mirror of
https://github.com/DarkflameUniverse/NexusDashboard.git
synced 2024-11-29 00:47:23 +00:00
commit
9cc3dbb4c4
@ -13,7 +13,7 @@ from flask_apscheduler import APScheduler
|
|||||||
from app.luclient import query_cdclient, register_luclient_jinja_helpers
|
from app.luclient import query_cdclient, register_luclient_jinja_helpers
|
||||||
|
|
||||||
from app.commands import init_db, init_accounts, load_property, gen_image_cache, gen_model_cache
|
from app.commands import init_db, init_accounts, load_property, gen_image_cache, gen_model_cache
|
||||||
from app.models import Account, AccountInvitation
|
from app.models import Account, AccountInvitation, AuditLog
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from logging.handlers import RotatingFileHandler
|
from logging.handlers import RotatingFileHandler
|
||||||
@ -245,3 +245,9 @@ def gm_level(gm_level):
|
|||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
return wrapper
|
return wrapper
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
def log_audit(message):
|
||||||
|
AuditLog(
|
||||||
|
account_id=current_user.id,
|
||||||
|
action=message
|
||||||
|
).save()
|
||||||
|
@ -6,7 +6,7 @@ import datetime
|
|||||||
import time
|
import time
|
||||||
from app.models import Account, AccountInvitation, db
|
from app.models import Account, AccountInvitation, db
|
||||||
from app.schemas import AccountSchema
|
from app.schemas import AccountSchema
|
||||||
from app import gm_level
|
from app import gm_level, log_audit
|
||||||
from app.forms import EditGMLevelForm
|
from app.forms import EditGMLevelForm
|
||||||
|
|
||||||
accounts_blueprint = Blueprint('accounts', __name__)
|
accounts_blueprint = Blueprint('accounts', __name__)
|
||||||
@ -46,8 +46,10 @@ def edit_gm_level(id):
|
|||||||
form = EditGMLevelForm()
|
form = EditGMLevelForm()
|
||||||
|
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
|
log_audit(f"Changed ({account_data.id}){account_data.username}'s GM Level from {account_data.gm_level} to {form.gm_level.data}")
|
||||||
account_data.gm_level = form.gm_level.data
|
account_data.gm_level = form.gm_level.data
|
||||||
account_data.save()
|
account_data.save()
|
||||||
|
|
||||||
return redirect(url_for('accounts.view', id=account_data.id))
|
return redirect(url_for('accounts.view', id=account_data.id))
|
||||||
|
|
||||||
form.gm_level.data = account_data.gm_level
|
form.gm_level.data = account_data.gm_level
|
||||||
@ -63,8 +65,10 @@ def lock(id):
|
|||||||
account.locked = not account.locked
|
account.locked = not account.locked
|
||||||
account.save()
|
account.save()
|
||||||
if account.locked:
|
if account.locked:
|
||||||
|
log_audit(f"Locked ({account.id}){account.username}")
|
||||||
flash("Locked Account", "danger")
|
flash("Locked Account", "danger")
|
||||||
else:
|
else:
|
||||||
|
log_audit(f"Unlocked ({account.id}){account.username}")
|
||||||
flash("Unlocked account", "success")
|
flash("Unlocked account", "success")
|
||||||
return redirect(request.referrer if request.referrer else url_for("main.index"))
|
return redirect(request.referrer if request.referrer else url_for("main.index"))
|
||||||
|
|
||||||
@ -77,8 +81,10 @@ def ban(id):
|
|||||||
account.banned = not account.banned
|
account.banned = not account.banned
|
||||||
account.save()
|
account.save()
|
||||||
if account.banned:
|
if account.banned:
|
||||||
|
log_audit(f"Banned ({account.id}){account.username}")
|
||||||
flash("Banned Account", "danger")
|
flash("Banned Account", "danger")
|
||||||
else:
|
else:
|
||||||
|
log_audit(f"Unbanned ({account.id}){account.username}")
|
||||||
flash("Unbanned account", "success")
|
flash("Unbanned account", "success")
|
||||||
return redirect(request.referrer if request.referrer else url_for("main.index"))
|
return redirect(request.referrer if request.referrer else url_for("main.index"))
|
||||||
|
|
||||||
@ -90,10 +96,12 @@ def mute(id, days=0):
|
|||||||
account = Account.query.filter(Account.id == id).first()
|
account = Account.query.filter(Account.id == id).first()
|
||||||
if days == "0":
|
if days == "0":
|
||||||
account.mute_expire = 0
|
account.mute_expire = 0
|
||||||
|
log_audit(f"Unmuted ({account.id}){account.username}")
|
||||||
flash("Unmuted Account", "success")
|
flash("Unmuted Account", "success")
|
||||||
else:
|
else:
|
||||||
muted_intil = datetime.datetime.now() + datetime.timedelta(days=int(days))
|
muted_intil = datetime.datetime.now() + datetime.timedelta(days=int(days))
|
||||||
account.mute_expire = muted_intil.timestamp()
|
account.mute_expire = muted_intil.timestamp()
|
||||||
|
log_audit(f"Muted ({account.id}){account.username} for {days} days")
|
||||||
flash(f"Muted account for {days} days", "danger")
|
flash(f"Muted account for {days} days", "danger")
|
||||||
account.save()
|
account.save()
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ from datatables import ColumnDT, DataTables
|
|||||||
import datetime, time
|
import datetime, time
|
||||||
from app.models import CharacterInfo, CharacterXML, Account, db
|
from app.models import CharacterInfo, CharacterXML, Account, db
|
||||||
from app.schemas import CharacterInfoSchema
|
from app.schemas import CharacterInfoSchema
|
||||||
from app import gm_level
|
from app import gm_level, log_audit
|
||||||
import xmltodict
|
import xmltodict
|
||||||
|
|
||||||
character_blueprint = Blueprint('characters', __name__)
|
character_blueprint = Blueprint('characters', __name__)
|
||||||
@ -26,16 +26,19 @@ def approve_name(id, action):
|
|||||||
character = CharacterInfo.query.filter(CharacterInfo.id == id).first()
|
character = CharacterInfo.query.filter(CharacterInfo.id == id).first()
|
||||||
|
|
||||||
if action == "approve":
|
if action == "approve":
|
||||||
|
log_audit(f"Approved ({character.id}){character.pending_name} from {character.name}")
|
||||||
|
flash(
|
||||||
|
f"Approved ({character.id}){character.pending_name} from {character.name}",
|
||||||
|
"success"
|
||||||
|
)
|
||||||
if character.pending_name:
|
if character.pending_name:
|
||||||
character.name = character.pending_name
|
character.name = character.pending_name
|
||||||
character.pending_name = ""
|
character.pending_name = ""
|
||||||
character.needs_rename = False
|
character.needs_rename = False
|
||||||
flash(
|
|
||||||
f"Approved name {character.name}",
|
|
||||||
"success"
|
|
||||||
)
|
|
||||||
elif action == "rename":
|
elif action == "rename":
|
||||||
character.needs_rename = True
|
character.needs_rename = True
|
||||||
|
log_audit(f"Marked character ({character.id}){character.name} (Pending Name: {character.pending_name if character.pending_name else 'None'}) as needing Rename")
|
||||||
flash(
|
flash(
|
||||||
f"Marked character {character.name} (Pending Name: {character.pending_name if character.pending_name else 'None'}) as needing Rename",
|
f"Marked character {character.name} (Pending Name: {character.pending_name if character.pending_name else 'None'}) as needing Rename",
|
||||||
"danger"
|
"danger"
|
||||||
@ -146,6 +149,9 @@ def restrict(id, bit):
|
|||||||
abort(404)
|
abort(404)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
log_audit(f"Updated ({character_data.id}){character_data.name}'s permission map to \
|
||||||
|
{character_data.permission_map ^ (1 << int(bit))} from {character_data.permission_map}")
|
||||||
|
|
||||||
character_data.permission_map ^= (1 << int(bit))
|
character_data.permission_map ^= (1 << int(bit))
|
||||||
character_data.save()
|
character_data.save()
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ from flask_user import login_required, current_user
|
|||||||
from app.models import db, Mail, CharacterInfo
|
from app.models import db, Mail, CharacterInfo
|
||||||
from datatables import ColumnDT, DataTables
|
from datatables import ColumnDT, DataTables
|
||||||
from app.forms import SendMailForm
|
from app.forms import SendMailForm
|
||||||
from app import gm_level
|
from app import gm_level, log_audit
|
||||||
from app.luclient import translate_from_locale, query_cdclient
|
from app.luclient import translate_from_locale, query_cdclient
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@ -29,6 +29,7 @@ def send():
|
|||||||
if form.attachment.data != "0" and form.attachment_count.data == 0:
|
if form.attachment.data != "0" and form.attachment_count.data == 0:
|
||||||
form.attachment_count.data = 1
|
form.attachment_count.data = 1
|
||||||
if form.recipient.data == "0":
|
if form.recipient.data == "0":
|
||||||
|
log_audit(f"Sending {form.subject.data}: {form.body.data} to All Characters with {form.attachment_count.data} of item {form.attachment.data}")
|
||||||
for character in CharacterInfo.query.all():
|
for character in CharacterInfo.query.all():
|
||||||
Mail(
|
Mail(
|
||||||
sender_id = 0,
|
sender_id = 0,
|
||||||
@ -42,6 +43,7 @@ def send():
|
|||||||
attachment_lot = form.attachment.data,
|
attachment_lot = form.attachment.data,
|
||||||
attachment_count = form.attachment_count.data
|
attachment_count = form.attachment_count.data
|
||||||
).save()
|
).save()
|
||||||
|
log_audit(f"Sent {form.subject.data}: {form.body.data} to ({character.id}){character.name} with {form.attachment_count.data} of item {form.attachment.data}")
|
||||||
else:
|
else:
|
||||||
Mail(
|
Mail(
|
||||||
sender_id = 0,
|
sender_id = 0,
|
||||||
@ -55,6 +57,7 @@ def send():
|
|||||||
attachment_lot = form.attachment.data,
|
attachment_lot = form.attachment.data,
|
||||||
attachment_count = form.attachment_count.data
|
attachment_count = form.attachment_count.data
|
||||||
).save()
|
).save()
|
||||||
|
log_audit(f"Sent {form.subject.data}: {form.body.data} to ({form.recipient.data}){CharacterInfo.query.filter(CharacterInfo.id == form.recipient.data).first().name} with {form.attachment_count.data} of item {form.attachment.data}")
|
||||||
|
|
||||||
flash("Sent Mail", "success")
|
flash("Sent Mail", "success")
|
||||||
return redirect(url_for('mail.send'))
|
return redirect(url_for('mail.send'))
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
from flask_migrate import Migrate
|
from flask_migrate import Migrate
|
||||||
from flask_user import UserMixin
|
from flask_user import UserMixin, current_user
|
||||||
from wtforms import ValidationError
|
from wtforms import ValidationError
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@ -1010,3 +1010,42 @@ class Reports(db.Model):
|
|||||||
def delete(self):
|
def delete(self):
|
||||||
db.session.delete(self)
|
db.session.delete(self)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
class AuditLog(db.Model):
|
||||||
|
__tablename__ = 'audit_logs'
|
||||||
|
id = db.Column(
|
||||||
|
mysql.INTEGER,
|
||||||
|
primary_key=True
|
||||||
|
)
|
||||||
|
|
||||||
|
account_id = db.Column(
|
||||||
|
db.Integer(),
|
||||||
|
db.ForeignKey(Account.id, ondelete='CASCADE'),
|
||||||
|
nullable=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
account = db.relationship(
|
||||||
|
'Account',
|
||||||
|
backref="audit_logs",
|
||||||
|
passive_deletes=True
|
||||||
|
)
|
||||||
|
|
||||||
|
action = db.Column(
|
||||||
|
mysql.TEXT,
|
||||||
|
nullable=False
|
||||||
|
)
|
||||||
|
|
||||||
|
date = db.Column(
|
||||||
|
mysql.TIMESTAMP,
|
||||||
|
nullable=False,
|
||||||
|
server_default=db.func.now()
|
||||||
|
)
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
db.session.add(self)
|
||||||
|
db.session.commit()
|
||||||
|
db.session.refresh(self)
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
db.session.delete(self)
|
||||||
|
db.session.commit()
|
||||||
|
@ -3,7 +3,7 @@ from flask_user import login_required
|
|||||||
from app.models import PetNames, db
|
from app.models import PetNames, db
|
||||||
from datatables import ColumnDT, DataTables
|
from datatables import ColumnDT, DataTables
|
||||||
from app.forms import CreatePlayKeyForm, EditPlayKeyForm
|
from app.forms import CreatePlayKeyForm, EditPlayKeyForm
|
||||||
from app import gm_level
|
from app import gm_level, log_audit
|
||||||
|
|
||||||
moderation_blueprint = Blueprint('moderation', __name__)
|
moderation_blueprint = Blueprint('moderation', __name__)
|
||||||
|
|
||||||
@ -23,6 +23,7 @@ def approve_pet(id):
|
|||||||
pet_data = PetNames.query.filter(PetNames.id == id).first()
|
pet_data = PetNames.query.filter(PetNames.id == id).first()
|
||||||
|
|
||||||
pet_data.approved = 2
|
pet_data.approved = 2
|
||||||
|
log_audit(f"Approved pet name {pet_data.pet_name}")
|
||||||
flash(f"Approved pet name {pet_data.pet_name}", "success")
|
flash(f"Approved pet name {pet_data.pet_name}", "success")
|
||||||
pet_data.save()
|
pet_data.save()
|
||||||
return redirect(request.referrer if request.referrer else url_for("main.index"))
|
return redirect(request.referrer if request.referrer else url_for("main.index"))
|
||||||
@ -36,6 +37,7 @@ def reject_pet(id):
|
|||||||
pet_data = PetNames.query.filter(PetNames.id == id).first()
|
pet_data = PetNames.query.filter(PetNames.id == id).first()
|
||||||
|
|
||||||
pet_data.approved = 0
|
pet_data.approved = 0
|
||||||
|
log_audit(f"Rejected pet name {pet_data.pet_name}")
|
||||||
flash(f"Rejected pet name {pet_data.pet_name}", "danger")
|
flash(f"Rejected pet name {pet_data.pet_name}", "danger")
|
||||||
pet_data.save()
|
pet_data.save()
|
||||||
return redirect(request.referrer if request.referrer else url_for("main.index"))
|
return redirect(request.referrer if request.referrer else url_for("main.index"))
|
||||||
|
@ -3,7 +3,7 @@ from flask_user import login_required, current_user
|
|||||||
from app.models import Account, AccountInvitation, PlayKey, db
|
from app.models import Account, AccountInvitation, PlayKey, db
|
||||||
from datatables import ColumnDT, DataTables
|
from datatables import ColumnDT, DataTables
|
||||||
from app.forms import CreatePlayKeyForm, EditPlayKeyForm
|
from app.forms import CreatePlayKeyForm, EditPlayKeyForm
|
||||||
from app import gm_level
|
from app import gm_level, log_audit
|
||||||
|
|
||||||
play_keys_blueprint = Blueprint('play_keys', __name__)
|
play_keys_blueprint = Blueprint('play_keys', __name__)
|
||||||
|
|
||||||
@ -21,6 +21,7 @@ def index():
|
|||||||
@gm_level(9)
|
@gm_level(9)
|
||||||
def create(count=1, uses=1):
|
def create(count=1, uses=1):
|
||||||
PlayKey.create(count=count, uses=uses)
|
PlayKey.create(count=count, uses=uses)
|
||||||
|
log_audit(f"Created {count} Play Key(s) with {uses} uses!")
|
||||||
flash(f"Created {count} Play Key(s) with {uses} uses!", "success")
|
flash(f"Created {count} Play Key(s) with {uses} uses!", "success")
|
||||||
return redirect(url_for('play_keys.index'))
|
return redirect(url_for('play_keys.index'))
|
||||||
|
|
||||||
@ -32,6 +33,8 @@ def bulk_create():
|
|||||||
form = CreatePlayKeyForm()
|
form = CreatePlayKeyForm()
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
PlayKey.create(count=form.count.data, uses=form.uses.data)
|
PlayKey.create(count=form.count.data, uses=form.uses.data)
|
||||||
|
log_audit(f"Created {form.count.data} Play Key(s) with {form.uses.data} uses!")
|
||||||
|
flash(f"Created {form.count.data} Play Key(s) with {form.uses.data} uses!", "success")
|
||||||
return redirect(url_for('play_keys.index'))
|
return redirect(url_for('play_keys.index'))
|
||||||
|
|
||||||
return render_template('play_keys/bulk.html.j2', form=form)
|
return render_template('play_keys/bulk.html.j2', form=form)
|
||||||
@ -43,6 +46,7 @@ def bulk_create():
|
|||||||
def delete(id):
|
def delete(id):
|
||||||
key = PlayKey.query.filter(PlayKey.id == id).first()
|
key = PlayKey.query.filter(PlayKey.id == id).first()
|
||||||
associated_accounts = Account.query.filter(Account.play_key_id==id).all()
|
associated_accounts = Account.query.filter(Account.play_key_id==id).all()
|
||||||
|
log_audit(f"Deleted Play Key {key.key_string}")
|
||||||
flash(f"Deleted Play Key {key.key_string}", "danger")
|
flash(f"Deleted Play Key {key.key_string}", "danger")
|
||||||
key.delete()
|
key.delete()
|
||||||
return redirect(url_for('play_keys.index'))
|
return redirect(url_for('play_keys.index'))
|
||||||
@ -56,10 +60,16 @@ def edit(id):
|
|||||||
form = EditPlayKeyForm()
|
form = EditPlayKeyForm()
|
||||||
|
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
|
log_audit(f"Updated Play key {key.id} \
|
||||||
|
Uses: {key.key_uses}:{form.uses.data} \
|
||||||
|
Active: {key.active}:{form.active.data} \
|
||||||
|
Notes: {key.notes}:{form.notes.data} \
|
||||||
|
")
|
||||||
key.key_uses = form.uses.data
|
key.key_uses = form.uses.data
|
||||||
key.active = form.active.data
|
key.active = form.active.data
|
||||||
key.notes = form.notes.data
|
key.notes = form.notes.data
|
||||||
key.save()
|
key.save()
|
||||||
|
|
||||||
return redirect(url_for('play_keys.index'))
|
return redirect(url_for('play_keys.index'))
|
||||||
|
|
||||||
form.uses.data = key.key_uses
|
form.uses.data = key.key_uses
|
||||||
|
@ -16,7 +16,7 @@ from datatables import ColumnDT, DataTables
|
|||||||
import time
|
import time
|
||||||
from app.models import Property, db, UGC, CharacterInfo, PropertyContent, Account
|
from app.models import Property, db, UGC, CharacterInfo, PropertyContent, Account
|
||||||
from app.schemas import PropertySchema
|
from app.schemas import PropertySchema
|
||||||
from app import gm_level
|
from app import gm_level, log_audit
|
||||||
from app.luclient import query_cdclient
|
from app.luclient import query_cdclient
|
||||||
|
|
||||||
import zlib
|
import zlib
|
||||||
@ -50,25 +50,29 @@ def approve(id):
|
|||||||
property_data.rejection_reason = ""
|
property_data.rejection_reason = ""
|
||||||
|
|
||||||
if property_data.mod_approved:
|
if property_data.mod_approved:
|
||||||
flash(
|
message = f"""Approved Property
|
||||||
f"""Approved Property
|
|
||||||
{property_data.name if property_data.name else query_cdclient(
|
{property_data.name if property_data.name else query_cdclient(
|
||||||
'select DisplayDescription from ZoneTable where zoneID = ?',
|
'select DisplayDescription from ZoneTable where zoneID = ?',
|
||||||
[property_data.zone_id],
|
[property_data.zone_id],
|
||||||
one=True
|
one=True
|
||||||
)[0]}
|
)[0]}
|
||||||
from {CharacterInfo.query.filter(CharacterInfo.id==property_data.owner_id).first().name}""",
|
from {CharacterInfo.query.filter(CharacterInfo.id==property_data.owner_id).first().name}"""
|
||||||
|
log_audit(message)
|
||||||
|
flash(
|
||||||
|
message,
|
||||||
"success"
|
"success"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
flash(
|
message = f"""Unapproved Property
|
||||||
f"""Unapproved Property
|
|
||||||
{property_data.name if property_data.name else query_cdclient(
|
{property_data.name if property_data.name else query_cdclient(
|
||||||
'select DisplayDescription from ZoneTable where zoneID = ?',
|
'select DisplayDescription from ZoneTable where zoneID = ?',
|
||||||
[property_data.zone_id],
|
[property_data.zone_id],
|
||||||
one=True
|
one=True
|
||||||
)[0]}
|
)[0]}
|
||||||
from {CharacterInfo.query.filter(CharacterInfo.id==property_data.owner_id).first().name}""",
|
from {CharacterInfo.query.filter(CharacterInfo.id==property_data.owner_id).first().name}"""
|
||||||
|
log_audit(message)
|
||||||
|
flash(
|
||||||
|
message,
|
||||||
"danger"
|
"danger"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
38
migrations/versions/3132aaef7413_fix_nullables.py
Normal file
38
migrations/versions/3132aaef7413_fix_nullables.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
"""fix nullables
|
||||||
|
|
||||||
|
Revision ID: 3132aaef7413
|
||||||
|
Revises: bd908969d8fe
|
||||||
|
Create Date: 2022-02-11 21:51:58.479066
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import mysql
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '3132aaef7413'
|
||||||
|
down_revision = 'bd908969d8fe'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.alter_column('audit_logs', 'account_id',
|
||||||
|
existing_type=mysql.INTEGER(display_width=11),
|
||||||
|
nullable=False)
|
||||||
|
op.alter_column('audit_logs', 'action',
|
||||||
|
existing_type=mysql.TEXT(),
|
||||||
|
nullable=False)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.alter_column('audit_logs', 'action',
|
||||||
|
existing_type=mysql.TEXT(),
|
||||||
|
nullable=True)
|
||||||
|
op.alter_column('audit_logs', 'account_id',
|
||||||
|
existing_type=mysql.INTEGER(display_width=11),
|
||||||
|
nullable=True)
|
||||||
|
# ### end Alembic commands ###
|
35
migrations/versions/bd908969d8fe_add_audit_log_table.py
Normal file
35
migrations/versions/bd908969d8fe_add_audit_log_table.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
"""Add audit_log table
|
||||||
|
|
||||||
|
Revision ID: bd908969d8fe
|
||||||
|
Revises: aee4c6c24811
|
||||||
|
Create Date: 2022-02-11 21:48:03.798474
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import mysql
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'bd908969d8fe'
|
||||||
|
down_revision = 'aee4c6c24811'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('audit_logs',
|
||||||
|
sa.Column('id', mysql.INTEGER(), nullable=False),
|
||||||
|
sa.Column('account_id', sa.Integer(), nullable=True),
|
||||||
|
sa.Column('action', mysql.TEXT(), nullable=True),
|
||||||
|
sa.Column('date', mysql.TIMESTAMP(), server_default=sa.text('now()'), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['account_id'], ['accounts.id'], ondelete='CASCADE'),
|
||||||
|
sa.PrimaryKeyConstraint('id')
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_table('audit_logs')
|
||||||
|
# ### end Alembic commands ###
|
Loading…
Reference in New Issue
Block a user