Add remarks, status and changelog

master
informatic 2020-03-27 19:04:29 +01:00
parent b28e847a9c
commit b497ac3d8d
7 changed files with 185 additions and 2 deletions

View File

@ -1,13 +1,69 @@
from formity.extensions import admin, db, ModelView
from formity.models import FaceshieldRequest
from formity.models import FaceshieldRequest, RequestChange
from spaceauth import current_user
import enum
from sqlalchemy import inspect
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 FaceshieldRequestAdmin(ModelView):
details_modal_template = 'changelog_details_modal.html'
edit_template = 'changelog_edit.html'
column_filters = (
'entity_info', 'full_name', 'phone_number', 'email', 'extra',
'faceshield_front_required', 'faceshield_model',
'faceshield_full_required',
'created', 'ua', 'ip',
'created', 'ua', 'ip', 'status', 'remarks',
)
column_list = ('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
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,
))
admin.add_view(FaceshieldRequestAdmin(FaceshieldRequest, db.session))

View File

@ -1,5 +1,14 @@
from formity.extensions import db
from datetime import datetime
import enum
class Status(enum.Enum):
new = 1
confirmed = 2
allocated = 3
fulfilled = 4
rejected = 5
class FaceshieldRequest(db.Model):
@ -22,3 +31,19 @@ class FaceshieldRequest(db.Model):
ua = db.Column(db.String)
ip = db.Column(db.String)
status = db.Column(db.Enum(Status), default=Status.new, server_default='new', nullable=False)
remarks = db.Column(db.String)
class RequestChange(db.Model):
id = db.Column(db.Integer, primary_key=True)
request_id = db.Column(db.Integer, db.ForeignKey(FaceshieldRequest.id))
request = db.relationship(FaceshieldRequest, backref='changelog')
user_id = db.Column(db.String, nullable=False)
state_before = db.Column(db.JSON)
state_after = db.Column(db.JSON)
remarks = db.Column(db.String)
created = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)

View File

@ -0,0 +1,38 @@
"""Add RequestChange
Revision ID: 77ec5ee5da15
Revises: adce9713c86f
Create Date: 2020-03-27 17:42:38.009456
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '77ec5ee5da15'
down_revision = 'adce9713c86f'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('request_change',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('request_id', sa.Integer(), nullable=True),
sa.Column('user_id', sa.String(), nullable=False),
sa.Column('state_before', sa.JSON(), nullable=True),
sa.Column('state_after', sa.JSON(), nullable=True),
sa.Column('remarks', sa.String(), nullable=True),
sa.Column('created', sa.DateTime(), nullable=False),
sa.ForeignKeyConstraint(['request_id'], ['faceshield_request.id'], ),
sa.PrimaryKeyConstraint('id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('request_change')
# ### end Alembic commands ###

View File

@ -0,0 +1,34 @@
"""Add remarks and status fields
Revision ID: adce9713c86f
Revises: 383ca469a0fe
Create Date: 2020-03-27 17:16:20.158951
"""
from alembic import op
import sqlalchemy as sa
status = sa.Enum('new', 'confirmed', 'allocated', 'fulfilled', 'rejected', name='status')
# revision identifiers, used by Alembic.
revision = 'adce9713c86f'
down_revision = '383ca469a0fe'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
status.create(op.get_bind())
op.add_column('faceshield_request', sa.Column('remarks', sa.String(), nullable=True))
op.add_column('faceshield_request', sa.Column('status', status, server_default='new', nullable=False))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('faceshield_request', 'status')
op.drop_column('faceshield_request', 'remarks')
status.drop(op.get_bind())
# ### end Alembic commands ###

15
templates/_changelog.html Normal file
View File

@ -0,0 +1,15 @@
{% macro render_changelog(model) %}
{% for entry in model.changelog %}
<p>
<span class="text-muted">{{ entry.created.strftime('%Y/%m/%d %H:%M') }}</span> <b>{{ entry.user_id }}</b> changed
{% for key, value in entry.state_after.items() %}
{%- if not loop.first -%}
{%- if loop.last -%}
and
{%- else -%}
,
{%- endif -%}
{%- endif %} <b>{{ key }}</b> to <code title="{{ value }}">{{ value|truncate(40) }}</code> {% endfor %}
</p>
{% endfor %}
{% endmacro %}

View File

@ -0,0 +1,7 @@
{% extends "admin/model/modals/details.html" %}
{% from "_changelog.html" import render_changelog %}
{% block details_table %}
{{ super() }}
{{ render_changelog(model) }}
{% endblock %}

View File

@ -0,0 +1,8 @@
{% extends "admin/model/edit.html" %}
{% from "_changelog.html" import render_changelog %}
{% block body %}
{{ super() }}
{{ render_changelog(model) }}
{% endblock %}