Compare commits

...

11 Commits

6 changed files with 30 additions and 24 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
.venv/ .venv/
__pycache__/ __pycache__/
config-*.py

View File

@ -1,6 +1,6 @@
# AfpyLogs # AfpyLogs
Web view of IRC logs from #afpy channel on Freenode. Web view of IRC logs from #afpy channel on [Libera](https://libera.chat/).
## Installing ## Installing

36
app.py
View File

@ -3,24 +3,33 @@
import os import os
import re import re
from pathlib import Path
from bleach import Cleaner
from bleach.linkifier import LinkifyFilter
from flask import Flask, g, redirect, render_template, url_for from flask import Flask, g, redirect, render_template, url_for
application = Flask(__name__, template_folder=".") application = Flask(__name__, template_folder=".")
application.config.from_object("config") application.config.from_object("config")
try:
application.config.from_object(f"config-{application.config['ENV']}")
except Exception as e:
print(
"Starting without specific configuration"
f"file config-{application.config['ENV']}.py"
)
application.jinja_env.trim_blocks = application.config["JINJA_ENV"]["TRIM_BLOCKS"] application.jinja_env.trim_blocks = application.config["JINJA_ENV"]["TRIM_BLOCKS"]
application.jinja_env.lstrip_blocks = application.config["JINJA_ENV"]["LSTRIP_BLOCKS"] application.jinja_env.lstrip_blocks = application.config["JINJA_ENV"]["LSTRIP_BLOCKS"]
LOG_PATTERN = re.compile(application.config["LOG_PATTERN"]) LOG_PATTERN = re.compile(application.config["LOG_PATTERN"])
LINK_PATTERN = re.compile(application.config["LINK_PATTERN"])
BOLD_PATTERN = re.compile(application.config["BOLD_PATTERN"]) BOLD_PATTERN = re.compile(application.config["BOLD_PATTERN"])
def get_archives(): def get_archives():
archives = [] archives = []
dates = {"years": [], "months": {}, "days": {}} dates = {"years": [], "months": {}, "days": {}}
for filename in sorted(os.listdir(application.config["LOG_PATH"])): for filename in sorted(Path(application.config["LOG_PATH"]).glob("log-*-*-*.txt")):
date = filename[:-4].split("-")[1:] date = filename.name[:-4].split("-")[1:]
archives.append(date) archives.append(date)
if date[0] not in dates["years"]: if date[0] not in dates["years"]:
dates["years"].append(date[0]) dates["years"].append(date[0])
@ -41,36 +50,35 @@ def archives(year=None, month=None, day=None):
# Récupération des fichiers disponibles # Récupération des fichiers disponibles
archives, g.dates = get_archives() archives, g.dates = get_archives()
# Récupération de la date souhaitée # Récupération de la date souhaitée
if year is None or month is None or day is None: if (
# Si date mal ou non fournie, on prend la dernière existante year is None
or month is None
or day is None
or [year, month, day] not in archives
):
# Si date mal ou non fournie ou inexistante, on prend la dernière
year = archives[-1][0] year = archives[-1][0]
month = archives[-1][1] month = archives[-1][1]
day = archives[-1][2] day = archives[-1][2]
# Et on redirige proprement # Et on redirige proprement
return redirect(url_for("archives", year=year, month=month, day=day)) return redirect(url_for("archives", year=year, month=month, day=day))
# On vérifie que le tuple existe
if [year, month, day] not in archives:
# TODO: Renvoyer une 404 ou mettre un message d'erreur ?
return "404"
# Ok, on charge et on affiche le contenu du fichier # Ok, on charge et on affiche le contenu du fichier
filename = "log-%s-%s-%s.txt" % (year, month, day) filename = "log-%s-%s-%s.txt" % (year, month, day)
filepath = os.path.join(application.config["LOG_PATH"], filename) filepath = os.path.join(application.config["LOG_PATH"], filename)
with open(filepath) as f: with open(filepath, encoding="utf-8") as f:
lines = f.read().splitlines() lines = f.read().splitlines()
g.lines = [] g.lines = []
g.year, g.month, g.day = year, month, day g.year, g.month, g.day = year, month, day
cleaner = Cleaner(tags=["b"], filters=[LinkifyFilter])
for line in lines: for line in lines:
result = LOG_PATTERN.match(line) result = LOG_PATTERN.match(line)
if result is not None: if result is not None:
message = result.group("message") message = result.group("message")
for link in LINK_PATTERN.findall(message):
message = message.replace(
link, application.config["LINK_HTML"].format(link=link)
)
for text in BOLD_PATTERN.findall(message): for text in BOLD_PATTERN.findall(message):
message = message.replace( message = message.replace(
text, application.config["BOLD_HTML"].format(text=text) text, application.config["BOLD_HTML"].format(text=text)
) )
message = cleaner.clean(message)
g.lines.append( g.lines.append(
{ {
"time": result.group("time"), "time": result.group("time"),

View File

@ -13,11 +13,5 @@ LOG_PATH = "/var/www/logs.afpy.org"
DATE_FORMAT = "(\d+-\d+-\d+ )?(?P<time>\d\d:\d\d)" DATE_FORMAT = "(\d+-\d+-\d+ )?(?P<time>\d\d:\d\d)"
LOG_PATTERN = r"^%s\s+[<*]\s*(?P<nick>[^> ]+)[> ]\s+(?P<message>.*)$" % DATE_FORMAT LOG_PATTERN = r"^%s\s+[<*]\s*(?P<nick>[^> ]+)[> ]\s+(?P<message>.*)$" % DATE_FORMAT
# Patterns BOLD_PATTERN = r"\*[^*\s]+\*"
LINK_PATTERN = r"https?://\S+" BOLD_HTML = "<b>{text}</b>"
BOLD_PATTERN = r"\*[^\*\s]+\*"
# html
LINK_HTML = '<a href="{link}">{link}</a>'
BOLD_HTML = "<b>{text}</b>"

View File

@ -1,2 +1,3 @@
flask flask
bleach
gunicorn gunicorn

View File

@ -1,6 +1,8 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Logs du chan #afpy pour le </title> <title>Logs du chan #afpy pour le </title>
<style type="text/css"> <style type="text/css">
body {background-color: #000; color: #fff; font-family: "Verdana"} body {background-color: #000; color: #fff; font-family: "Verdana"}
@ -67,7 +69,7 @@
</div> </div>
<div id="content"> <div id="content">
{% for line in g.lines %} {% for line in g.lines %}
<span class="time">{{ line.time }}</span> <span class="bracket">&lt;</span><span class="nick">{{ line.nick }}</span><span class="bracket">&gt;</span> <span class="message">{{ line.message |safe }}</span><br /> <span class="time">{{ line.time }}</span> <span class="bracket">&lt;</span><span class="nick">{{ line.nick }}</span><span class="bracket">&gt;</span> <span class="message">{{ line.message|safe }}</span><br />
{% endfor %} {% endfor %}
</div> </div>
</body> </body>