summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDirk Engling <erdgeist@erdgeist.org>2025-11-06 00:48:00 +0000
committerDirk Engling <erdgeist@erdgeist.org>2025-11-06 00:48:00 +0000
commit6f1bcc3db2c8ee807b68fa8a47a1a8cb7aabcc48 (patch)
tree1c9e920b22a6d7d526b0ecb51cb9d73e61e75823
parent95ae3c51cf05425baf739919af9938608f62ad64 (diff)
Create a create_app helper to be used from wsgi.py
-rwxr-xr-xhalfnarp2.py54
-rw-r--r--static/faq.html4
-rw-r--r--static/halfnarp.js2
-rw-r--r--wsgi.py6
4 files changed, 37 insertions, 29 deletions
diff --git a/halfnarp2.py b/halfnarp2.py
index 5ac9405..24d099a 100755
--- a/halfnarp2.py
+++ b/halfnarp2.py
@@ -1,6 +1,6 @@
1#!venv/bin/python 1#!venv/bin/python
2 2
3from flask import Flask, render_template, jsonify, request, abort, send_file, url_for 3from flask import Flask, Blueprint, render_template, jsonify, request, abort, send_file, url_for
4from flask_sqlalchemy import SQLAlchemy 4from flask_sqlalchemy import SQLAlchemy
5from flask_cors import CORS 5from flask_cors import CORS
6from lxml import etree 6from lxml import etree
@@ -13,10 +13,9 @@ from datetime import datetime, time, timedelta
13from html_sanitizer import Sanitizer 13from html_sanitizer import Sanitizer
14from hashlib import sha256 14from hashlib import sha256
15 15
16app = Flask(__name__) 16bp = Blueprint("main", __name__)
17db = SQLAlchemy() 17db = SQLAlchemy()
18 18
19
20class TalkPreference(db.Model): 19class TalkPreference(db.Model):
21 """A preference of halfnarp frontend. An array of strings""" 20 """A preference of halfnarp frontend. An array of strings"""
22 21
@@ -26,17 +25,17 @@ class TalkPreference(db.Model):
26 25
27 26
28""" 27"""
29@app.route("/") 28@bp.route("/")
30def root(): 29def root():
31 return render_template("index.html") 30 return render_template("index.html")
32""" 31"""
33 32
34@app.route("/-/talkpreferences", methods=["GET"]) 33@bp.route("/-/talkpreferences", methods=["GET"])
35def sessions(): 34def sessions():
36 return send_file("var/talks_local", mimetype="application/json") 35 return send_file("var/talks_local", mimetype="application/json")
37 36
38 37
39@app.route("/-/talkpreferences/<uid>", methods=["GET"]) 38@bp.route("/-/talkpreferences/<uid>", methods=["GET"])
40def get_own_preferences(uid): 39def get_own_preferences(uid):
41 pref = db.session.get(TalkPreference, uid) 40 pref = db.session.get(TalkPreference, uid)
42 if pref == None: 41 if pref == None:
@@ -57,7 +56,7 @@ def get_own_preferences(uid):
57 ) 56 )
58 57
59 58
60@app.route("/-/talkpreferences/", methods=["POST"]) 59@bp.route("/-/talkpreferences/", methods=["POST"])
61def store_preferences(): 60def store_preferences():
62 try: 61 try:
63 content = request.json 62 content = request.json
@@ -92,7 +91,7 @@ def store_preferences():
92 ) 91 )
93 92
94 93
95@app.route("/-/talkpreferences/<uid>", methods=["POST", "PUT"]) 94@bp.route("/-/talkpreferences/<uid>", methods=["POST", "PUT"])
96def update_preferences(uid): 95def update_preferences(uid):
97 pref = db.session.get(TalkPreference, uid) 96 pref = db.session.get(TalkPreference, uid)
98 if pref == None: 97 if pref == None:
@@ -105,7 +104,7 @@ def update_preferences(uid):
105 return jsonify({"uid": pref.uid, "hashed_uid": pref.public_uid}) 104 return jsonify({"uid": pref.uid, "hashed_uid": pref.public_uid})
106 105
107 106
108@app.route("/-/talkpreferences/public/<public_uid>", methods=["GET"]) 107@bp.route("/-/talkpreferences/public/<public_uid>", methods=["GET"])
109def get_preferences(public_uid): 108def get_preferences(public_uid):
110 pref = ( 109 pref = (
111 db.session.query(TalkPreference) 110 db.session.query(TalkPreference)
@@ -238,7 +237,7 @@ def export_prefs(config):
238 print("[]]") 237 print("[]]")
239 238
240 239
241if __name__ == "__main__": 240def parse_args():
242 parser = ArgumentParser(description="halfnarp2") 241 parser = ArgumentParser(description="halfnarp2")
243 parser.add_argument( 242 parser.add_argument(
244 "-i", 243 "-i",
@@ -257,20 +256,20 @@ if __name__ == "__main__":
257 parser.add_argument( 256 parser.add_argument(
258 "-c", "--config", help="Config file location", default="./config.json" 257 "-c", "--config", help="Config file location", default="./config.json"
259 ) 258 )
260 args = parser.parse_args() 259 return parser.parse_args()
261 260
262 with open(args.config, mode="r", encoding="utf-8") as json_file:
263 config = json.load(json_file)
264 config["pretalx-api-url"] = (
265 config["pretalx-url"] + "api/events/" + config["pretalx-conference"]
266 )
267 261
268 app.config["SQLALCHEMY_DATABASE_URI"] = config.get( 262def create_app(config_file="./config.json"):
263 app = Flask(__name__)
264 with open(config_file, mode="r", encoding="utf-8") as config_file:
265 app.config["halfnarp"] = json.load(config_file)
266
267 app.config["SQLALCHEMY_DATABASE_URI"] = app.config["halfnarp"].get(
269 "database-uri", "sqlite:///test.db" 268 "database-uri", "sqlite:///test.db"
270 ) 269 )
271 app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False 270 app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
272 app.config["SERVER_NAME"] = config.get("server-name", "localhost") 271 app.config["SERVER_NAME"] = app.config["halfnarp"].get("server-name", "localhost")
273 app.config["SECRET_KEY"] = config.get("server-secret", "<YOUR SERVER SECRET HERE>") 272 app.config["SECRET_KEY"] = app.config["halfnarp"].get("server-secret", "<YOUR SERVER SECRET HERE>")
274 273
275 if app.config["SECRET_KEY"] == "<YOUR SERVER SECRET HERE>": 274 if app.config["SECRET_KEY"] == "<YOUR SERVER SECRET HERE>":
276 print("You must set the server-secret in your config.json") 275 print("You must set the server-secret in your config.json")
@@ -281,15 +280,24 @@ if __name__ == "__main__":
281 CORS() 280 CORS()
282 281
283 db.init_app(app) 282 db.init_app(app)
283 app.register_blueprint(bp)
284 return app
284 285
286if __name__ == "__main__":
287 args = parse_args()
288 app = create_app(args.config)
289
290 app.config["halfnarp"]["pretalx-api-url"] = (
291 app.config["halfnarp"]["pretalx-url"] + "api/events/" + app.config["halfnarp"]["pretalx-conference"]
292 )
285 with app.app_context(): 293 with app.app_context():
286 db.create_all() 294 db.create_all()
287 if args.pretalx_import: 295 if args.pretalx_import:
288 fetch_talks(config) 296 fetch_talks(app.config["halfnarp"])
289 elif args.fullnarp_export: 297 elif args.fullnarp_export:
290 export_prefs(config) 298 export_prefs(app.config["halfnarp"])
291 else: 299 else:
292 app.run( 300 app.run(
293 host=config.get("host", "127.0.0.1"), 301 host=app.config["halfnarp"].get("host", "127.0.0.1"),
294 port=int(config.get("port", "8080")), 302 port=int(app.config["halfnarp"].get("port", "8080")),
295 ) 303 )
diff --git a/static/faq.html b/static/faq.html
index aefd03d..a90b4b5 100644
--- a/static/faq.html
+++ b/static/faq.html
@@ -7,7 +7,7 @@
7</head> 7</head>
8<body> 8<body>
9 9
10<div class="headline">The 38C3 halfnarp FAQ</div> 10<div class="headline">The 39C3 halfnarp FAQ</div>
11 11
12<dl> 12<dl>
13<dt>Q: What is halfnarp?</dt> 13<dt>Q: What is halfnarp?</dt>
@@ -18,7 +18,7 @@
18</dd> 18</dd>
19<dt>Q: How does it work?</dt> 19<dt>Q: How does it work?</dt>
20<dd> 20<dd>
21 <p>A: 38C3 Fahrplan is curated by six teams each responsible for one track. By default, lectures are sorted by these tracks.</p> 21 <p>A: 39C3 Fahrplan is curated by six teams each responsible for one track. By default, lectures are sorted by these tracks.</p>
22 <ul> 22 <ul>
23 <li>On a desktop browser, hovering over an event’s description reveals the full abstract. Clicking on an event adds or removes events to/from your favorites list – they turn green.</li> 23 <li>On a desktop browser, hovering over an event’s description reveals the full abstract. Clicking on an event adds or removes events to/from your favorites list – they turn green.</li>
24 <li>On mobile browsers, tapping an event once selects it and reveals the whole content. Tapping a selected event adds or removes events to/from your favorites list – they turn green.</li> 24 <li>On mobile browsers, tapping an event once selects it and reveals the whole content. Tapping a selected event adds or removes events to/from your favorites list – they turn green.</li>
diff --git a/static/halfnarp.js b/static/halfnarp.js
index b7f4a45..5cd1ef3 100644
--- a/static/halfnarp.js
+++ b/static/halfnarp.js
@@ -93,7 +93,7 @@ function redraw_calendar(myuid, ids) {
93 calendar += 'DTSTART:' + start.toISOString().replace(/-|;|:|\./g, '').replace(/...Z$/, 'Z') + '\r\n'; 93 calendar += 'DTSTART:' + start.toISOString().replace(/-|;|:|\./g, '').replace(/...Z$/, 'Z') + '\r\n';
94 calendar += 'DURATION:PT' + item.duration + 'S\r\n'; 94 calendar += 'DURATION:PT' + item.duration + 'S\r\n';
95 calendar += 'LOCATION:' + item.room_name + '\r\n'; 95 calendar += 'LOCATION:' + item.room_name + '\r\n';
96 calendar += 'URL:http://events.ccc.de/congress/2023/Fahrplan/events/' + item.event_id + '.html\r\n'; 96 calendar += 'URL:http://events.ccc.de/congress/2025/Fahrplan/events/' + item.event_id + '.html\r\n';
97 calendar += 'SUMMARY:' + item.title + '\r\n'; 97 calendar += 'SUMMARY:' + item.title + '\r\n';
98 calendar += 'DESCRIPTION:' + item.abstract.replace(/\n|\r/g, ' ') + '\r\n'; 98 calendar += 'DESCRIPTION:' + item.abstract.replace(/\n|\r/g, ' ') + '\r\n';
99 // console.log( 'id:' + id + ' ' + all_events[id] ); 99 // console.log( 'id:' + id + ' ' + all_events[id] );
diff --git a/wsgi.py b/wsgi.py
index 2ad28d9..db217db 100644
--- a/wsgi.py
+++ b/wsgi.py
@@ -1,4 +1,4 @@
1from halfnarp2 import app 1from halfnarp2 import create_app
2 2
3if __name__ == "__main__": 3app = create_app("config.json")
4 app.run(debug=False) 4#app.run(debug=False)