covid-formity/formity/admin.py

111 lines
4.5 KiB
Python

import flask_admin
from formity.extensions import admin, db, ModelView, AdminSecurityMixin
from wtforms import TextAreaField
from formity.models import FaceshieldRequest, RequestChange, Status
from spaceauth import current_user
import enum
from sqlalchemy import inspect, func
from sqlalchemy.orm import class_mapper
from sqlalchemy.orm.attributes import get_history
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()
if isinstance(state_before[attr.key], enum.Enum):
state_before[attr.key] = state_before[attr.key].name
state_after[attr.key] = getattr(target, 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
class IndexView(AdminSecurityMixin, flask_admin.AdminIndexView):
@flask_admin.expose('/')
def index(self):
stats = FaceshieldRequest.query.with_entities(
FaceshieldRequest.status.label('status'),
func.count().label('count'),
func.sum(FaceshieldRequest.faceshield_full_required).label('faceshield_full_required'),
func.sum(FaceshieldRequest.faceshield_full_delivered).label('faceshield_full_delivered'),
func.sum(FaceshieldRequest.faceshield_front_required).label('faceshield_front_required'),
func.sum(FaceshieldRequest.faceshield_front_delivered).label('faceshield_front_delivered'),
).group_by(FaceshieldRequest.status).all()
stats.sort(key=lambda v: v.status.value)
for rec in stats:
print(dir(rec))
return self.render('admin_index.html', stats=stats)
class FaceshieldRequestAdmin(ModelView):
column_default_sort = 'created'
details_modal_template = 'changelog_details_modal.html'
edit_template = 'changelog_edit.html'
column_searchable_list = ('email', 'remarks', 'extra', 'entity_info', 'full_name')
column_filters = (
'entity_info', 'full_name', 'phone_number', 'email', 'extra',
'faceshield_front_required', 'faceshield_model',
'faceshield_full_required',
'created', 'ua', 'ip', 'status', 'remarks',
'shipping_name', 'shipping_street', 'shipping_postalcode', 'shipping_city',
'postalcode_info',
)
form_overrides = {'entity_info': TextAreaField, 'extra': TextAreaField, 'remarks': TextAreaField}
form_excluded_columns = ('changelog', 'postalcode_info')
column_export_list = ['id', *column_filters]
column_list = ('id', 'entity_info', 'full_name', 'faceshield_front_required', 'faceshield_full_required', 'created', 'status')
column_editable_list = ('status', 'remarks')
can_delete = False
can_view_details = True
details_modal = True
can_export = True
can_set_page_size = True
def on_model_change(self, form, model, is_created):
if is_created:
return
try:
before, after = get_diff(model)
except Exception:
# xD
before, after = {'diff': 'failed'}, {'diff': 'failed'}
if before or after:
db.session.add(RequestChange(
user_id=current_user.get_id() or 'nobody',
request_id=model.id,
state_before=before,
state_after=after,
))
class FilteredFaceshieldRequestAdmin(FaceshieldRequestAdmin):
def get_query(self):
return super(FilteredFaceshieldRequestAdmin, self).get_query().filter(FaceshieldRequest.status != Status.rejected)
class ShippingFaceshieldRequestAdmin(FaceshieldRequestAdmin):
column_editable_list = ('shipping_name', 'shipping_street', 'shipping_postalcode', 'shipping_city', 'status')
column_list = ['id', 'entity_info', 'full_name', *column_editable_list]
admin.add_view(FaceshieldRequestAdmin(FaceshieldRequest, db.session))
admin.add_view(FilteredFaceshieldRequestAdmin(FaceshieldRequest, db.session, name='FaceshieldRequest (Filtered)', endpoint='request_filtered'))
admin.add_view(ShippingFaceshieldRequestAdmin(FaceshieldRequest, db.session, name='FaceshieldRequest (Shipping)', endpoint='request_shipping'))