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'))