def paper_search(): if request.method == 'POST': DBsession = sessionmaker(bind=db.engine) data = request.get_data() json_data = json.loads(data.decode('utf-8')) catlog = json_data.get('catlog') keyword = json_data.get('keyword') dbsession = DBsession() retList = [] if catlog == 'note': full = dbsession.query(notes, user._account).join( user, user._id == notes._uid).filter(FullTextSearch(keyword, notes)) for note in full: notep = note[0] if notep._parentid != None: continue id = notep._id uid = notep._uid content = notep.notesContent _numOfnotes = notep._numOfnotes pid = notep._pid account = note[1] thumup = 0 retList.append({ 'id': id, 'uid': uid, 'note': content, 'account': account, 'thumup': thumup, 'numOfReply': _numOfnotes, 'pid': pid }) ret_dict = {'state': 'success', "notes_json": retList} notes_json = json.dumps(ret_dict) print(notes_json) return notes_json if catlog == 'paper': full = dbsession.query(paper).filter(FullTextSearch( keyword, paper)) for part in full: retList.append({ "id": part._id, "title": part._title, "abstract": part._abstract, "content": part._abstract, "author": part._author, "catlog": part._catlog, "numOfnotes": part._numOfnotes }) ret_dict = {'state': 'success', "paper_json": retList} paper_json = json.dumps(ret_dict) print(paper_json) dbsession.close() return paper_json dbsession.close() return "failed"
def mysql_fulltext_query(mysql, count, search_terms, topics, unwanted_topics, user_topics, unwanted_user_topics, language, upper_bounds, lower_bounds): class FulltextContext(FullText): __fulltext_columns__ = ('article.content', 'article.title') query = mysql.query(Article) # if no user topics wanted or un_wanted we can do NATURAL LANGUAGE mode # otherwise do BOOLEAN MODE if not unwanted_user_topics and not user_topics: boolean_query = False if search_terms: search = search_terms query = mysql.query(Article).filter(FullTextSearch(search, FulltextContext, FullTextMode.NATURAL)) else: # build a boolean query instead boolean_query = True unwanted_user_topics = add_symbol_in_front_of_words('-', unwanted_user_topics) user_topics = add_symbol_in_front_of_words('', user_topics) search_terms = add_symbol_in_front_of_words('', search_terms) search = search_terms + " " + user_topics.strip() + " " + unwanted_user_topics.strip() query = mysql.query(Article).filter(FullTextSearch(search, FulltextContext, FullTextMode.BOOLEAN)) # Language query = query.filter(Article.language_id == language.id) # Topics topic_IDs = split_numbers_in_string(topics) topic_conditions = [] if topic_IDs: for ID in topic_IDs: topic_conditions.append(Article.Topic.id == ID) query = query.filter(or_(*topic_conditions)) # Unwanted topics unwanted_topic_IDs = split_numbers_in_string(unwanted_topics) untopic_conditions = [] if unwanted_topic_IDs: for ID in unwanted_topic_IDs: untopic_conditions.append(Article.Topic.id != ID) query = query.filter(or_(*untopic_conditions)) # difficulty, upper and lower query = query.filter(lower_bounds < Article.fk_difficulty) query = query.filter(upper_bounds > Article.fk_difficulty) # if boolean search mode in fulltext then order by relevance score if boolean_query: query = query.order_by(desc(FullTextSearch(search, FulltextContext, FullTextMode.BOOLEAN))) return query.limit(count)
def search_related_entity_for_api(self, query, result_limit=10): try: print( "search for", query, ) print("type chunk ", type(query)) query = unicode(query) print( "search for", query, ) print("type chunk ", type(query)) max_limit = result_limit + 50 # max_limit = result_limit statement = self.get_session().query(EntityForQA).filter( EntityForQA.source == "api", FullTextSearch(query, EntityForQA, FullTextMode.NATURAL)) if result_limit == 0: entity_for_qa_list = statement.all() else: entity_for_qa_list = statement.limit(max_limit).all() return entity_for_qa_list except Exception, e: print(e) self.clean_session() if self.logger: self.logger.exception("exception occur in query=%s", query) return []
def test_fulltext_query(self): full = self.session.query(RecipeReviewModel).filter( FullTextSearch('spam', RecipeReviewModel)) self.assertEqual( full.count(), 2, ) full = self.session.query(RecipeReviewModelForMigration).filter( FullTextSearch('spam', RecipeReviewModelForMigration)) self.assertEqual( full.count(), 2, ) raw = self.session.execute( 'SELECT * FROM {0} WHERE MATCH (commentor, review) AGAINST ("spam")' .format(RecipeReviewModel.__tablename__)) self.assertEqual(full.count(), raw.rowcount, 'Query Test Failed')
def search(self, text, limit): """ Fulltext Search models. :param text: :param limit: :return: """ return self.__model__.query.filter(FullTextSearch(text, self.__model__))
def test_fulltext_query_boolean_mode(self): full = self.session.query(RecipeReviewModel).filter( FullTextSearch('spa*', RecipeReviewModel, FullTextMode.BOOLEAN)) self.assertEqual( full.count(), 3, ) full = self.session.query(RecipeReviewModelForMigration).filter( FullTextSearch('spa*', RecipeReviewModelForMigration, FullTextMode.BOOLEAN)) self.assertEqual( full.count(), 3, ) raw = self.session.execute( 'SELECT * FROM {0} WHERE MATCH (commentor, review) AGAINST ("spa*" IN BOOLEAN MODE)' .format(RecipeReviewModel.__tablename__)) self.assertEqual(full.count(), raw.rowcount, 'Query Test Failed')
def test_fulltext_qutoe_query(self): full = self.session.query(RecipeReviewModel).filter( FullTextSearch('"parrot can"', RecipeReviewModel, FullTextMode.BOOLEAN)) self.assertEqual( full.count(), 2, ) full = self.session.query(RecipeReviewModelForMigration).filter( FullTextSearch('"parrot can"', RecipeReviewModelForMigration, FullTextMode.BOOLEAN)) self.assertEqual( full.count(), 2, ) raw = self.session.execute( """SELECT * FROM {0} WHERE MATCH (commentor, review) AGAINST ('"parrot can"' IN BOOLEAN MODE)""" .format(RecipeReviewModel.__tablename__)) self.assertEqual(full.count(), raw.rowcount)
def test_fulltext_query_natural_mode(self): full = self.session.query(RecipeReviewModel).filter( FullTextSearch('spam', RecipeReviewModel, FullTextMode.NATURAL)) self.assertEqual( full.count(), 3, ) raw = self.session.execute( 'SELECT * FROM {0} WHERE MATCH (commentor, review) AGAINST ("spam" IN NATURAL LANGUAGE MODE)' .format(RecipeReviewModel.__tablename__)) self.assertEqual(full.count(), raw.rowcount, 'Query Test Failed')
def lookup_text(db): q = request.query.q if not q: abort(400, 'q is a required parameter') entity = db.query(Expression).filter(FullTextSearch( q, Expression)).limit(1000).all() d = [] for row in entity: d.append({'href': "%s/works/%s" % (app.config['api.base'], row.id)}) response.content_type = 'application/json' return dumps(d)
def test_fulltext_query_query_expansion_mode(self): full = self.session.query(RecipeReviewModel).filter( FullTextSearch('spam', RecipeReviewModel, FullTextMode.QUERY_EXPANSION)) self.assertEqual( full.count(), 3, ) raw = self.session.execute( 'SELECT * FROM {0} WHERE MATCH (commentor, review) AGAINST ("spam" WITH QUERY EXPANSION)' .format(RecipeReviewModel.__tablename__)) self.assertEqual(full.count(), raw.rowcount, 'Query Test Failed')
def get_quote_suggestions(self, query, n=10): session = Session() query_ft = query # replace problematic characters for fulltext search for char in '()+-*~@<>"': query_ft = query.replace(char, ' ') quotes = (session.query(Quote).filter( FullTextSearch( query_ft + '*', Quote, FullTextMode.BOOLEAN)).filter( Quote.quote.like('%' + query.strip() + '%')).order_by( func.length(Quote.quote)).limit(n).all()) Session.remove() return quotes
def get_person_suggestions(self, query, n=10): session = Session() query_ft = query # replace problematic characters for fulltext search for char in '()+-*~@<>"': query_ft = query_ft.replace(char, ' ') people = (session.query(Person).filter( FullTextSearch( query_ft + '*', Person, FullTextMode.BOOLEAN)).filter( Person.name.like('%' + query.strip() + '%')).order_by( func.length(Person.name)).limit(n).all()) Session.remove() return people
def test_github_issue_9(self): # https://github.com/mengzhuo/sqlalchemy-fulltext-search/issues/9 full = self.session.query(RecipeReviewModel).filter( RecipeReviewModel.id >= 1) full = full.filter( FullTextSearch('the -rainbow', RecipeReviewModel, FullTextMode.BOOLEAN)).limit(20) self.assertEqual(full.count(), 0) raw = self.session.execute( 'SELECT * FROM {0} WHERE MATCH (commentor, review) AGAINST ("the -rainbow" IN BOOLEAN MODE)' .format(RecipeReviewModel.__tablename__)) self.assertEqual(full.count(), raw.rowcount, 'Query Test Failed') full = self.session.query(RecipeReviewModelForMigration).filter( RecipeReviewModelForMigration.id >= 1) full = full.filter( FullTextSearch('the -rainbow', RecipeReviewModelForMigration, FullTextMode.BOOLEAN)).limit(20) self.assertEqual(full.count(), 0) raw = self.session.execute( 'SELECT * FROM {0} WHERE MATCH (commentor, review) AGAINST ("the -rainbow" IN BOOLEAN MODE)' .format(RecipeReviewModelForMigration.__tablename__)) self.assertEqual(full.count(), raw.rowcount, 'Query Test Failed')
def search(self, query, result_limit=0): try: statement = self.get_session().query(WikipediaEntityName).filter( FullTextSearch(query, WikipediaEntityName, FullTextMode.NATURAL)) if result_limit == 0: result = statement.limit(300).all() else: result = statement.limit(result_limit).all() return result except Exception, e: print(e) self.clean_session() if self.logger: self.logger.exception("exception occur in query=%s", query) return []
def full_text_search_in_nature_language( self, query, model_class, limit=ALL_RESULT, result_format=RESULT_FORMAT_ALL_INFO): if result_format == DBSearcher.RESULT_FORMAT_ALL_INFO: session_query = self.get_session().query(model_class) else: session_query = self.get_session().query(model_class.id) session_query = session_query.filter( FullTextSearch(query, model_class, FullTextMode.NATURAL)) if limit == DBSearcher.ALL_RESULT: limit = DBSearcher.MAX_RESULT_NUM return session_query.limit(limit).all()
def scholarly_search_name(): """ Run this to autocomplete. Params are author_name and refresh """ a_name = request.args.get('author') refresh = request.args.get('refresh') tsess = Session() author = tsess.query(TempAuthor).filter(FullTextSearch(a_name, TempAuthor)).all() print([a.name, a.scholar_id] for a in list(author)) if not refresh and author: return jsonify({ 'from': 'db', 'results': [{ 'name': a.name, 'affiliation': a.organization, 'scholar_id': a.scholar_id, } for a in list(author)] }) # [vars(a) for a in list(author)]}) author = a_name if author: authors = [] search_query = scholarly.search_author(author) try: authors = list(search_query) authors = [{ "name": auth.name, "affiliation": auth.affiliation, "scholar_id": auth.id } for auth in authors] # Start running the analysis for the authors subprocess.Popen(["python3", "fetch_profile.py", "author"] + author.split(" ")) except StopIteration as e: return jsonify(**{'error': 'Scholarly did not find author'}) return jsonify(**{"results": authors}) else: return jsonify(**{"results": []})
def search_sentence_answer(self, query, result_limit=10): try: max_limit = result_limit + 50 statement = self.get_session().query( DocumentSentenceText.doc_id, DocumentSentenceText.text).filter( FullTextSearch(query, DocumentSentenceText, FullTextMode.NATURAL)) print(statement) if result_limit == 0: sentence_list = statement.all() else: sentence_list = statement.limit(max_limit).all() return sentence_list[:result_limit] except Exception, e: print(e) self.clean_session() if self.logger: self.logger.exception("exception occur in query=%s", query) return []
def search_post(self, query, result_limit=10): try: max_limit = result_limit + 50 statement = self.get_session().query(PostsRecord).filter( FullTextSearch(query, PostsRecord, FullTextMode.NATURAL)) if result_limit == 0: post_list = statement.all() else: post_list = statement.limit(max_limit).all() post_list.sort(key=lambda x: x.score, reverse=True) return post_list[:result_limit] except Exception: self.clean_session() if self.logger: self.logger.exception("exception occur in query=%s", query) return []
def filter_query(self, query, overview=False): query = query.filter( Document.analysis_nature_id == self.nature_id, Document.country == self.country, ) if not overview and self.medium: query = query.filter(Document.medium == self.medium) query = query.filter(Document.published_at >= self.published_from, Document.published_at <= self.published_to) if self.source_person_id.data: query = query\ .join(DocumentSource)\ .filter(DocumentSource.person_id == self.source_person_id.data) if self.q.data: # full text search query = query.filter( FullTextSearch(self.q.data, Document, FullTextMode.NATURAL)) return query
def search(query, orderby='creation', filter_user=None, search_title=True, search_text=True, subreddit=None): """ search for threads (and maybe comments in the future) """ if not query: return [] query = query.strip() base_qs = Thread.query.join(Publication).filter( FullTextSearch(query, Publication, FullTextMode.NATURAL)) if orderby == 'creation': base_qs = base_qs.order_by(db.desc(Thread.created_on)) elif orderby == 'title': base_qs = base_qs.order_by(Thread.title) elif orderby == 'numb_comments': pass return base_qs
def test_fulltext_cjk_query(self): cjk = self.session.query(RecipeReviewModel).filter( FullTextSearch('中国人'.decode('utf8'), RecipeReviewModel)) self.assertEqual(cjk.count(), 2)
def filter_query(self, query): query = query.filter( Document.analysis_nature_id == self.analysis_nature_id.data) if self.cluster_id.data: query = query.join(ClusteredDocument)\ .filter(ClusteredDocument.cluster_id == self.cluster_id.data) if self.medium_id.data: query = query.filter(Document.medium_id.in_(self.medium_id.data)) if self.user_id.data: if self.user_id.data == '-': query = query.filter( or_( Document.created_by_user_id == None, # noqa Document.checked_by_user_id == None)) else: query = query.filter( or_(Document.created_by_user_id == self.user_id.data, Document.checked_by_user_id == self.user_id.data)) if self.country_id.data: query = query.filter(Document.country_id.in_(self.country_id.data)) if self.created_from: query = query.filter(Document.created_at >= self.created_from) if self.created_to: query = query.filter(Document.created_at <= self.created_to) if self.published_from: query = query.filter(Document.published_at >= self.published_from) if self.published_to: query = query.filter(Document.published_at <= self.published_to) if self.source_person_id.data: query = query\ .join(DocumentSource)\ .filter(DocumentSource.person_id == self.source_person_id.data) if self.problems.data: for code in self.problems.data: query = DocumentAnalysisProblem.lookup(code).filter_query( query) if self.flagged.data: query = query.filter(Document.flagged == True) # noqa if self.has_url.data == '1': query = query.filter(Document.url != None, Document.url != '') # noqa elif self.has_url.data == '0': query = query.filter(or_(Document.url == None, Document.url == '')) # noqa if self.q.data: # full text search query = query.filter( FullTextSearch(self.q.data, Document, FullTextMode.NATURAL)) if self.tags.data: tags = set(f for f in re.split('\s*,\s*', self.tags.data) if f) for tag in tags: query = query.filter(Document.tags.contains(tag)) return query
def test_fulltext_form_query(self): FullTextSearch('spam', RecipeReviewModel) FullTextSearch('spam', RecipeReviewModelForMigration)
def search_db(term='', user=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: flask.abort(404) sort_keys = { 'id': models.Torrent.id, 'size': models.Torrent.filesize, # Disable this because we disabled this in search_elastic, for the sake of consistency: # 'name': models.Torrent.display_name, 'comments': models.Torrent.comment_count, 'seeders': models.Statistic.seed_count, 'leechers': models.Statistic.leech_count, 'downloads': models.Statistic.download_count } sort_column = sort_keys.get(sort.lower()) if sort_column is None: flask.abort(400) order_keys = {'desc': 'desc', 'asc': 'asc'} order_ = order.lower() if order_ not in order_keys: flask.abort(400) filter_keys = { '0': None, '1': (models.TorrentFlags.REMAKE, False), '2': (models.TorrentFlags.TRUSTED, True), '3': (models.TorrentFlags.COMPLETE, True) } sentinel = object() filter_tuple = filter_keys.get(quality_filter.lower(), sentinel) 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 sub_cat_id = 0 if category: cat_match = re.match(r'^(\d+)_(\d+)$', category) if not cat_match: flask.abort(400) main_cat_id = int(cat_match.group(1)) sub_cat_id = int(cat_match.group(2)) if main_cat_id > 0: if sub_cat_id > 0: sub_category = models.SubCategory.by_category_ids( main_cat_id, sub_cat_id) else: main_category = models.MainCategory.by_id(main_cat_id) if not category: flask.abort(400) # Force sort by id desc if rss if rss: sort_column = sort_keys['id'] order = 'desc' same_user = False if logged_in_user: same_user = logged_in_user.id == user model_class = models.TorrentNameSearch if term else models.Torrent query = db.session.query(model_class) # This is... eh. Optimize the COUNT() query since MySQL is bad at that. # See http://docs.sqlalchemy.org/en/rel_1_1/orm/query.html#sqlalchemy.orm.query.Query.count # Wrap the queries into the helper class to deduplicate code and apply filters to both in one go count_query = db.session.query(sqlalchemy.func.count(model_class.id)) qpc = QueryPairCaller(query, count_query) # User view (/user/username) if user: qpc.filter(models.Torrent.uploader_id == user) if not admin: # Hide all DELETED torrents if regular user qpc.filter( models.Torrent.flags.op('&')(int( models.TorrentFlags.DELETED)).is_(False)) # If logged in user is not the same as the user being viewed, # show only torrents that aren't hidden or anonymous # # If logged in user is the same as the user being viewed, # show all torrents including hidden and anonymous ones # # On RSS pages in user view, # show only torrents that aren't hidden or anonymous no matter what if not same_user or rss: qpc.filter( models.Torrent.flags.op('&')( int(models.TorrentFlags.HIDDEN | models.TorrentFlags.ANONYMOUS)).is_(False)) # General view (homepage, general search view) else: if not admin: # Hide all DELETED torrents if regular user qpc.filter( models.Torrent.flags.op('&')(int( models.TorrentFlags.DELETED)).is_(False)) # If logged in, show all torrents that aren't hidden unless they belong to you # On RSS pages, show all public torrents and nothing more. if logged_in_user and not rss: qpc.filter((models.Torrent.flags.op('&') (int(models.TorrentFlags.HIDDEN)).is_(False)) | (models.Torrent.uploader_id == logged_in_user.id)) # Otherwise, show all torrents that aren't hidden else: qpc.filter( models.Torrent.flags.op('&')(int( models.TorrentFlags.HIDDEN)).is_(False)) if main_category: qpc.filter(models.Torrent.main_category_id == main_cat_id) elif sub_category: qpc.filter((models.Torrent.main_category_id == main_cat_id) & (models.Torrent.sub_category_id == sub_cat_id)) if filter_tuple: qpc.filter( models.Torrent.flags.op('&')(int(filter_tuple[0])).is_( filter_tuple[1])) if term: for item in shlex.split(term, posix=False): if len(item) >= 2: qpc.filter( FullTextSearch(item, models.TorrentNameSearch, FullTextMode.NATURAL)) query, count_query = qpc.items # Sort and order if sort_column.class_ != models.Torrent: index_name = _get_index_name(sort_column) query = query.join(sort_column.class_) query = query.with_hint(sort_column.class_, 'USE INDEX ({0})'.format(index_name)) query = query.order_by(getattr(sort_column, order)()) if rss: query = query.limit(per_page) else: query = query.paginate_faste(page, per_page=per_page, step=5, count_query=count_query) return query
def test_fulltext_cjk_query(self): _ = self.session.query(RecipeReviewModel).filter( FullTextSearch('中国人'.decode('utf8'), RecipeReviewModel)) _ = self.session.query(RecipeReviewModelForMigration).filter( FullTextSearch('中国人'.decode('utf8'), RecipeReviewModelForMigration))
def searched_paginate(self, page, per_page, text): paginated = self.__model__.query.filter(FullTextSearch(text, self.__model__, FulltextMode.BOOLEAN)).paginate(page, per_page, False) return paginated.items, paginated.has_prev, paginated.has_next
def _build_fulltext_search(self, model_cls, query, q, mode=FullTextMode.BOOLEAN): return query.filter(FullTextSearch(q, model_cls, mode=mode))
def search_db(term='', user=None, sort='id', order='desc', category='0_0', quality_filter='0', page=1, rss=False, admin=False, logged_in_user=None, per_page=75): sort_keys = { 'id': models.Torrent.id, 'size': models.Torrent.filesize, # 'name': models.Torrent.display_name, # Disable this because we disabled this in search_elastic, for the sake of consistency 'seeders': models.Statistic.seed_count, 'leechers': models.Statistic.leech_count, 'downloads': models.Statistic.download_count } sort_ = sort.lower() if sort_ not in sort_keys: flask.abort(400) sort = sort_keys[sort] order_keys = {'desc': 'desc', 'asc': 'asc'} order_ = order.lower() if order_ not in order_keys: flask.abort(400) filter_keys = { '0': None, '1': (models.TorrentFlags.REMAKE, False), '2': (models.TorrentFlags.TRUSTED, True), '3': (models.TorrentFlags.COMPLETE, True) } sentinel = object() filter_tuple = filter_keys.get(quality_filter.lower(), sentinel) 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 sub_cat_id = 0 if category: cat_match = re.match(r'^(\d+)_(\d+)$', category) if not cat_match: flask.abort(400) main_cat_id = int(cat_match.group(1)) sub_cat_id = int(cat_match.group(2)) if main_cat_id > 0: if sub_cat_id > 0: sub_category = models.SubCategory.by_category_ids( main_cat_id, sub_cat_id) else: main_category = models.MainCategory.by_id(main_cat_id) if not category: flask.abort(400) # Force sort by id desc if rss if rss: sort = sort_keys['id'] order = 'desc' same_user = False if logged_in_user: same_user = logged_in_user.id == user if term: query = db.session.query(models.TorrentNameSearch) else: query = models.Torrent.query # User view (/user/username) if user: query = query.filter(models.Torrent.uploader_id == user) if not admin: # Hide all DELETED torrents if regular user query = query.filter( models.Torrent.flags.op('&')(int( models.TorrentFlags.DELETED)).is_(False)) # If logged in user is not the same as the user being viewed, show only torrents that aren't hidden or anonymous # If logged in user is the same as the user being viewed, show all torrents including hidden and anonymous ones # On RSS pages in user view, show only torrents that aren't hidden or anonymous no matter what if not same_user or rss: query = query.filter( models.Torrent.flags.op('&')( int(models.TorrentFlags.HIDDEN | models.TorrentFlags.ANONYMOUS)).is_(False)) # General view (homepage, general search view) else: if not admin: # Hide all DELETED torrents if regular user query = query.filter( models.Torrent.flags.op('&')(int( models.TorrentFlags.DELETED)).is_(False)) # If logged in, show all torrents that aren't hidden unless they belong to you # On RSS pages, show all public torrents and nothing more. if logged_in_user and not rss: query = query.filter( (models.Torrent.flags.op('&') (int(models.TorrentFlags.HIDDEN)).is_(False)) | (models.Torrent.uploader_id == logged_in_user.id)) # Otherwise, show all torrents that aren't hidden else: query = query.filter( models.Torrent.flags.op('&')(int( models.TorrentFlags.HIDDEN)).is_(False)) if main_category: query = query.filter(models.Torrent.main_category_id == main_cat_id) elif sub_category: query = query.filter((models.Torrent.main_category_id == main_cat_id) & (models.Torrent.sub_category_id == sub_cat_id)) if filter_tuple: query = query.filter( models.Torrent.flags.op('&')(int(filter_tuple[0])).is_( filter_tuple[1])) if term: for item in shlex.split(term, posix=False): if len(item) >= 2: query = query.filter( FullTextSearch(item, models.TorrentNameSearch, FullTextMode.NATURAL)) # Sort and order if sort.class_ != models.Torrent: query = query.join(sort.class_) query = query.order_by(getattr(sort, order)()) if rss: query = query.limit(per_page) else: query = query.paginate_faste(page, per_page=per_page, step=5) return query
def search(term='', user=None, sort='id', order='desc', category='0_0', quality_filter='0', page=1, rss=False, admin=False): sort_keys = { 'id': models.Torrent.id, 'size': models.Torrent.filesize, 'name': models.Torrent.display_name, 'seeders': models.Statistic.seed_count, 'leechers': models.Statistic.leech_count, 'downloads': models.Statistic.download_count } sort_ = sort.lower() if sort_ not in sort_keys: flask.abort(400) sort = sort_keys[sort] order_keys = {'desc': 'desc', 'asc': 'asc'} order_ = order.lower() if order_ not in order_keys: flask.abort(400) filter_keys = { '0': None, '1': (models.TorrentFlags.REMAKE, False), '2': (models.TorrentFlags.TRUSTED, True), '3': (models.TorrentFlags.COMPLETE, True) } sentinel = object() filter_tuple = filter_keys.get(quality_filter.lower(), sentinel) 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 sub_cat_id = 0 if category: cat_match = re.match(r'^(\d+)_(\d+)$', category) if not cat_match: flask.abort(400) main_cat_id = int(cat_match.group(1)) sub_cat_id = int(cat_match.group(2)) if main_cat_id > 0: if sub_cat_id > 0: sub_category = models.SubCategory.by_category_ids( main_cat_id, sub_cat_id) else: main_category = models.MainCategory.by_id(main_cat_id) if not category: flask.abort(400) # Force sort by id desc if rss if rss: sort = sort_keys['id'] order = 'desc' page = 1 same_user = False if flask.g.user: same_user = flask.g.user.id == user if term: query = db.session.query(models.TorrentNameSearch) else: query = models.Torrent.query # Filter by user if user: query = query.filter(models.Torrent.uploader_id == user) # If admin, show everything if not admin: # If user is not logged in or the accessed feed doesn't belong to user, # hide anonymous torrents belonging to the queried user if not same_user: query = query.filter( models.Torrent.flags.op('&')( int(models.TorrentFlags.ANONYMOUS | models.TorrentFlags.DELETED)).is_(False)) if main_category: query = query.filter(models.Torrent.main_category_id == main_cat_id) elif sub_category: query = query.filter((models.Torrent.main_category_id == main_cat_id) & (models.Torrent.sub_category_id == sub_cat_id)) if filter_tuple: query = query.filter( models.Torrent.flags.op('&')(int(filter_tuple[0])).is_( filter_tuple[1])) # If admin, show everything if not admin: query = query.filter( models.Torrent.flags.op('&')( int(models.TorrentFlags.HIDDEN | models.TorrentFlags.DELETED)).is_(False)) if term: for item in shlex.split(term, posix=False): if len(item) >= 2: query = query.filter( FullTextSearch(item, models.TorrentNameSearch, FullTextMode.NATURAL)) # Sort and order if sort.class_ != models.Torrent: query = query.join(sort.class_) query = query.order_by(getattr(sort, order)()) if rss: query = query.limit(app.config['RESULTS_PER_PAGE']) else: query = query.paginate_faste(page, per_page=app.config['RESULTS_PER_PAGE'], step=5) return query