logging: add some logging for v5 events #136

Merged
Darks merged 1 commits from logging into dev 2023-06-20 19:11:51 +02:00
16 changed files with 73 additions and 9 deletions

3
.gitignore vendored
View File

@ -22,6 +22,9 @@ test.*
# Autosaves
*.dia~
## Logging files
*.log
## Deployment files

View File

@ -9,6 +9,7 @@ from config import FlaskApplicationSettings, V5Config
app = Flask(__name__)
app.config.from_object(FlaskApplicationSettings)
app.v5logger = V5Config.v5logger()
# Check security of secret
if FlaskApplicationSettings.SECRET_KEY == "a-random-secret-key":

View File

@ -397,7 +397,7 @@ class Member(User):
Notify a user with a message.
An hyperlink can be added to redirect to the notification source
"""
return
# return
Darks marked this conversation as resolved
Review

Pourquoi est-ce que c'était soft-commenté et peut-on cleanup ?

Pourquoi est-ce que c'était soft-commenté et peut-on cleanup ?
Review

Parce que j'ai pas du tout testé cette partie. On s'est rendus compte avec Eragon que les notifs ne fonctionnaient pas probablement pour ça, mais je suis pas allé vérifier plus loin.

Je vais checker ce soir, si c'est ok je clean

Parce que j'ai pas du tout testé cette partie. On s'est rendus compte avec Eragon que les notifs ne fonctionnaient pas probablement pour ça, mais je suis pas allé vérifier plus loin. Je vais checker ce soir, si c'est ok je clean
n = Notification(self.id, message, href=href)
db.session.add(n)
db.session.commit()

View File

@ -45,6 +45,7 @@ def edit_account():
db.session.commit()
current_user.update_trophies("on-profile-update")
flash('Modifications effectuées', 'ok')
app.v5logger.info(f"<{current_user.name}> has edited their account")
return redirect(request.url)
else:
flash('Erreur lors de la modification', 'error')
@ -62,6 +63,7 @@ def ask_reset_password():
m = Member.query.filter_by(email=form.email.data).first()
if m is not None:
send_reset_password_mail(m.name, m.email)
app.v5logger.info(f"<{m.name}> has asked a password reset token")
flash('Un email a été envoyé à l\'adresse renseignée', 'ok')
return redirect(url_for('login'))
elif request.method == "POST":
@ -87,6 +89,7 @@ def reset_password(token):
db.session.merge(m)
db.session.commit()
flash('Modifications effectuées', 'ok')
app.v5logger.info(f"<{m.name}> has reset their password")
return redirect(url_for('login'))
else:
flash('Erreur lors de la modification', 'error')
@ -102,6 +105,7 @@ def delete_account():
if del_form.submit.data:
if del_form.validate_on_submit():
name = current_user.name
if del_form.transfer.data:
guest = Guest(current_user.generate_guest_name())
db.session.add(guest)
@ -116,6 +120,7 @@ def delete_account():
logout_user()
db.session.commit()
flash('Compte supprimé', 'ok')
app.v5logger.info(f"<{name}> has deleted their account ({'with' if del_form.transfer.data else 'without'} guest transfer)")
return redirect(url_for('index'))
else:
flash('Erreur lors de la suppression du compte', 'error')
@ -141,6 +146,7 @@ def register():
# Email validation message
send_validation_mail(member.name, member.email)
app.v5logger.info(f"<{member.name}> registered")
return redirect(url_for('validation') + "?email=" + form.email.data)
return render('account/register.html', title='Register',
@ -178,4 +184,5 @@ def activate_account(token):
db.session.commit()
flash("L'email a bien été confirmé", "ok")
app.v5logger.info(f"<{m.name}> has activated their account")
return redirect(url_for('login'))

View File

@ -49,6 +49,7 @@ def login():
login_user(member, remember=form.remember_me.data,
duration=datetime.timedelta(days=7))
member.update_trophies("on-login")
app.v5logger.info(f"<{member.name}> has logged in")
# Redirect safely (https://huit.re/open-redirect)
def is_safe_url(target):
@ -71,8 +72,10 @@ def login():
@login_required
@check_csrf
def logout():
name = current_user.name
logout_user()
flash('Déconnexion réussie', 'info')
app.v5logger.info(f"<{name}> has logged out")
if request.referrer:
return redirect(request.referrer)
return redirect(url_for('index'))

View File

@ -28,5 +28,6 @@ def account_polls():
db.session.commit()
flash(f"Le sondage {p.id} a été créé", "info")
app.v5logger.info(f"<{current_user.name}> has created the form #{p.id}")
return render("account/polls.html", polls=polls, form=form)

View File

@ -68,6 +68,7 @@ def adm_edit_account(user_id):
# TODO: send an email to member saying his account has been modified
user.notify(f"Vos informations personnelles ont été modifiées par {current_user.name}.")
flash('Modifications effectuées', 'ok')
app.v5logger.info(f"[admin] <{current_user.name}> has edited <{user.name}>'s data")
return redirect(request.url)
else:
flash('Erreur lors de la modification', 'error')
@ -85,6 +86,7 @@ def adm_edit_account(user_id):
db.session.merge(user)
db.session.commit()
flash('Modifications effectuées', 'ok')
app.v5logger.info(f"[admin] <{current_user.name}> has edited <{user.name}>'s trophies")
return redirect(request.url)
else:
flash("Erreur lors de la modification des trophées", 'error')
@ -102,6 +104,7 @@ def adm_edit_account(user_id):
db.session.merge(user)
db.session.commit()
flash('Modifications effectuées', 'ok')
app.v5logger.info(f"[admin] <{current_user.name}> has edited <{user.name}>'s groups")
return redirect(request.url)
else:
flash("Erreur lors de la modification des groupes", 'error')
@ -151,6 +154,7 @@ def adm_delete_account(user_id):
user.delete()
db.session.commit()
flash('Compte supprimé', 'ok')
app.v5logger.info(f"[admin] <{current_user.name}> has deleted <{user.name}> account")
return redirect(url_for('adm'))
else:
flash('Erreur lors de la suppression du compte', 'error')

View File

@ -42,6 +42,7 @@ def adm_login_as():
# Create a safe token to flee when needed
s = Serializer(app.config["SECRET_KEY"])
vandal_token = s.dumps(current_user.id)
vandal_name = current_user.name
# Login and display some messages
login_user(user)
@ -51,9 +52,11 @@ def adm_login_as():
else:
flash(f"Connecté en tant que {user.name}")
app.v5logger.info(f"[admin] <{vandal_name}> has logged in as <{user.name}>")
# Return the response
resp = make_response(redirect(url_for('index')))
resp.set_cookie('vandale', vandal_token)
resp.set_cookie('vandale', vandal_token, path='/')
return resp
# Else return form
@ -75,14 +78,17 @@ def adm_logout_as():
flash("Vous avez vraiment agi de manière stupide.", "error")
abort(403)
victim_name = current_user.name
user = Member.query.get(id)
logout_user()
login_user(user)
app.v5logger.info(f"[admin] <{user.name}> has logged out from <{victim_name}>'s account")
if request.referrer:
resp = make_response(redirect(request.referrer))
else:
resp = make_response(redirect(url_for('index')))
resp.set_cookie('vandale', '', expires=0)
resp.set_cookie('vandale', '', expires=0, path='/')
return resp

View File

@ -73,6 +73,7 @@ def forum_page(f, page=1):
current_user.update_trophies('new-post')
flash('Le sujet a bien été créé', 'ok')
app.v5logger.info(f"<{t.author.name}> has created the topic #{t.id}")
return redirect(url_for('forum_topic', f=f, page=(t,1)))
# Paginate topic pages

View File

@ -54,6 +54,7 @@ def forum_topic(f, page):
current_user.update_trophies('new-post')
flash('Message envoyé', 'ok')
app.v5logger.info(f"<{c.author.name}> has posted a the comment #{c.id}")
# Redirect to empty the form
return redirect(url_for('forum_topic', f=f, page=(t, "fin"),
_anchor=str(c.id)))

View File

@ -34,7 +34,8 @@ def poll_vote(poll_id):
db.session.add(answer)
db.session.commit()
flash('Le vote a été pris en compte', 'info')
flash('Le vote a été pris en compte', 'ok')
app.v5logger.info(f"<{current_user.name}> has voted on the poll #{poll.id}")
if request.referrer:
return redirect(request.referrer)

View File

@ -84,6 +84,10 @@ def edit_post(postid):
for a, file in attachments:
a.set_file(file)
flash('Modifications enregistrées', 'ok')
admin_msg = "[admin] " if current_user != p.author else ""
app.v5logger.info(f"{admin_msg}<{current_user.name}> has edited the post #{p.id}")
# Determine topic URL now, in case forum was changed
if isinstance(p, Topic):
return redirect(url_for('forum_topic', f=p.forum, page=(p,1)))
@ -111,6 +115,10 @@ def delete_post(postid):
if not current_user.can_delete_post(p):
abort(403)
# Is a penalty deletion
is_penalty = request.args.get('penalty') == 'True' \
and current_user.priv('delete.posts')
# Users who need to have their trophies updated
authors = set()
@ -126,16 +134,21 @@ def delete_post(postid):
authors.add(comment.author)
if isinstance(p.author, Member):
factor = 3 if request.args.get('penalty') == 'True' else 1
factor = 3 if is_penalty else 1
p.author.add_xp(xp * factor)
db.session.merge(p.author)
authors.add(p.author)
admin_msg = "[admin] " if current_user != p.author else ""
p.delete()
db.session.commit()
for author in authors:
author.update_trophies("new-post")
flash("Le contenu a été supprimé", 'ok')
penalty_msg = " (with penalty)" if is_penalty else ""
app.v5logger.info(f"{admin_msg}<{current_user.name}> has deleted the post #{p.id}{penalty_msg}")
return redirect(next_page)
@ -149,6 +162,9 @@ def set_post_topcomment(postid):
comment.thread.top_comment = comment
db.session.add(comment.thread)
db.session.commit()
flash("Le post a été défini comme nouvel en-tête", 'ok')
admin_msg = "[admin] " if current_user != comment.author else ""
app.v5logger.info(f"{admin_msg}<{current_user.name}> has set a new top comment on thread #{comment.thread.id}")
return redirect(request.referrer)
@ -191,8 +207,11 @@ def move_post(postid):
comment.thread = thread
db.session.add(comment)
db.session.commit()
flash("Le topic a été déplacé", 'ok')
admin_msg = "[admin] " if current_user != comment.author else ""
app.v5logger.info(f"{admin_msg}<{current_user.name}> has moved the comment #{comment.id} to thread #{thread.id}")
return redirect(url_for('forum_topic', f=t.forum, page=(t,1)))
return render('post/move_post.html', comment=comment,
search_form=search_form, move_form=move_form)
@ -212,8 +231,10 @@ def lock_thread(postid):
db.session.commit()
if post.thread.locked:
flash(f"Le thread a été verrouillé")
flash(f"Le thread a été verrouillé", 'ok')
app.v5logger.info(f"[admin] <{current_user.name}> has locked the thread #{post.thread.id}")
else:
flash(f"Le thread a été déverrouillé")
flash(f"Le thread a été déverrouillé", 'ok')
app.v5logger.info(f"[admin] <{current_user.name}> has unlocked the thread #{post.thread.id}")
return redirect(request.referrer)

View File

@ -41,6 +41,7 @@ def program_view(page):
current_user.update_trophies('new-post')
flash('Message envoyé', 'ok')
app.v5logger.info(f"<{c.author.name}> has posted a the comment #{c.id}")
# Redirect to empty the form
return redirect(url_for('program_view', page=(p, "fin"), _anchor=str(c.id)))

View File

@ -54,6 +54,7 @@ def program_submit():
current_user.update_trophies('new-program')
flash('Le programme a bien été soumis', 'ok')
app.v5logger.info(f"<{p.author.name}> has submitted the program #{c.id}")
return redirect(url_for('program_index'))
return render('/programs/submit.html', form=form)

View File

@ -2,7 +2,7 @@
{% import "widgets/editor.html" as widget_editor %}
{% import "widgets/tag_selector.html" as widget_tag_selector with context %}
{% set tabtitle = f"Programmes - Soumettre un programme" %}
{% set tabtitle = "Programmes - Soumettre un programme" %}
{% block title %}
<a href="{{ url_for('program_index') }}">Programmes</a> » <h1>Soumettre un programme</h1>

View File

@ -1,4 +1,5 @@
import os
import logging
from datetime import timedelta
try:
@ -86,6 +87,18 @@ class DefaultConfig(object):
# Tab title prefix. Useful to dissociate local/dev/prod tabs
TABTITLE_PREFIX = ""
@staticmethod
def v5logger():
""" A fully configured logger for v5 activity logs """
logger = logging.getLogger('v5')
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('[%(asctime)s] %(levelname)s: %(message)s')
handler = logging.FileHandler('v5_activity.log')
handler.setLevel(logging.DEBUG)
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
class V5Config(LocalConfig, DefaultConfig):
"""