server/general: cosmetic fixes

This commit is contained in:
rr- 2016-06-05 10:39:56 +02:00
parent 508cb6e7ab
commit f3bb6c28a1
12 changed files with 202 additions and 201 deletions

View File

@ -2,8 +2,8 @@ import falcon
from szurubooru import errors from szurubooru import errors
from szurubooru.func import net from szurubooru.func import net
def _lower_first(input): def _lower_first(source):
return input[0].lower() + input[1:] return source[0].lower() + source[1:]
def _param_wrapper(func): def _param_wrapper(func):
def wrapper(self, name, required=False, default=None, **kwargs): def wrapper(self, name, required=False, default=None, **kwargs):
@ -11,10 +11,10 @@ def _param_wrapper(func):
value = self.input[name] value = self.input[name]
try: try:
value = func(self, value, **kwargs) value = func(self, value, **kwargs)
except errors.InvalidParameterError as e: except errors.InvalidParameterError as ex:
raise errors.InvalidParameterError( raise errors.InvalidParameterError(
'Parameter %r is invalid: %s' % ( 'Parameter %r is invalid: %s' % (
name, _lower_first(str(e)))) name, _lower_first(str(ex))))
return value return value
if not required: if not required:
return default return default

View File

@ -1,10 +1,4 @@
import sqlalchemy from szurubooru.search import tokens
from szurubooru import db, errors
from szurubooru.func import util
from szurubooru.search import criteria, tokens
def wildcard_transformer(value):
return value.replace('*', '%')
class BaseSearchConfig(object): class BaseSearchConfig(object):
SORT_ASC = tokens.SortToken.SORT_ASC SORT_ASC = tokens.SortToken.SORT_ASC
@ -34,127 +28,3 @@ class BaseSearchConfig(object):
@property @property
def sort_columns(self): def sort_columns(self):
return {} return {}
@staticmethod
def _apply_num_criterion_to_column(column, criterion):
'''
Decorate SQLAlchemy filter on given column using supplied criterion.
'''
try:
if isinstance(criterion, criteria.PlainCriterion):
expr = column == int(criterion.value)
elif isinstance(criterion, criteria.ArrayCriterion):
expr = column.in_(int(value) for value in criterion.values)
elif isinstance(criterion, criteria.RangedCriterion):
assert criterion.min_value != '' \
or criterion.max_value != ''
if criterion.min_value != '' and criterion.max_value != '':
expr = column.between(
int(criterion.min_value), int(criterion.max_value))
elif criterion.min_value != '':
expr = column >= int(criterion.min_value)
elif criterion.max_value != '':
expr = column <= int(criterion.max_value)
else:
assert False
except ValueError:
raise errors.SearchError(
'Criterion value %r must be a number.' % (criterion,))
return expr
@staticmethod
def _create_num_filter(column):
def wrapper(query, criterion, negated):
expr = BaseSearchConfig._apply_num_criterion_to_column(
column, criterion)
if negated:
expr = ~expr
return query.filter(expr)
return wrapper
@staticmethod
def _apply_str_criterion_to_column(
column, criterion, transformer=wildcard_transformer):
'''
Decorate SQLAlchemy filter on given column using supplied criterion.
'''
if isinstance(criterion, criteria.PlainCriterion):
expr = column.ilike(transformer(criterion.value))
elif isinstance(criterion, criteria.ArrayCriterion):
expr = sqlalchemy.sql.false()
for value in criterion.values:
expr = expr | column.ilike(transformer(value))
elif isinstance(criterion, criteria.RangedCriterion):
raise errors.SearchError(
'Composite token %r is invalid in this context.' % (criterion,))
else:
assert False
return expr
@staticmethod
def _create_str_filter(column, transformer=wildcard_transformer):
def wrapper(query, criterion, negated):
expr = BaseSearchConfig._apply_str_criterion_to_column(
column, criterion, transformer)
if negated:
expr = ~expr
return query.filter(expr)
return wrapper
@staticmethod
def _apply_date_criterion_to_column(column, criterion):
'''
Decorate SQLAlchemy filter on given column using supplied criterion.
Parse the datetime inside the criterion.
'''
if isinstance(criterion, criteria.PlainCriterion):
min_date, max_date = util.parse_time_range(criterion.value)
expr = column.between(min_date, max_date)
elif isinstance(criterion, criteria.ArrayCriterion):
expr = sqlalchemy.sql.false()
for value in criterion.values:
min_date, max_date = util.parse_time_range(value)
expr = expr | column.between(min_date, max_date)
elif isinstance(criterion, criteria.RangedCriterion):
assert criterion.min_value or criterion.max_value
if criterion.min_value and criterion.max_value:
min_date = util.parse_time_range(criterion.min_value)[0]
max_date = util.parse_time_range(criterion.max_value)[1]
expr = column.between(min_date, max_date)
elif criterion.min_value:
min_date = util.parse_time_range(criterion.min_value)[0]
expr = column >= min_date
elif criterion.max_value:
max_date = util.parse_time_range(criterion.max_value)[1]
expr = column <= max_date
else:
assert False
return expr
@staticmethod
def _create_date_filter(column):
def wrapper(query, criterion, negated):
expr = BaseSearchConfig._apply_date_criterion_to_column(
column, criterion)
if negated:
expr = ~expr
return query.filter(expr)
return wrapper
@staticmethod
def _create_subquery_filter(
left_id_column,
right_id_column,
filter_column,
filter_factory,
subquery_decorator=None):
filter_func = filter_factory(filter_column)
def wrapper(query, criterion, negated):
subquery = db.session.query(right_id_column.label('foreign_id'))
if subquery_decorator:
subquery = subquery_decorator(subquery)
subquery = subquery.options(sqlalchemy.orm.lazyload('*'))
subquery = filter_func(subquery, criterion, negated)
subquery = subquery.subquery('t')
return query.filter(left_id_column.in_(subquery))
return wrapper

View File

@ -1,5 +1,6 @@
from sqlalchemy.sql.expression import func from sqlalchemy.sql.expression import func
from szurubooru import db from szurubooru import db
from szurubooru.search.configs import util as search_util
from szurubooru.search.configs.base_search_config import BaseSearchConfig from szurubooru.search.configs.base_search_config import BaseSearchConfig
class CommentSearchConfig(BaseSearchConfig): class CommentSearchConfig(BaseSearchConfig):
@ -11,22 +12,22 @@ class CommentSearchConfig(BaseSearchConfig):
@property @property
def anonymous_filter(self): def anonymous_filter(self):
return self._create_str_filter(db.Comment.text) return search_util.create_str_filter(db.Comment.text)
@property @property
def named_filters(self): def named_filters(self):
return { return {
'id': self._create_num_filter(db.Comment.comment_id), 'id': search_util.create_num_filter(db.Comment.comment_id),
'post': self._create_num_filter(db.Comment.post_id), 'post': search_util.create_num_filter(db.Comment.post_id),
'user': self._create_str_filter(db.User.name), 'user': search_util.create_str_filter(db.User.name),
'author': self._create_str_filter(db.User.name), 'author': search_util.create_str_filter(db.User.name),
'text': self._create_str_filter(db.Comment.text), 'text': search_util.create_str_filter(db.Comment.text),
'creation-date': self._create_date_filter(db.Comment.creation_time), 'creation-date': search_util.create_date_filter(db.Comment.creation_time),
'creation-time': self._create_date_filter(db.Comment.creation_time), 'creation-time': search_util.create_date_filter(db.Comment.creation_time),
'last-edit-date': self._create_date_filter(db.Comment.last_edit_time), 'last-edit-date': search_util.create_date_filter(db.Comment.last_edit_time),
'last-edit-time': self._create_date_filter(db.Comment.last_edit_time), 'last-edit-time': search_util.create_date_filter(db.Comment.last_edit_time),
'edit-date': self._create_date_filter(db.Comment.last_edit_time), 'edit-date': search_util.create_date_filter(db.Comment.last_edit_time),
'edit-time': self._create_date_filter(db.Comment.last_edit_time), 'edit-time': search_util.create_date_filter(db.Comment.last_edit_time),
} }
@property @property

View File

@ -3,6 +3,7 @@ from sqlalchemy.sql.expression import func
from szurubooru import db, errors from szurubooru import db, errors
from szurubooru.func import util from szurubooru.func import util
from szurubooru.search import criteria, tokens from szurubooru.search import criteria, tokens
from szurubooru.search.configs import util as search_util
from szurubooru.search.configs.base_search_config import BaseSearchConfig from szurubooru.search.configs.base_search_config import BaseSearchConfig
def _enum_transformer(available_values, value): def _enum_transformer(available_values, value):
@ -45,7 +46,7 @@ def _create_score_filter(score):
user_alias = aliased(db.User) user_alias = aliased(db.User)
score_alias = aliased(db.PostScore) score_alias = aliased(db.PostScore)
expr = score_alias.score == score expr = score_alias.score == score
expr = expr & BaseSearchConfig._apply_str_criterion_to_column( expr = expr & search_util.apply_str_criterion_to_column(
user_alias.name, criterion) user_alias.name, criterion)
if negated: if negated:
expr = ~expr expr = ~expr
@ -106,69 +107,69 @@ class PostSearchConfig(BaseSearchConfig):
@property @property
def anonymous_filter(self): def anonymous_filter(self):
return self._create_subquery_filter( return search_util.create_subquery_filter(
db.Post.post_id, db.Post.post_id,
db.PostTag.post_id, db.PostTag.post_id,
db.TagName.name, db.TagName.name,
self._create_str_filter, search_util.create_str_filter,
lambda subquery: subquery.join(db.Tag).join(db.TagName)) lambda subquery: subquery.join(db.Tag).join(db.TagName))
@property @property
def named_filters(self): def named_filters(self):
return util.unalias_dict({ return util.unalias_dict({
'id': self._create_num_filter(db.Post.post_id), 'id': search_util.create_num_filter(db.Post.post_id),
'tag': self._create_subquery_filter( 'tag': search_util.create_subquery_filter(
db.Post.post_id, db.Post.post_id,
db.PostTag.post_id, db.PostTag.post_id,
db.TagName.name, db.TagName.name,
self._create_str_filter, search_util.create_str_filter,
lambda subquery: subquery.join(db.Tag).join(db.TagName)), lambda subquery: subquery.join(db.Tag).join(db.TagName)),
'score': self._create_num_filter(db.Post.score), 'score': search_util.create_num_filter(db.Post.score),
('uploader', 'upload', 'submit'): ('uploader', 'upload', 'submit'):
self._create_subquery_filter( search_util.create_subquery_filter(
db.Post.user_id, db.Post.user_id,
db.User.user_id, db.User.user_id,
db.User.name, db.User.name,
self._create_str_filter), search_util.create_str_filter),
'comment': self._create_subquery_filter( 'comment': search_util.create_subquery_filter(
db.Post.post_id, db.Post.post_id,
db.Comment.post_id, db.Comment.post_id,
db.User.name, db.User.name,
self._create_str_filter, search_util.create_str_filter,
lambda subquery: subquery.join(db.User)), lambda subquery: subquery.join(db.User)),
'fav': self._create_subquery_filter( 'fav': search_util.create_subquery_filter(
db.Post.post_id, db.Post.post_id,
db.PostFavorite.post_id, db.PostFavorite.post_id,
db.User.name, db.User.name,
self._create_str_filter, search_util.create_str_filter,
lambda subquery: subquery.join(db.User)), lambda subquery: subquery.join(db.User)),
'liked': _create_score_filter(1), 'liked': _create_score_filter(1),
'disliked': _create_score_filter(-1), 'disliked': _create_score_filter(-1),
'tag-count': self._create_num_filter(db.Post.tag_count), 'tag-count': search_util.create_num_filter(db.Post.tag_count),
'comment-count': self._create_num_filter(db.Post.comment_count), 'comment-count': search_util.create_num_filter(db.Post.comment_count),
'fav-count': self._create_num_filter(db.Post.favorite_count), 'fav-count': search_util.create_num_filter(db.Post.favorite_count),
'note-count': self._create_num_filter(db.Post.note_count), 'note-count': search_util.create_num_filter(db.Post.note_count),
'feature-count': self._create_num_filter(db.Post.feature_count), 'feature-count': search_util.create_num_filter(db.Post.feature_count),
'type': self._create_str_filter(db.Post.type, _type_transformer), 'type': search_util.create_str_filter(db.Post.type, _type_transformer),
'file-size': self._create_num_filter(db.Post.file_size), 'file-size': search_util.create_num_filter(db.Post.file_size),
('image-width', 'width'): ('image-width', 'width'):
self._create_num_filter(db.Post.canvas_width), search_util.create_num_filter(db.Post.canvas_width),
('image-height', 'height'): ('image-height', 'height'):
self._create_num_filter(db.Post.canvas_height), search_util.create_num_filter(db.Post.canvas_height),
('image-area', 'area'): ('image-area', 'area'):
self._create_num_filter(db.Post.canvas_area), search_util.create_num_filter(db.Post.canvas_area),
('creation-date', 'creation-time', 'date', 'time'): ('creation-date', 'creation-time', 'date', 'time'):
self._create_date_filter(db.Post.creation_time), search_util.create_date_filter(db.Post.creation_time),
('last-edit-date', 'last-edit-time', 'edit-date', 'edit-time'): ('last-edit-date', 'last-edit-time', 'edit-date', 'edit-time'):
self._create_date_filter(db.Post.last_edit_time), search_util.create_date_filter(db.Post.last_edit_time),
('comment-date', 'comment-time'): ('comment-date', 'comment-time'):
self._create_date_filter(db.Post.last_comment_edit_time), search_util.create_date_filter(db.Post.last_comment_edit_time),
('fav-date', 'fav-time'): ('fav-date', 'fav-time'):
self._create_date_filter(db.Post.last_favorite_time), search_util.create_date_filter(db.Post.last_favorite_time),
('feature-date', 'feature-time'): ('feature-date', 'feature-time'):
self._create_date_filter(db.Post.last_feature_time), search_util.create_date_filter(db.Post.last_feature_time),
('safety', 'rating'): ('safety', 'rating'):
self._create_str_filter(db.Post.safety, _safety_transformer), search_util.create_str_filter(db.Post.safety, _safety_transformer),
}) })
@property @property

View File

@ -1,4 +1,5 @@
from szurubooru import db from szurubooru import db
from szurubooru.search.configs import util as search_util
from szurubooru.search.configs.base_search_config import BaseSearchConfig from szurubooru.search.configs.base_search_config import BaseSearchConfig
class SnapshotSearchConfig(BaseSearchConfig): class SnapshotSearchConfig(BaseSearchConfig):
@ -11,10 +12,10 @@ class SnapshotSearchConfig(BaseSearchConfig):
@property @property
def named_filters(self): def named_filters(self):
return { return {
'type': self._create_str_filter(db.Snapshot.resource_type), 'type': search_util.create_str_filter(db.Snapshot.resource_type),
'id': self._create_str_filter(db.Snapshot.resource_repr), 'id': search_util.create_str_filter(db.Snapshot.resource_repr),
'date': self._create_date_filter(db.Snapshot.creation_time), 'date': search_util.create_date_filter(db.Snapshot.creation_time),
'time': self._create_date_filter(db.Snapshot.creation_time), 'time': search_util.create_date_filter(db.Snapshot.creation_time),
'operation': self._create_str_filter(db.Snapshot.operation), 'operation': search_util.create_str_filter(db.Snapshot.operation),
'user': self._create_str_filter(db.User.name), 'user': search_util.create_str_filter(db.User.name),
} }

View File

@ -2,6 +2,7 @@ from sqlalchemy.orm import subqueryload
from sqlalchemy.sql.expression import func from sqlalchemy.sql.expression import func
from szurubooru import db from szurubooru import db
from szurubooru.func import util from szurubooru.func import util
from szurubooru.search.configs import util as search_util
from szurubooru.search.configs.base_search_config import BaseSearchConfig from szurubooru.search.configs.base_search_config import BaseSearchConfig
class TagSearchConfig(BaseSearchConfig): class TagSearchConfig(BaseSearchConfig):
@ -23,33 +24,35 @@ class TagSearchConfig(BaseSearchConfig):
@property @property
def anonymous_filter(self): def anonymous_filter(self):
return self._create_subquery_filter( return search_util.create_subquery_filter(
db.Tag.tag_id, db.Tag.tag_id,
db.TagName.tag_id, db.TagName.tag_id,
db.TagName.name, db.TagName.name,
self._create_str_filter) search_util.create_str_filter)
@property @property
def named_filters(self): def named_filters(self):
return util.unalias_dict({ return util.unalias_dict({
'name': self._create_subquery_filter( 'name': search_util.create_subquery_filter(
db.Tag.tag_id, db.Tag.tag_id,
db.TagName.tag_id, db.TagName.tag_id,
db.TagName.name, db.TagName.name,
self._create_str_filter), search_util.create_str_filter),
'category': self._create_subquery_filter( 'category': search_util.create_subquery_filter(
db.Tag.category_id, db.Tag.category_id,
db.TagCategory.tag_category_id, db.TagCategory.tag_category_id,
db.TagCategory.name, db.TagCategory.name,
self._create_str_filter), search_util.create_str_filter),
('creation-date', 'creation-time'): ('creation-date', 'creation-time'):
self._create_date_filter(db.Tag.creation_time), search_util.create_date_filter(db.Tag.creation_time),
('last-edit-date', 'last-edit-time', 'edit-date', 'edit-time'): ('last-edit-date', 'last-edit-time', 'edit-date', 'edit-time'):
self._create_date_filter(db.Tag.last_edit_time), search_util.create_date_filter(db.Tag.last_edit_time),
('usage-count', 'post-count', 'usages'): ('usage-count', 'post-count', 'usages'):
self._create_num_filter(db.Tag.post_count), search_util.create_num_filter(db.Tag.post_count),
'suggestion-count': self._create_num_filter(db.Tag.suggestion_count), 'suggestion-count':
'implication-count': self._create_num_filter(db.Tag.implication_count), search_util.create_num_filter(db.Tag.suggestion_count),
'implication-count':
search_util.create_num_filter(db.Tag.implication_count),
}) })
@property @property

View File

@ -1,5 +1,6 @@
from sqlalchemy.sql.expression import func from sqlalchemy.sql.expression import func
from szurubooru import db from szurubooru import db
from szurubooru.search.configs import util as search_util
from szurubooru.search.configs.base_search_config import BaseSearchConfig from szurubooru.search.configs.base_search_config import BaseSearchConfig
class UserSearchConfig(BaseSearchConfig): class UserSearchConfig(BaseSearchConfig):
@ -13,18 +14,18 @@ class UserSearchConfig(BaseSearchConfig):
@property @property
def anonymous_filter(self): def anonymous_filter(self):
return self._create_str_filter(db.User.name) return search_util.create_str_filter(db.User.name)
@property @property
def named_filters(self): def named_filters(self):
return { return {
'name': self._create_str_filter(db.User.name), 'name': search_util.create_str_filter(db.User.name),
'creation-date': self._create_date_filter(db.User.creation_time), 'creation-date': search_util.create_date_filter(db.User.creation_time),
'creation-time': self._create_date_filter(db.User.creation_time), 'creation-time': search_util.create_date_filter(db.User.creation_time),
'last-login-date': self._create_date_filter(db.User.last_login_time), 'last-login-date': search_util.create_date_filter(db.User.last_login_time),
'last-login-time': self._create_date_filter(db.User.last_login_time), 'last-login-time': search_util.create_date_filter(db.User.last_login_time),
'login-date': self._create_date_filter(db.User.last_login_time), 'login-date': search_util.create_date_filter(db.User.last_login_time),
'login-time': self._create_date_filter(db.User.last_login_time), 'login-time': search_util.create_date_filter(db.User.last_login_time),
} }
@property @property

View File

@ -0,0 +1,124 @@
import sqlalchemy
from szurubooru import db, errors
from szurubooru.func import util
from szurubooru.search import criteria
def wildcard_transformer(value):
return value.replace('*', '%')
def apply_num_criterion_to_column(column, criterion):
'''
Decorate SQLAlchemy filter on given column using supplied criterion.
'''
try:
if isinstance(criterion, criteria.PlainCriterion):
expr = column == int(criterion.value)
elif isinstance(criterion, criteria.ArrayCriterion):
expr = column.in_(int(value) for value in criterion.values)
elif isinstance(criterion, criteria.RangedCriterion):
assert criterion.min_value != '' \
or criterion.max_value != ''
if criterion.min_value != '' and criterion.max_value != '':
expr = column.between(
int(criterion.min_value), int(criterion.max_value))
elif criterion.min_value != '':
expr = column >= int(criterion.min_value)
elif criterion.max_value != '':
expr = column <= int(criterion.max_value)
else:
assert False
except ValueError:
raise errors.SearchError(
'Criterion value %r must be a number.' % (criterion,))
return expr
def create_num_filter(column):
def wrapper(query, criterion, negated):
expr = apply_num_criterion_to_column(
column, criterion)
if negated:
expr = ~expr
return query.filter(expr)
return wrapper
def apply_str_criterion_to_column(
column, criterion, transformer=wildcard_transformer):
'''
Decorate SQLAlchemy filter on given column using supplied criterion.
'''
if isinstance(criterion, criteria.PlainCriterion):
expr = column.ilike(transformer(criterion.value))
elif isinstance(criterion, criteria.ArrayCriterion):
expr = sqlalchemy.sql.false()
for value in criterion.values:
expr = expr | column.ilike(transformer(value))
elif isinstance(criterion, criteria.RangedCriterion):
raise errors.SearchError(
'Composite token %r is invalid in this context.' % (criterion,))
else:
assert False
return expr
def create_str_filter(column, transformer=wildcard_transformer):
def wrapper(query, criterion, negated):
expr = apply_str_criterion_to_column(
column, criterion, transformer)
if negated:
expr = ~expr
return query.filter(expr)
return wrapper
def apply_date_criterion_to_column(column, criterion):
'''
Decorate SQLAlchemy filter on given column using supplied criterion.
Parse the datetime inside the criterion.
'''
if isinstance(criterion, criteria.PlainCriterion):
min_date, max_date = util.parse_time_range(criterion.value)
expr = column.between(min_date, max_date)
elif isinstance(criterion, criteria.ArrayCriterion):
expr = sqlalchemy.sql.false()
for value in criterion.values:
min_date, max_date = util.parse_time_range(value)
expr = expr | column.between(min_date, max_date)
elif isinstance(criterion, criteria.RangedCriterion):
assert criterion.min_value or criterion.max_value
if criterion.min_value and criterion.max_value:
min_date = util.parse_time_range(criterion.min_value)[0]
max_date = util.parse_time_range(criterion.max_value)[1]
expr = column.between(min_date, max_date)
elif criterion.min_value:
min_date = util.parse_time_range(criterion.min_value)[0]
expr = column >= min_date
elif criterion.max_value:
max_date = util.parse_time_range(criterion.max_value)[1]
expr = column <= max_date
else:
assert False
return expr
def create_date_filter(column):
def wrapper(query, criterion, negated):
expr = apply_date_criterion_to_column(
column, criterion)
if negated:
expr = ~expr
return query.filter(expr)
return wrapper
def create_subquery_filter(
left_id_column,
right_id_column,
filter_column,
filter_factory,
subquery_decorator=None):
filter_func = filter_factory(filter_column)
def wrapper(query, criterion, negated):
subquery = db.session.query(right_id_column.label('foreign_id'))
if subquery_decorator:
subquery = subquery_decorator(subquery)
subquery = subquery.options(sqlalchemy.orm.lazyload('*'))
subquery = filter_func(subquery, criterion, negated)
subquery = subquery.subquery('t')
return query.filter(left_id_column.in_(subquery))
return wrapper