Basic rebuild done

This commit is contained in:
Mindiell 2020-12-17 08:49:07 +01:00
parent a77c282081
commit 6b955e945a
7 changed files with 172 additions and 80 deletions

View File

@ -1,20 +1,14 @@
# AfpyLogs
Web view of IRC logs from #python-fr channel on Freenode.
Web view of IRC logs from #afpy channel on Freenode.
## Installing
pip install -e .
## Testing
pip install -e .[test]
pytest
pip install -r requirements.txt
## Running
gunicorn --workers 2 --bind unix:afpylogs.sock -m 007 server
gunicorn --workers 2 --bind 0.0.0.0:8000 app

82
app.py Normal file
View File

@ -0,0 +1,82 @@
# encoding: utf-8
import os
import re
from flask import Flask, g, redirect, render_template, url_for
application = Flask(__name__, template_folder=".")
application.config.from_object("config")
application.jinja_env.trim_blocks = application.config["JINJA_ENV"]["TRIM_BLOCKS"]
application.jinja_env.lstrip_blocks = application.config["JINJA_ENV"]["LSTRIP_BLOCKS"]
LOG_PATTERN = re.compile(application.config["LOG_PATTERN"])
LINK_PATTERN = re.compile(application.config["LINK_PATTERN"])
BOLD_PATTERN = re.compile(application.config["BOLD_PATTERN"])
def get_archives():
archives = []
dates = {"years": [], "months": {}, "days": {}}
for filename in sorted(os.listdir(application.config["LOG_PATH"])):
date = filename[:-4].split("-")[1:]
archives.append(date)
if date[0] not in dates["years"]:
dates["years"].append(date[0])
dates["months"][date[0]] = []
if date[1] not in dates["months"][date[0]]:
dates["months"][date[0]].append(date[1])
dates["days"]["%s%s" % tuple(date[:2])] = []
if date[2] not in dates["days"]["%s%s" % tuple(date[:2])]:
dates["days"]["%s%s" % tuple(date[:2])].append(date[2])
return archives, dates
@application.route("/")
@application.route("/archives/<year>")
@application.route("/archives/<year>/<month>")
@application.route("/archives/<year>/<month>/<day>")
def archives(year=None, month=None, day=None):
# Récupération des fichiers disponibles
archives, g.dates = get_archives()
# Récupération de la date souhaitée
if year is None or month is None or day is None:
# Si date mal ou non fournie, on prend la dernière existante
year = archives[-1][0]
month = archives[-1][1]
day = archives[-1][2]
# Et on redirige proprement
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
filename = "log-%s-%s-%s.txt" % (year, month, day)
filepath = os.path.join(application.config["LOG_PATH"], filename)
with open(filepath) as f:
lines = f.read().splitlines()
g.lines = []
g.year, g.month, g.day = year, month, day
for line in lines:
result = LOG_PATTERN.match(line)
if result is not None:
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):
message = message.replace(
text, application.config["BOLD_HTML"].format(text=text)
)
g.lines.append(
{
"time": result.group("time"),
"nick": result.group("nick"),
"message": message,
}
)
return render_template("template.html")

View File

@ -7,6 +7,17 @@ JINJA_ENV = {
"LSTRIP_BLOCKS": True,
}
PATH = "../logs.afpy.org"
CHANNEL = "#afpy"
LOG_PATH = "../logs.afpy.org"
# IRSSI log pattern
DATE_FORMAT = "(\d+-\d+-\d+ )?(?P<time>\d\d:\d\d)"
LOG_PATTERN = r"^%s\s+[<*]\s*(?P<nick>[^> ]+)[> ]\s+(?P<message>.*)$" % DATE_FORMAT
# Patterns
LINK_PATTERN = r"https?://\S+"
BOLD_PATTERN = r"\*[^\*\s]+\*"
# html
LINK_HTML = '<a href="{link}">{link}</a>'
BOLD_HTML = "<b>{text}</b>"

View File

@ -1,17 +0,0 @@
# encoding: utf-8
from flask import Flask
app = Flask(__name__)
app.config.from_object("config")
app.jinja_env.trim_blocks = app.config["JINJA_ENV"]["TRIM_BLOCKS"]
app.jinja_env.lstrip_blocks = app.config["JINJA_ENV"]["LSTRIP_BLOCKS"]
@app.route("/")
def hello_world():
return "Hello, World!"
# WSGI needs an "application" variable
application = app

View File

@ -1,43 +0,0 @@
[metadata]
name = AfpyLogs
url = https://github.com/AFPy/AfpyLogs
version = file: afpylogs/VERSION
description = Web view of IRC logs from #python-fr channel on Freenode
long_description = file: README.md
long_description_content_type = text/markdown
license = GNU AFFERO GENERAL PUBLIC LICENSE version 3 or later
license_file = LICENSE
author = Mindiell
classifiers =
Development Status :: 3 - Alpha
Environment :: Web Environment
License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
Operating System :: OS Independent
Programming Language :: Python :: 3
Programming Language :: Python :: 3.8
project_urls =
Documentation = https://github.com/AFPy/AfpyLogs/blob/master/README.md
[options]
packages = find:
setup_requires = pytest_runner
python_requires = >= 3.8
install_requires =
flask
gunicorn
[options.extras_require]
test =
pytest-black
pytest-isort
pytest
[bdist_wheel]
python-tag = py3
[tool:pytest]
addopts = --isort --black
[isort]
default_section = THIRDPARTY
multi_line_output = 3

View File

@ -1,9 +0,0 @@
# encoding: utf-8
"""
Setup for AfpyLogs
"""
from setuptools import setup
setup()

74
template.html Normal file
View File

@ -0,0 +1,74 @@
<!DOCTYPE html>
<html>
<head>
<title>Logs du chan #afpy pour le </title>
<style type="text/css">
body {background-color: #000; color: #fff; font-family: "Verdana"}
.time {color: #ffd738; font-size: .9em; font-weight: bold}
.bracket {color: #ccc; font-size: .8em}
.nick {color: #dAa642}
.message {color: #eaeaea}
.action {color: #a4c}
.click {cursor: pointer}
.off {display: none}
.on {display: block}
#content a {color: #ffd738; font-size: .9em; font-weight: bold; text-decoration: none}
#content a:hover {text-decoration: underline}
.calendar {color: #ffd738}
.day {font-weight: bold}
#calendar {padding-bottom: .6em; margin-bottom: .6em; border-bottom: 1px dashed #ffd738}
#calendar a {color: #ffd738; text-decoration: none}
#calendar a:hover {text-decoration: underline}
</style>
<script type="text/javascript">
function hide(id) {
var els = document.getElementsByClassName("on");
[].forEach.call(els, function (el){
console.log(el.id);
console.log(id);
console.log(id.substr(0, el.id.length));
console.log(id.substr(0, el.id.length) != el.id);
if (el.id != id.substr(0, el.id.length)) {
el.className = "off";
}
});
}
function display(id) {
hide(id.toString());
var el = document.getElementById(id);
if (el!=null) {
el.className = "on";
}
}
</script>
</head>
<body>
<div id="calendar">
<nav>
{% for year in g.dates.years %}
<span onclick="display('{{ year }}')" class="calendar click {%if year==g.year%}day{%endif%}">{{ year }}</span>
{% endfor %}
</nav>
{% for year in g.dates.years %}
<nav id="{{year}}" class="{%if year==g.year%}on{%else%}off{%endif%}">
{% for month in g.dates.months[year] %}
<span onclick="display('{{ year }}{{ month }}')" class="calendar click {%if year==g.year and month==g.month%}day{%endif%}">{{ month }}</span>
{% endfor %}
{% for month in g.dates.months[year] %}
<nav id="{{year}}{{month}}" class="{%if year==g.year and month==g.month%}on{%else%}off{%endif%}">
{% for day in g.dates.days[year+month] %}
<a href="{{url_for('archives', year=year, month=month, day=day)}}" class="calendar {%if year==g.year and month==g.month and day==g.day%}day{%endif%}">{{ day }}</a>
{% endfor %}
</nav>
{% endfor %}
</nav>
{% endfor %}
</div>
<div id="content">
{% 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 />
{% endfor %}
</div>
</body>
</html>