aboutsummaryrefslogtreecommitdiff
path: root/app/blueprints
diff options
context:
space:
mode:
authorrubenwardy <rw@rubenwardy.com>2020-07-11 02:32:17 +0100
committerrubenwardy <rw@rubenwardy.com>2020-07-11 02:32:17 +0100
commita4dd4f04293b6ad6dab5d3dc0a4c52a3290b4394 (patch)
tree8e56f86e0318bd41266ad4cf9178269fe6da4dbb /app/blueprints
parentbf927c50f00bd15c7bc1765b7d5fb0c6a6abeb86 (diff)
downloadcheatdb-a4dd4f04293b6ad6dab5d3dc0a4c52a3290b4394.tar.xz
Add audit log
Diffstat (limited to 'app/blueprints')
-rw-r--r--app/blueprints/admin/__init__.py2
-rw-r--r--app/blueprints/admin/audit.py30
-rw-r--r--app/blueprints/packages/packages.py30
-rw-r--r--app/blueprints/threads/__init__.py24
-rw-r--r--app/blueprints/users/profile.py17
5 files changed, 82 insertions, 21 deletions
diff --git a/app/blueprints/admin/__init__.py b/app/blueprints/admin/__init__.py
index 66eb1ea..03cfc8a 100644
--- a/app/blueprints/admin/__init__.py
+++ b/app/blueprints/admin/__init__.py
@@ -19,4 +19,4 @@ from flask import Blueprint
bp = Blueprint("admin", __name__)
-from . import admin, licenseseditor, tagseditor, versioneditor
+from . import admin, licenseseditor, tagseditor, versioneditor, audit
diff --git a/app/blueprints/admin/audit.py b/app/blueprints/admin/audit.py
new file mode 100644
index 0000000..64dc3a7
--- /dev/null
+++ b/app/blueprints/admin/audit.py
@@ -0,0 +1,30 @@
+# ContentDB
+# Copyright (C) 2020 rubenwardy
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+from flask import Blueprint, render_template, redirect, url_for
+from flask_user import current_user, login_required
+from app.models import db, AuditLogEntry, UserRank
+from app.utils import rank_required
+
+from . import bp
+
+@bp.route("/admin/audit/")
+@login_required
+@rank_required(UserRank.MODERATOR)
+def audit():
+ log = AuditLogEntry.query.order_by(db.desc(AuditLogEntry.created_at)).all()
+ return render_template("admin/audit.html", log=log)
diff --git a/app/blueprints/packages/packages.py b/app/blueprints/packages/packages.py
index 3f26444..4743a57 100644
--- a/app/blueprints/packages/packages.py
+++ b/app/blueprints/packages/packages.py
@@ -265,8 +265,13 @@ def create_edit(author=None, name=None):
return redirect(url_for("packages.create_edit", author=author, name=name))
else:
+ msg = "Edited {}".format(package.title)
+
addNotification(package.maintainers, current_user,
- "Edited {}".format(package.title), package.getDetailsURL(), package)
+ msg, package.getDetailsURL(), package)
+
+ severity = AuditSeverity.NORMAL if current_user in package.maintainers else AuditSeverity.EDITOR
+ addAuditLog(severity, current_user, msg, package.getDetailsURL(), package)
form.populate_obj(package) # copy to row
@@ -337,8 +342,10 @@ def approve(package):
for s in screenshots:
s.approved = True
- addNotification(package.maintainers, current_user,
- "Approved {}".format(package.title), package.getDetailsURL(), package)
+ msg = "Approved {}".format(package.title)
+ addNotification(package.maintainers, current_user, msg, package.getDetailsURL(), package)
+ severity = AuditSeverity.NORMAL if current_user == package.author else AuditSeverity.EDITOR
+ addAuditLog(severity, current_user, msg, package.getDetailsURL(), package)
db.session.commit()
return redirect(package.getDetailsURL())
@@ -359,8 +366,9 @@ def remove(package):
package.soft_deleted = True
url = url_for("users.profile", username=package.author.username)
- addNotification(package.maintainers, current_user,
- "Deleted {}".format(package.title), url, package)
+ msg = "Deleted {}".format(package.title)
+ addNotification(package.maintainers, current_user, msg, url, package)
+ addAuditLog(AuditSeverity.EDITOR, current_user, msg, url)
db.session.commit()
flash("Deleted package", "success")
@@ -373,8 +381,10 @@ def remove(package):
package.approved = False
- addNotification(package.maintainers, current_user,
- "Unapproved {}".format(package.title), package.getDetailsURL(), package)
+ msg = "Unapproved {}".format(package.title)
+ addNotification(package.maintainers, current_user, msg, package.getDetailsURL(), package)
+ addAuditLog(AuditSeverity.EDITOR, current_user, msg, package.getDetailsURL(), package)
+
db.session.commit()
flash("Unapproved package", "success")
@@ -420,8 +430,10 @@ def edit_maintainers(package):
package.maintainers.extend(users)
package.maintainers.append(package.author)
- addNotification(package.author, current_user,
- "Edited {} maintainers".format(package.title), package.getDetailsURL(), package)
+ msg = "Edited {} maintainers".format(package.title)
+ addNotification(package.author, current_user, msg, package.getDetailsURL(), package)
+ severity = AuditSeverity.NORMAL if current_user == package.author else AuditSeverity.MODERATION
+ addAuditLog(severity, current_user, msg, package.getDetailsURL(), package)
db.session.commit()
diff --git a/app/blueprints/threads/__init__.py b/app/blueprints/threads/__init__.py
index e54c7c8..e3043c0 100644
--- a/app/blueprints/threads/__init__.py
+++ b/app/blueprints/threads/__init__.py
@@ -21,7 +21,7 @@ bp = Blueprint("threads", __name__)
from flask_user import *
from app.models import *
-from app.utils import addNotification, clearNotifications, isYes
+from app.utils import addNotification, clearNotifications, isYes, addAuditLog
import datetime
@@ -91,13 +91,19 @@ def set_lock(id):
if thread.locked is None:
abort(400)
- db.session.commit()
-
+ msg = None
if thread.locked:
+ msg = "Locked thread '{}'".format(thread.title)
flash("Locked thread", "success")
else:
+ msg = "Unlocked thread '{}'".format(thread.title)
flash("Unlocked thread", "success")
+ addNotification(thread.watchers, current_user, msg, thread.getViewURL(), thread.package)
+ addAuditLog(AuditSeverity.MODERATION, current_user, msg, thread.getViewURL(), thread.package)
+
+ db.session.commit()
+
return redirect(thread.getViewURL())
@@ -129,10 +135,10 @@ def view(id):
thread.watchers.append(current_user)
msg = "New comment on '{}'".format(thread.title)
- addNotification(thread.watchers, current_user, msg, url_for("threads.view", id=thread.id), thread.package)
+ addNotification(thread.watchers, current_user, msg, thread.getViewURL(), thread.package)
db.session.commit()
- return redirect(url_for("threads.view", id=id))
+ return redirect(thread.getViewURL())
else:
flash("Comment needs to be between 3 and 500 characters.")
@@ -175,7 +181,7 @@ def new():
# Only allow creating one thread when not approved
elif is_review_thread and package.review_thread is not None:
flash("A review thread already exists!", "danger")
- return redirect(url_for("threads.view", id=package.review_thread.id))
+ return redirect(package.review_thread.getViewURL())
elif not current_user.canOpenThreadRL():
flash("Please wait before opening another thread", "danger")
@@ -218,14 +224,14 @@ def new():
notif_msg = "New thread '{}'".format(thread.title)
if package is not None:
- addNotification(package.maintainers, current_user, notif_msg, url_for("threads.view", id=thread.id), package)
+ addNotification(package.maintainers, current_user, notif_msg, thread.getViewURL(), package)
editors = User.query.filter(User.rank >= UserRank.EDITOR).all()
- addNotification(editors, current_user, notif_msg, url_for("threads.view", id=thread.id), package)
+ addNotification(editors, current_user, notif_msg, thread.getViewURL(), package)
db.session.commit()
- return redirect(url_for("threads.view", id=thread.id))
+ return redirect(thread.getViewURL())
return render_template("threads/new.html", form=form, allow_private_change=allow_change, package=package)
diff --git a/app/blueprints/users/profile.py b/app/blueprints/users/profile.py
index 47543dc..d33bc50 100644
--- a/app/blueprints/users/profile.py
+++ b/app/blueprints/users/profile.py
@@ -24,7 +24,7 @@ from app.models import *
from flask_wtf import FlaskForm
from wtforms import *
from wtforms.validators import *
-from app.utils import randomString, loginUser, rank_required, nonEmptyOrNone
+from app.utils import randomString, loginUser, rank_required, nonEmptyOrNone, addAuditLog
from app.tasks.forumtasks import checkForumAccount
from app.tasks.emails import sendVerifyEmail, sendEmailRaw
from app.tasks.phpbbparser import getProfile
@@ -62,6 +62,10 @@ def profile(username):
# Process valid POST
if request.method=="POST" and form.validate():
+ severity = AuditSeverity.NORMAL if current_user == user else AuditSeverity.MODERATION
+ addAuditLog(severity, current_user, "Edited {}'s profile".format(user.display_name),
+ url_for("users.profile", username=username))
+
# Copy form fields to user_profile fields
if user.checkPerm(current_user, Permission.CHANGE_USERNAMES):
user.display_name = form.display_name.data
@@ -75,7 +79,10 @@ def profile(username):
if user.checkPerm(current_user, Permission.CHANGE_RANK):
newRank = form["rank"].data
if current_user.rank.atLeast(newRank):
- user.rank = form["rank"].data
+ if newRank != user.rank:
+ user.rank = form["rank"].data
+ msg = "Set rank of {} to {}".format(user.display_name, user.rank.getTitle())
+ addAuditLog(AuditSeverity.MODERATION, current_user, msg, url_for("users.profile", username=username))
else:
flash("Can't promote a user to a rank higher than yourself!", "danger")
@@ -84,6 +91,9 @@ def profile(username):
if newEmail != user.email and newEmail.strip() != "":
token = randomString(32)
+ msg = "Changed email of {}".format(user.display_name)
+ addAuditLog(severity, current_user, msg, url_for("users.profile", username=username))
+
ver = UserEmailVerification()
ver.user = user
ver.token = token
@@ -158,6 +168,9 @@ def send_email(username):
form = SendEmailForm(request.form)
if form.validate_on_submit():
+ addAuditLog(AuditSeverity.MODERATION, current_user,
+ "Sent email to {}".format(user.display_name), url_for("users.profile", username=username))
+
text = form.text.data
html = render_markdown(text)
task = sendEmailRaw.delay([user.email], form.subject.data, text, html)