mirror of
https://git.wownero.com/lza_menace/suchwow.git
synced 2024-08-15 01:03:19 +00:00
add audit logs
This commit is contained in:
parent
143d08f2f7
commit
3094205362
7 changed files with 71 additions and 17 deletions
|
@ -3,7 +3,7 @@ from os import makedirs
|
||||||
import click
|
import click
|
||||||
from flask import Blueprint, url_for, current_app
|
from flask import Blueprint, url_for, current_app
|
||||||
|
|
||||||
from suchwow.models import Post, Profile, Comment, Notification, db, Moderator, Ban
|
from suchwow.models import Post, Profile, Comment, Notification, db, Moderator, Ban, AuditEvent
|
||||||
from suchwow.utils.helpers import get_latest_tipped_posts
|
from suchwow.utils.helpers import get_latest_tipped_posts
|
||||||
from suchwow.utils.helpers import get_top_posters, get_top_posts
|
from suchwow.utils.helpers import get_top_posters, get_top_posts
|
||||||
from suchwow.reddit import make_post
|
from suchwow.reddit import make_post
|
||||||
|
@ -20,7 +20,7 @@ def init():
|
||||||
makedirs(f"{config.DATA_FOLDER}/{i}", exist_ok=True)
|
makedirs(f"{config.DATA_FOLDER}/{i}", exist_ok=True)
|
||||||
|
|
||||||
# init db
|
# init db
|
||||||
db.create_tables([Post, Profile, Comment, Notification, Moderator, Ban])
|
db.create_tables([Post, Profile, Comment, Notification, Moderator, Ban, AuditEvent])
|
||||||
|
|
||||||
|
|
||||||
@bp.cli.command("post_reddit")
|
@bp.cli.command("post_reddit")
|
||||||
|
|
|
@ -143,3 +143,12 @@ class Ban(Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
database = db
|
database = db
|
||||||
|
|
||||||
|
class AuditEvent(Model):
|
||||||
|
id = AutoField()
|
||||||
|
user = ForeignKeyField(Profile)
|
||||||
|
timestamp = DateTimeField(default=datetime.now)
|
||||||
|
action = CharField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
database = db
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
from flask import Blueprint, render_template, redirect, url_for, flash, request
|
from flask import Blueprint, render_template, redirect, url_for, flash, request
|
||||||
|
|
||||||
from suchwow.models import Post, Profile, Moderator, Ban, get_ban_reason
|
from suchwow.models import AuditEvent, Post, Profile, Moderator, Ban, get_ban_reason
|
||||||
from suchwow.utils.decorators import moderator_required
|
from suchwow.utils.decorators import moderator_required
|
||||||
from suchwow.utils.helpers import get_session_user
|
from suchwow.utils.helpers import get_session_user, audit_event
|
||||||
from suchwow import config
|
from suchwow import config
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ def manage_mods():
|
||||||
flash('Cannot delete super admin you son-of-a-bitch.', 'is-danger')
|
flash('Cannot delete super admin you son-of-a-bitch.', 'is-danger')
|
||||||
else:
|
else:
|
||||||
m.delete_instance()
|
m.delete_instance()
|
||||||
|
audit_event(f'Deleted {to_delete} from mods')
|
||||||
flash(f'Removed {to_delete} from mods!', 'is-success')
|
flash(f'Removed {to_delete} from mods!', 'is-success')
|
||||||
return redirect(url_for('mod.manage_mods'))
|
return redirect(url_for('mod.manage_mods'))
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
@ -61,6 +62,7 @@ def manage_mods():
|
||||||
else:
|
else:
|
||||||
m = Moderator(username=to_add)
|
m = Moderator(username=to_add)
|
||||||
m.save()
|
m.save()
|
||||||
|
audit_event(f'Added {to_add} to mods')
|
||||||
flash(f'Added {to_add} to mods!', 'is-success')
|
flash(f'Added {to_add} to mods!', 'is-success')
|
||||||
mods = Profile.select().join(Moderator, on=(Profile.username == Moderator.username))
|
mods = Profile.select().join(Moderator, on=(Profile.username == Moderator.username))
|
||||||
return render_template('mod/manage.html', mods=mods)
|
return render_template('mod/manage.html', mods=mods)
|
||||||
|
@ -80,6 +82,7 @@ def manage_bans():
|
||||||
flash('Cannot ban super admin you son-of-a-bitch.', 'is-danger')
|
flash('Cannot ban super admin you son-of-a-bitch.', 'is-danger')
|
||||||
else:
|
else:
|
||||||
ban.delete_instance()
|
ban.delete_instance()
|
||||||
|
audit_event(f'Removed ban on {to_delete}')
|
||||||
flash(f'Unbanned {to_delete}!', 'is-success')
|
flash(f'Unbanned {to_delete}!', 'is-success')
|
||||||
return redirect(url_for('mod.manage_bans'))
|
return redirect(url_for('mod.manage_bans'))
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
@ -98,9 +101,14 @@ def manage_bans():
|
||||||
reason = get_ban_reason()
|
reason = get_ban_reason()
|
||||||
ban = Ban(user=u, reason=reason)
|
ban = Ban(user=u, reason=reason)
|
||||||
ban.save()
|
ban.save()
|
||||||
|
audit_event(f'Banned {to_add} ({reason})')
|
||||||
flash(f'Banned {to_add}!', 'is-success')
|
flash(f'Banned {to_add}!', 'is-success')
|
||||||
bans = Ban.select()
|
bans = Ban.select()
|
||||||
return render_template('mod/bans.html', bans=bans)
|
return render_template('mod/bans.html', bans=bans)
|
||||||
|
|
||||||
# audit trail of activity
|
|
||||||
# view wallet rpc logs
|
@bp.route('/mods/logs')
|
||||||
|
@moderator_required
|
||||||
|
def view_logs():
|
||||||
|
events = AuditEvent.select().order_by(AuditEvent.timestamp.desc()).limit(50)
|
||||||
|
return render_template('mod/logs.html', logs=events)
|
|
@ -2,6 +2,7 @@ from datetime import datetime, timedelta
|
||||||
from os import path, remove
|
from os import path, remove
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from base64 import b64encode
|
from base64 import b64encode
|
||||||
|
from sys import audit
|
||||||
from qrcode import make as qrcode_make
|
from qrcode import make as qrcode_make
|
||||||
from flask import render_template, Blueprint, request, session, flash
|
from flask import render_template, Blueprint, request, session, flash
|
||||||
from flask import send_from_directory, redirect, url_for, current_app
|
from flask import send_from_directory, redirect, url_for, current_app
|
||||||
|
@ -12,8 +13,7 @@ from suchwow import config
|
||||||
from suchwow.models import Post, Profile, Comment, Ban
|
from suchwow.models import Post, Profile, Comment, Ban
|
||||||
from suchwow.utils.decorators import login_required, profile_required, moderator_required
|
from suchwow.utils.decorators import login_required, profile_required, moderator_required
|
||||||
from suchwow.utils.helpers import allowed_file, is_moderator, get_session_user
|
from suchwow.utils.helpers import allowed_file, is_moderator, get_session_user
|
||||||
from suchwow.utils.helpers import rw_cache, post_webhook
|
from suchwow.utils.helpers import post_webhook, audit_event
|
||||||
from suchwow.reddit import make_post
|
|
||||||
from suchwow.discord import post_discord_webhook
|
from suchwow.discord import post_discord_webhook
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,7 +57,6 @@ def create():
|
||||||
submitter = get_session_user()
|
submitter = get_session_user()
|
||||||
u = Profile.filter(username=submitter)
|
u = Profile.filter(username=submitter)
|
||||||
banned = Ban.filter(user=u).first()
|
banned = Ban.filter(user=u).first()
|
||||||
print(banned)
|
|
||||||
if banned:
|
if banned:
|
||||||
flash(f"You can't post: {banned.reason}", "is-danger")
|
flash(f"You can't post: {banned.reason}", "is-danger")
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
@ -105,7 +104,7 @@ def create():
|
||||||
post.save()
|
post.save()
|
||||||
post.save_thumbnail()
|
post.save_thumbnail()
|
||||||
url = url_for('post.read', id=post.id, _external=True)
|
url = url_for('post.read', id=post.id, _external=True)
|
||||||
post_webhook(f"New post :doge2: [{post.id}]({url}) by `{submitter}` :neckbeard:")
|
audit_event(f'Created new post {post.id}')
|
||||||
flash("New post created and pending approval!", "is-success")
|
flash("New post created and pending approval!", "is-success")
|
||||||
return redirect(url_for("main.index"))
|
return redirect(url_for("main.index"))
|
||||||
return render_template("post/create.html")
|
return render_template("post/create.html")
|
||||||
|
@ -119,11 +118,10 @@ def approve(id):
|
||||||
if not post.approved:
|
if not post.approved:
|
||||||
post.approved = True
|
post.approved = True
|
||||||
post.save()
|
post.save()
|
||||||
post_webhook(f"Post [{post.id}]({url}) approved :white_check_mark: by `{get_session_user()}` :fieri_parrot:")
|
|
||||||
flash("Approved", "is-success")
|
flash("Approved", "is-success")
|
||||||
|
audit_event(f'Approved post {post.id}')
|
||||||
if current_app.config["DEBUG"] is False:
|
if current_app.config["DEBUG"] is False:
|
||||||
post_discord_webhook(post)
|
post_discord_webhook(post)
|
||||||
post_webhook(f"Post [{post.id}]({url}) submitted :dab_parrot: to Discord.")
|
|
||||||
return redirect(url_for("mod.pending_posts"))
|
return redirect(url_for("mod.pending_posts"))
|
||||||
else:
|
else:
|
||||||
flash("You can't approve this", "is-success")
|
flash("You can't approve this", "is-success")
|
||||||
|
@ -141,8 +139,8 @@ def delete(id):
|
||||||
save_path_base = path.join(current_app.config["DATA_FOLDER"], "uploads")
|
save_path_base = path.join(current_app.config["DATA_FOLDER"], "uploads")
|
||||||
save_path = path.join(save_path_base, post.image_name)
|
save_path = path.join(save_path_base, post.image_name)
|
||||||
remove(save_path)
|
remove(save_path)
|
||||||
|
audit_event(f'Deleted post {post.id}')
|
||||||
post.delete_instance()
|
post.delete_instance()
|
||||||
post_webhook(f"Post {post.id} deleted :dumpsterfire: by `{user}` :godmode:")
|
|
||||||
flash("Deleted that shit, brah!", "is-success")
|
flash("Deleted that shit, brah!", "is-success")
|
||||||
if is_mod:
|
if is_mod:
|
||||||
return redirect(url_for("mod.pending_posts"))
|
return redirect(url_for("mod.pending_posts"))
|
||||||
|
|
29
suchwow/templates/mod/logs.html
Normal file
29
suchwow/templates/mod/logs.html
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="container" style="text-align:center;">
|
||||||
|
<h1 class="title">Manage Mods</h1>
|
||||||
|
<nav class="breadcrumb is-centered" aria-label="breadcrumbs">
|
||||||
|
<ul>
|
||||||
|
<li><a href="/">Home</a></li>
|
||||||
|
<li><a href="{{ url_for('mod.main') }}">Mods</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<section class="section">
|
||||||
|
{% for log in logs %}
|
||||||
|
<article class="message" style="width: 40%; margin: 1em auto;">
|
||||||
|
<div class="message-header">
|
||||||
|
<p>{{ log.user.username }} - {{ log.timestamp | humanize }} </p>
|
||||||
|
</div>
|
||||||
|
<div class="message-body">
|
||||||
|
{{ log.action }}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block footer %}{% endblock %}
|
|
@ -52,7 +52,7 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a>
|
<a href="{{ url_for('mod.view_logs') }}">
|
||||||
<span class="icon is-small"></span>
|
<span class="icon is-small"></span>
|
||||||
<span>View Logs</span>
|
<span>View Logs</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import pickle
|
import pickle
|
||||||
from os import path, remove
|
from os import path
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from requests import post as r_post
|
|
||||||
from json import dumps
|
from json import dumps
|
||||||
|
|
||||||
|
from requests import post as r_post
|
||||||
from flask import session, current_app
|
from flask import session, current_app
|
||||||
from suchwow.models import Moderator, Post
|
|
||||||
|
from suchwow.models import Moderator, Post, AuditEvent, Profile
|
||||||
from suchwow.wownero import Wallet, from_atomic
|
from suchwow.wownero import Wallet, from_atomic
|
||||||
from suchwow import config
|
from suchwow import config
|
||||||
|
|
||||||
|
@ -20,6 +22,14 @@ def is_moderator(username):
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_profile():
|
||||||
|
p = Profile.filter(username=get_session_user()).first()
|
||||||
|
return p
|
||||||
|
|
||||||
|
def audit_event(event):
|
||||||
|
e = AuditEvent(user=get_profile(), action=event)
|
||||||
|
e.save()
|
||||||
|
|
||||||
def get_session_user():
|
def get_session_user():
|
||||||
if "auth" not in session or not session["auth"]:
|
if "auth" not in session or not session["auth"]:
|
||||||
return None
|
return None
|
||||||
|
|
Loading…
Reference in a new issue