236 lines
7.4 KiB
Python
236 lines
7.4 KiB
Python
|
from enum import Enum
|
||
|
|
||
|
from flask_admin.model import filters
|
||
|
|
||
|
|
||
|
class BookmarkField(Enum):
|
||
|
ID = 0
|
||
|
URL = 1
|
||
|
TITLE = 2
|
||
|
TAGS = 3
|
||
|
DESCRIPTION = 4
|
||
|
|
||
|
|
||
|
def equal_func(query, value, index):
|
||
|
return filter(lambda x: x[index] == value, query)
|
||
|
|
||
|
|
||
|
def not_equal_func(query, value, index):
|
||
|
return filter(lambda x: x[index] != value, query)
|
||
|
|
||
|
|
||
|
def greater_func(query, value, index):
|
||
|
return filter(lambda x: x[index] > value, query)
|
||
|
|
||
|
|
||
|
def smaller_func(query, value, index):
|
||
|
return filter(lambda x: x[index] > value, query)
|
||
|
|
||
|
|
||
|
def in_list_func(query, value, index):
|
||
|
return filter(lambda x: x[index] in value, query)
|
||
|
|
||
|
|
||
|
def not_in_list_func(query, value, index):
|
||
|
return filter(lambda x: x[index] not in value, query)
|
||
|
|
||
|
|
||
|
def top_x_func(query, value, index):
|
||
|
items = sorted(set(x[index] for x in query), reverse=True)
|
||
|
top_x = items[:value]
|
||
|
return filter(lambda x: x[index] in top_x, query)
|
||
|
|
||
|
|
||
|
def bottom_x_func(query, value, index):
|
||
|
items = sorted(set(x[index] for x in query), reverse=False)
|
||
|
top_x = items[:value]
|
||
|
return filter(lambda x: x[index] in top_x, query)
|
||
|
|
||
|
|
||
|
class FilterType(Enum):
|
||
|
|
||
|
EQUAL = {'func': equal_func, 'text':'equals'}
|
||
|
NOT_EQUAL = {'func': not_equal_func, 'text':'not equal'}
|
||
|
GREATER = {'func': greater_func, 'text':'greater than'}
|
||
|
SMALLER = {'func': smaller_func, 'text':'smaller than'}
|
||
|
IN_LIST = {'func': in_list_func, 'text':'in list'}
|
||
|
NOT_IN_LIST = {'func': not_in_list_func, 'text':'not in list'}
|
||
|
TOP_X = {'func': top_x_func, 'text': 'top x'}
|
||
|
BOTTOM_X = {'func': bottom_x_func, 'text': 'bottom x'}
|
||
|
|
||
|
|
||
|
class BaseFilter(filters.BaseFilter):
|
||
|
|
||
|
def operation(self):
|
||
|
return getattr(self, 'operation_text')
|
||
|
|
||
|
def apply(self, query, value):
|
||
|
return getattr(self, 'apply_func')(query, value, getattr(self, 'index'))
|
||
|
|
||
|
|
||
|
class TagBaseFilter(BaseFilter):
|
||
|
|
||
|
def __init__(self, name, operation_text=None, apply_func=None, filter_type=None, options=None, data_type=None):
|
||
|
if operation_text in ('in list', 'not in list'):
|
||
|
super().__init__(name, options, data_type='select2-tags')
|
||
|
else:
|
||
|
super().__init__(name, options, data_type)
|
||
|
if name == 'name':
|
||
|
self.index = 0
|
||
|
elif name == 'usage_count':
|
||
|
self.index = 1
|
||
|
else:
|
||
|
raise ValueError('name: {}'.format(name))
|
||
|
self.filter_type = None
|
||
|
if filter_type:
|
||
|
self.apply_func = filter_type.value['func']
|
||
|
self.operation_text = filter_type.value['text']
|
||
|
self.filter_type = filter_type
|
||
|
else:
|
||
|
self.apply_func = apply_func
|
||
|
self.operation_text = operation_text
|
||
|
|
||
|
def clean(self, value):
|
||
|
if self.filter_type in (FilterType.IN_LIST, FilterType.NOT_IN_LIST) and self.name == 'usage_count':
|
||
|
value = [int(v.strip()) for v in value.split(',') if v.strip()]
|
||
|
elif self.filter_type in (FilterType.IN_LIST, FilterType.NOT_IN_LIST):
|
||
|
value = [v.strip() for v in value.split(',') if v.strip()]
|
||
|
elif self.name == 'usage_count':
|
||
|
value = int(value)
|
||
|
if self.filter_type in (FilterType.TOP_X, FilterType.BOTTOM_X) and value < 1:
|
||
|
raise ValueError
|
||
|
if isinstance(value, str):
|
||
|
return value.strip()
|
||
|
return value
|
||
|
|
||
|
|
||
|
class BookmarkBukuFilter(BaseFilter):
|
||
|
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
self.keys = {
|
||
|
'all_keywords': 'match all',
|
||
|
'deep': 'deep',
|
||
|
'regex': 'regex'
|
||
|
}
|
||
|
for key, value in kwargs.items():
|
||
|
if key in self.keys and value:
|
||
|
setattr(self, key, value)
|
||
|
else:
|
||
|
setattr(self, key, False)
|
||
|
list(map(lambda x: kwargs.pop(x), self.keys))
|
||
|
super().__init__('buku', *args, **kwargs)
|
||
|
|
||
|
def operation(self):
|
||
|
parts = []
|
||
|
for key, value in self.keys.items():
|
||
|
if getattr(self, key):
|
||
|
parts.append(value)
|
||
|
if not parts:
|
||
|
return 'search'
|
||
|
return 'search ' + ', '.join(parts)
|
||
|
|
||
|
def apply(self, query, value):
|
||
|
return query
|
||
|
|
||
|
|
||
|
class BookmarkBaseFilter(BaseFilter):
|
||
|
|
||
|
def __init__(self, name, operation_text=None, apply_func=None, filter_type=None, options=None, data_type=None):
|
||
|
if operation_text in ('in list', 'not in list'):
|
||
|
super().__init__(name, options, data_type='select2-tags')
|
||
|
else:
|
||
|
super().__init__(name, options, data_type)
|
||
|
bm_fields_dict = {x.name.lower(): x.value for x in BookmarkField}
|
||
|
if name in bm_fields_dict:
|
||
|
self.index = bm_fields_dict[name]
|
||
|
else:
|
||
|
raise ValueError('name: {}'.format(name))
|
||
|
self.filter_type = None
|
||
|
if filter_type:
|
||
|
self.apply_func = filter_type.value['func']
|
||
|
self.operation_text = filter_type.value['text']
|
||
|
else:
|
||
|
self.apply_func = apply_func
|
||
|
self.operation_text = operation_text
|
||
|
|
||
|
def clean(self, value):
|
||
|
if self.filter_type in (FilterType.IN_LIST, FilterType.NOT_IN_LIST) and self.name == BookmarkField.ID.name.lower():
|
||
|
value = [int(v.strip()) for v in value.split(',') if v.strip()]
|
||
|
elif self.filter_type in (FilterType.IN_LIST, FilterType.NOT_IN_LIST):
|
||
|
value = [v.strip() for v in value.split(',') if v.strip()]
|
||
|
elif self.name == BookmarkField.ID.name.lower():
|
||
|
value = int(value)
|
||
|
if self.filter_type in (FilterType.TOP_X, FilterType.BOTTOM_X) and value < 1:
|
||
|
raise ValueError
|
||
|
if isinstance(value, str):
|
||
|
return value.strip()
|
||
|
return value
|
||
|
|
||
|
|
||
|
class BookmarkTagNumberEqualFilter(BookmarkBaseFilter):
|
||
|
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
super().__init__(*args, **kwargs)
|
||
|
|
||
|
def apply_func(query, value, index):
|
||
|
for item in query:
|
||
|
tags = [tag for tag in item[index].split(',') if tag]
|
||
|
if len(tags) == value:
|
||
|
yield item
|
||
|
|
||
|
self.apply_func = apply_func
|
||
|
|
||
|
def clean(self, value):
|
||
|
value = int(value)
|
||
|
if value < 0:
|
||
|
raise ValueError
|
||
|
return value
|
||
|
|
||
|
|
||
|
class BookmarkTagNumberGreaterFilter(BookmarkTagNumberEqualFilter):
|
||
|
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
super().__init__(*args, **kwargs)
|
||
|
|
||
|
def apply_func(query, value, index):
|
||
|
for item in query:
|
||
|
tags = [tag for tag in item[index].split(',') if tag]
|
||
|
if len(tags) > value:
|
||
|
yield item
|
||
|
|
||
|
self.apply_func = apply_func
|
||
|
|
||
|
|
||
|
class BookmarkTagNumberNotEqualFilter(BookmarkTagNumberEqualFilter):
|
||
|
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
super().__init__(*args, **kwargs)
|
||
|
|
||
|
def apply_func(query, value, index):
|
||
|
for item in query:
|
||
|
tags = [tag for tag in item[index].split(',') if tag]
|
||
|
if len(tags) != value:
|
||
|
yield item
|
||
|
|
||
|
self. apply_func = apply_func
|
||
|
|
||
|
|
||
|
class BookmarkTagNumberSmallerFilter(BookmarkBaseFilter):
|
||
|
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
super().__init__(*args, **kwargs)
|
||
|
|
||
|
def apply_func(query, value, index):
|
||
|
for item in query:
|
||
|
tags = [tag for tag in item[index].split(',') if tag]
|
||
|
if len(tags) < value:
|
||
|
yield item
|
||
|
|
||
|
self.apply_func = apply_func
|
||
|
|
||
|
def clean(self, value):
|
||
|
value = int(value)
|
||
|
if value < 1:
|
||
|
raise ValueError
|
||
|
return value
|