86 lines
2.2 KiB
Python
86 lines
2.2 KiB
Python
import re
|
|
import enum
|
|
import decimal
|
|
import unicodedata
|
|
from sqlalchemy import inspect
|
|
from sqlalchemy.orm import exc, class_mapper
|
|
from sqlalchemy.orm.attributes import get_history
|
|
from werkzeug.exceptions import abort
|
|
|
|
|
|
def get_object_or_404(model, *criterion):
|
|
try:
|
|
rv = model.query.filter(*criterion).one()
|
|
except (exc.NoResultFound, exc.MultipleResultsFound):
|
|
abort(404)
|
|
else:
|
|
return rv
|
|
|
|
|
|
def strip_accents(text):
|
|
"""
|
|
Strip accents from input String.
|
|
|
|
:param text: The input string.
|
|
:type text: String.
|
|
|
|
:returns: The processed String.
|
|
:rtype: String.
|
|
"""
|
|
try:
|
|
text = unicode(text, 'utf-8')
|
|
except (TypeError, NameError): # unicode is a default on python 3
|
|
pass
|
|
text = unicodedata.normalize('NFD', text)
|
|
text = text.encode('ascii', 'ignore')
|
|
text = text.decode("utf-8")
|
|
return str(text)
|
|
|
|
|
|
def text_to_id(text):
|
|
"""
|
|
Convert input text to id.
|
|
|
|
:param text: The input string.
|
|
:type text: String.
|
|
|
|
:returns: The processed String.
|
|
:rtype: String.
|
|
"""
|
|
text = strip_accents(text.lower())
|
|
text = re.sub('[ ]+', '_', text)
|
|
text = re.sub('[^0-9a-zA-Z_-]', '', text)
|
|
return text
|
|
|
|
|
|
diff_sanitization_rules = [
|
|
(enum.Enum, lambda v: v.name),
|
|
(decimal.Decimal, float),
|
|
]
|
|
|
|
|
|
def get_diff(target, blacklist=['created', 'updated']):
|
|
state_before = {}
|
|
state_after = {}
|
|
inspr = inspect(target)
|
|
attrs = class_mapper(target.__class__).column_attrs
|
|
for attr in attrs:
|
|
if attr.key in blacklist:
|
|
continue
|
|
|
|
hist = getattr(inspr.attrs, attr.key).history
|
|
if hist.has_changes():
|
|
state_before[attr.key] = get_history(target, attr.key)[2].pop()
|
|
state_after[attr.key] = getattr(target, attr.key)
|
|
|
|
for data in [state_before, state_after]:
|
|
for t, c in diff_sanitization_rules:
|
|
if isinstance(data[attr.key], t):
|
|
data[attr.key] = c(data[attr.key])
|
|
|
|
if state_after[attr.key] == state_before[attr.key] or (state_after[attr.key] in ['', None] and state_before[attr.key] in ['', None]):
|
|
state_after.pop(attr.key)
|
|
state_before.pop(attr.key)
|
|
|
|
return state_before, state_after
|