Compare commits
32 Commits
50e7693e9a
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 5fa1ecf46e | |||
|
|
3dab312a74 | ||
|
|
364c6391c9 | ||
|
|
439e637a86 | ||
|
|
d9808cc66e | ||
|
|
f139fa4bc4 | ||
|
|
1af0e1f834 | ||
|
|
b0a88b1916 | ||
|
|
cf95503954 | ||
|
|
6cdf83b6d0 | ||
|
|
21a747e097 | ||
|
|
05faf28c26 | ||
|
|
154ab9089d | ||
|
|
429e2d221e | ||
|
|
f3d697699d | ||
|
|
02645b7ef7 | ||
|
|
9112763234 | ||
|
|
7a2fdec8d4 | ||
|
|
674edf2bf2 | ||
|
|
e76d9815c9 | ||
|
|
204269b849 | ||
|
|
c969dc0e2d | ||
|
|
b183059f85 | ||
|
|
b1e05e8e4d | ||
|
|
10bea4b46b | ||
|
|
0ede5055e2 | ||
|
|
d17c6f6142 | ||
|
|
fe7b0a9e41 | ||
|
|
3b659ab076 | ||
|
|
1819826151 | ||
|
|
614c16750d | ||
|
|
a7a52e7d4c |
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -1,2 +0,0 @@
|
||||
{
|
||||
}
|
||||
@@ -23,7 +23,8 @@ app:
|
||||
name: THSF
|
||||
real_url: https://www.thsf.net
|
||||
pretalx:
|
||||
url: https://23.thsf.net
|
||||
url: https://thsf.tetaneutral.net
|
||||
ssl_verify: False
|
||||
apiprefix: api
|
||||
apikey: bb770a53b15467dfb67c03d178004aca9e4819d6
|
||||
event: thsf-2023
|
||||
|
||||
13
maintenance/reboot.py
Executable file
13
maintenance/reboot.py
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/python3
|
||||
import docker
|
||||
|
||||
client = docker.from_env()
|
||||
for container in client.containers.list():
|
||||
if container.name == "thsf":
|
||||
print("Content-type: text/html\n\n")
|
||||
print("[+] Rebooting container<br>")
|
||||
print(" '-> Stopping container<br>")
|
||||
container.stop()
|
||||
print(" '-> Starting container<br>")
|
||||
container.start()
|
||||
print("[+] Container restarted<br>")
|
||||
2
maintenance/scripts/jquery-3.7.0.min.js
vendored
Normal file
2
maintenance/scripts/jquery-3.7.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
maintenance/scripts/maintenance.js
Normal file
7
maintenance/scripts/maintenance.js
Normal file
@@ -0,0 +1,7 @@
|
||||
$("#reboot").on("click", function(){
|
||||
$.get("https://www.thsf.net/thsf.net/maintenance/reboot.py", function(data, status){
|
||||
console.log(status);
|
||||
$("#logs").html = data;
|
||||
setTimeout(function () {document.location.reload()}, 5000);
|
||||
});
|
||||
});
|
||||
19
maintenance/status.py
Executable file
19
maintenance/status.py
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/python3
|
||||
import docker
|
||||
import jinja2
|
||||
|
||||
base_path = "/var/www/www.thsf.net/thsf.net/maintenance/templates"
|
||||
status_template = "status.html"
|
||||
|
||||
env = jinja2.Environment(loader=jinja2.FileSystemLoader(base_path),
|
||||
autoescape=True)
|
||||
template = env.get_template(status_template)
|
||||
|
||||
client = docker.from_env()
|
||||
for container in client.containers.list():
|
||||
if container.name == "thsf":
|
||||
cont = dict()
|
||||
cont["name"] = container.name
|
||||
cont["status"] = container.status
|
||||
cont["logs"] = container.logs().decode('utf-8').replace('\n', '<br>')
|
||||
print(template.render(containers=[cont]))
|
||||
66
maintenance/style/maintenance.css
Normal file
66
maintenance/style/maintenance.css
Normal file
@@ -0,0 +1,66 @@
|
||||
body {
|
||||
font-size: 1.2em;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
.page_wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
.center_wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
.container_list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
width: 48em;
|
||||
}
|
||||
.title {
|
||||
font-size: 3em;
|
||||
font-weight: bold;
|
||||
margin: 0.5em;
|
||||
}
|
||||
.table_headers, .line {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.header, .status {
|
||||
font-weight: bold;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
width: 16em;
|
||||
padding: 0.2em;
|
||||
}
|
||||
.table_content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
.status {
|
||||
font-weight: normal;
|
||||
}
|
||||
.container_log {
|
||||
text-align: left;
|
||||
width: 49em;
|
||||
padding: 0.2em;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
}
|
||||
.button {
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
46
maintenance/templates/status.html
Normal file
46
maintenance/templates/status.html
Normal file
@@ -0,0 +1,46 @@
|
||||
Content-type: text/html
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang='zxx'>
|
||||
<head>
|
||||
<title>THSF 2023: Status page</title>
|
||||
<meta name="viewport" content="initial-scale=1.0">
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet"
|
||||
href="/thsf.net/maintenance/style/maintenance.css">
|
||||
<link rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<script src="/thsf.net/maintenance/scripts/jquery-3.7.0.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page_wrapper">
|
||||
<div class="center_wrapper">
|
||||
<div class="container_list">
|
||||
<div class="line">
|
||||
<span class="title">THSF Status</span>
|
||||
</div>
|
||||
<div class="table_headers">
|
||||
<div class="header">Name</div>
|
||||
<div class="header">Status</div>
|
||||
<div class="header">Action</div>
|
||||
</div>
|
||||
<div class="table_content">
|
||||
{% for container in containers %}
|
||||
<div class="line">
|
||||
<div class="status">{{ container.name }}</div>
|
||||
<div class="status">{{ container.status }}</div>
|
||||
<div class="status">
|
||||
<i id="reboot" class="button fa-solid fa-recycle" title="Reboot container" alt="Reboot container"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container_log" id="logs">
|
||||
{{ container.logs | safe }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/thsf.net/maintenance/scripts/maintenance.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
resources/thsf_2023.png
Normal file
BIN
resources/thsf_2023.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
@@ -1,10 +1,8 @@
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import logging
|
||||
from logging import config
|
||||
import yaml
|
||||
from flask import Flask, render_template, redirect, request, url_for
|
||||
from flask import Flask, render_template, redirect, url_for
|
||||
from flask_minify import minify
|
||||
from thsf.backend import Backend
|
||||
from thsf.schedule import Schedule
|
||||
@@ -37,7 +35,8 @@ try:
|
||||
config.dictConfig(app.local_config["log"])
|
||||
backend = Backend(url=app.local_config["pretalx"]["url"],
|
||||
apiprefix=app.local_config["pretalx"]["apiprefix"],
|
||||
apikey=app.local_config["pretalx"]["apikey"])
|
||||
apikey=app.local_config["pretalx"]["apikey"],
|
||||
ssl_verify=app.local_config["pretalx"]["ssl_verify"])
|
||||
schedule = Schedule()
|
||||
navbar = Navbar(config=app.local_config["navbar"])
|
||||
except Exception as err:
|
||||
@@ -47,6 +46,7 @@ except Exception as err:
|
||||
if app.local_config["log"]["root"]["level"] != "DEBUG":
|
||||
minify(app=app, html=True, js=True, cssless=True)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# -- Tools
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -63,7 +63,7 @@ def get_speaker_biography(code):
|
||||
try:
|
||||
speaker_info = backend.get(endpoint=f"events/{app.local_config['pretalx']['event']}/speakers/{code}/").json()
|
||||
return speaker_info.get("biography").strip()
|
||||
except Exception as err:
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
@@ -125,9 +125,10 @@ def planning():
|
||||
for slot in slots.get("slots"):
|
||||
for speaker in slot.get("speakers"):
|
||||
speaker["biography"] = get_speaker_biography(speaker.get("code"))
|
||||
slots = sorted(slots.get("slots"),
|
||||
key=lambda slot: slot.get("slot").get("start"))
|
||||
return render_template("planning.html",
|
||||
slots=sorted(slots.get("slots"),
|
||||
key=lambda slot: slot.get("slot").get("start")),
|
||||
slots=slots,
|
||||
navbar=navbar.get_from_page(page="/planning"),
|
||||
filter=["concert", "dj set", "panel discussion", "talk", "screening"])
|
||||
|
||||
@@ -153,9 +154,10 @@ def goodies():
|
||||
@app.route('/concerts', methods=['GET'])
|
||||
def concerts():
|
||||
slots = get_slots()
|
||||
slots = sorted(slots.get("slots"),
|
||||
key=lambda slot: slot.get("slot").get("start"))
|
||||
return render_template("planning.html",
|
||||
slots=sorted(slots.get("slots"),
|
||||
key=lambda slot: slot.get("slot").get("start")),
|
||||
slots=slots,
|
||||
navbar=navbar.get_from_page(page="/concerts"),
|
||||
filter=["concert", "dj set"])
|
||||
|
||||
@@ -163,9 +165,10 @@ def concerts():
|
||||
@app.route('/workshops', methods=['GET'])
|
||||
def workshops():
|
||||
slots = get_slots()
|
||||
slots = sorted(slots.get("slots"),
|
||||
key=lambda slot: slot.get("slot").get("start"))
|
||||
return render_template("planning.html",
|
||||
slots=sorted(slots.get("slots"),
|
||||
key=lambda slot: slot.get("slot").get("start")),
|
||||
slots=slots,
|
||||
navbar=navbar.get_from_page(page="/workshops"),
|
||||
filter=["workshop"])
|
||||
|
||||
@@ -173,9 +176,10 @@ def workshops():
|
||||
@app.route('/screenings', methods=['GET'])
|
||||
def screenings():
|
||||
slots = get_slots()
|
||||
slots = sorted(slots.get("slots"),
|
||||
key=lambda slot: slot.get("slot").get("start"))
|
||||
return render_template("planning.html",
|
||||
slots=sorted(slots.get("slots"),
|
||||
key=lambda slot: slot.get("slot").get("start")),
|
||||
slots=slots,
|
||||
navbar=navbar.get_from_page(page="/screenings"),
|
||||
filter=["screening"])
|
||||
|
||||
@@ -183,9 +187,10 @@ def screenings():
|
||||
@app.route('/discussions', methods=['GET'])
|
||||
def discussions():
|
||||
slots = get_slots()
|
||||
slots = sorted(slots.get("slots"),
|
||||
key=lambda slot: slot.get("slot").get("start"))
|
||||
return render_template("planning.html",
|
||||
slots=sorted(slots.get("slots"),
|
||||
key=lambda slot: slot.get("slot").get("start")),
|
||||
slots=slots,
|
||||
navbar=navbar.get_from_page(page="/discussions"),
|
||||
filter=["panel discussion"])
|
||||
|
||||
@@ -193,9 +198,10 @@ def discussions():
|
||||
@app.route('/exhibitions', methods=['GET'])
|
||||
def exhibitions():
|
||||
slots = get_slots()
|
||||
slots = sorted(slots.get("slots"),
|
||||
key=lambda slot: slot.get("slot").get("start"))
|
||||
return render_template("planning.html",
|
||||
slots=sorted(slots.get("slots"),
|
||||
key=lambda slot: slot.get("slot").get("start")),
|
||||
slots=slots,
|
||||
navbar=navbar.get_from_page(page="/exhibitions"),
|
||||
filter=["installation"])
|
||||
|
||||
@@ -203,9 +209,10 @@ def exhibitions():
|
||||
@app.route('/talks', methods=['GET'])
|
||||
def talks():
|
||||
slots = get_slots()
|
||||
slots = sorted(slots.get("slots"),
|
||||
key=lambda slot: slot.get("slot").get("start"))
|
||||
return render_template("planning.html",
|
||||
slots=sorted(slots.get("slots"),
|
||||
key=lambda slot: slot.get("slot").get("start")),
|
||||
slots=slots,
|
||||
navbar=navbar.get_from_page(page="/talks"),
|
||||
filter=["talk", "light talk"])
|
||||
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
import requests
|
||||
import logging
|
||||
|
||||
|
||||
class Backend:
|
||||
def __init__(self, url, apiprefix, apikey):
|
||||
def __init__(self, url, apiprefix, apikey, ssl_verify):
|
||||
self.url = url
|
||||
self.apiprefix = apiprefix
|
||||
self.apikey = apikey
|
||||
self.ssl_verify = ssl_verify
|
||||
self.session = requests.Session()
|
||||
|
||||
def get(self, endpoint, params=None):
|
||||
url = f"{self.url}/{self.apiprefix}/{endpoint}"
|
||||
headers = {"Authorization": f"Token {self.apikey}",
|
||||
"Accept": "application/json"}
|
||||
return self.session.get(url, params=params, headers=headers)
|
||||
return self.session.get(url,
|
||||
params=params,
|
||||
headers=headers,
|
||||
verify=self.ssl_verify)
|
||||
|
||||
@@ -23,5 +23,7 @@
|
||||
<p>Comme toujours, notre objectif est de créer un festival qui poétise les bifurcations de nos idées communes et qui réinvente le sens de certains schémas imposés par notre époque. Rejoignez-nous pour une expérience enrichissante et pleine de surprises !</p>
|
||||
|
||||
<p>Retrouvez <a href="/planning">le programme du THSF</a> avec ses <a href="/workshops">ateliers</a>, ses <a href="/exhibitions">expositions et installations</a> mais également ses <a href="/concerts">concerts</a>, ses <a href="/projections">projections</a>, ses <a href="/talks">présentations</a> et ses <a href="/discussions">tables rondes</a>.</p>
|
||||
<p>Accéder aux conférences, tables rondes et reportages grâce à nos amis de TVBruits: <a href="https://tvbruits.org/spip.php?mot87">https://tvbruits.org/spip.php?mot87</a>
|
||||
</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="content">
|
||||
<p>Accéder aux conférences, tables rondes et reportages grâce à nos amis de TVBruits: <a href="https://tvbruits.org/spip.php?mot87">https://tvbruits.org/spip.php?mot87</a>
|
||||
</p>
|
||||
{% for slot in slots %}
|
||||
{% set loop_index = loop.index %}
|
||||
{% if filter %}
|
||||
|
||||
Reference in New Issue
Block a user