generated from nathanwoodburn/python-webserver-template
feat: Make leaders more flexible
Some checks failed
Build Docker / BuildImage (push) Failing after 2m22s
Some checks failed
Build Docker / BuildImage (push) Failing after 2m22s
This commit is contained in:
53
server.py
53
server.py
@@ -1,77 +1,77 @@
|
|||||||
from functools import cache
|
|
||||||
import json
|
import json
|
||||||
from flask import (
|
from flask import (
|
||||||
Flask,
|
Flask,
|
||||||
make_response,
|
make_response,
|
||||||
redirect,
|
|
||||||
request,
|
|
||||||
jsonify,
|
jsonify,
|
||||||
render_template,
|
render_template,
|
||||||
send_from_directory,
|
send_from_directory,
|
||||||
send_file,
|
send_file,
|
||||||
)
|
)
|
||||||
import os
|
import os
|
||||||
import json
|
|
||||||
import requests
|
import requests
|
||||||
from datetime import datetime
|
|
||||||
import dotenv
|
import dotenv
|
||||||
import csv
|
import csv
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
|
||||||
dotenv.load_dotenv()
|
dotenv.load_dotenv()
|
||||||
|
|
||||||
|
|
||||||
def load_schedule_data():
|
def load_schedule_data():
|
||||||
"""Load schedule data from Google Sheets or fallback to JSON file"""
|
"""Load schedule data from Google Sheets or fallback to JSON file"""
|
||||||
# Try to load from Google Sheets first
|
# Try to load from Google Sheets first
|
||||||
google_sheet_url = os.getenv('GOOGLE_SHEET_URL')
|
google_sheet_url = os.getenv("GOOGLE_SHEET_URL")
|
||||||
|
|
||||||
if google_sheet_url:
|
if google_sheet_url:
|
||||||
try:
|
try:
|
||||||
# Convert Google Sheets URL to CSV export URL
|
# Convert Google Sheets URL to CSV export URL
|
||||||
if '/edit' in google_sheet_url:
|
if "/edit" in google_sheet_url:
|
||||||
csv_url = google_sheet_url.replace('/edit#gid=', '/export?format=csv&gid=')
|
csv_url = google_sheet_url.replace(
|
||||||
csv_url = csv_url.replace('/edit', '/export?format=csv')
|
"/edit#gid=", "/export?format=csv&gid="
|
||||||
|
)
|
||||||
|
csv_url = csv_url.replace("/edit", "/export?format=csv")
|
||||||
else:
|
else:
|
||||||
csv_url = google_sheet_url
|
csv_url = google_sheet_url
|
||||||
|
|
||||||
print(f"Fetching schedule from Google Sheets: {csv_url}")
|
print(f"Fetching schedule from Google Sheets: {csv_url}")
|
||||||
|
|
||||||
response = requests.get(csv_url, timeout=10)
|
response = requests.get(csv_url, timeout=10)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
|
|
||||||
# Parse CSV data
|
# Parse CSV data
|
||||||
csv_data = StringIO(response.text)
|
csv_data = StringIO(response.text)
|
||||||
reader = csv.DictReader(csv_data)
|
reader = csv.DictReader(csv_data)
|
||||||
|
|
||||||
schedule = []
|
schedule = []
|
||||||
for row in reader:
|
for row in reader:
|
||||||
# Map CSV columns to our expected format
|
# Map CSV columns to our expected format
|
||||||
|
leaders_str = row.get("Leaders", "").strip()
|
||||||
# Expected columns: Date, Primary Leader, Secondary Leader, Topic
|
# Expected columns: Date, Primary Leader, Secondary Leader, Topic
|
||||||
schedule_item = {
|
schedule_item = {
|
||||||
"date": row.get('Date', '').strip(),
|
"date": row.get("Date", "").strip(),
|
||||||
"primary_leader": row.get('Primary Leader', '').strip(),
|
"leaders": [leader for leader in leaders_str.split(", ") if leader]
|
||||||
"secondary_leader": row.get('Secondary Leader', '').strip(),
|
if leaders_str
|
||||||
"topic": row.get('Topic', '').strip()
|
else [],
|
||||||
|
"topic": row.get("Topic", "").strip(),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Only add rows that have at least a date and topic
|
# Only add rows that have at least a date and topic
|
||||||
if schedule_item['date'] and schedule_item['topic']:
|
if schedule_item["date"] and schedule_item["topic"]:
|
||||||
schedule.append(schedule_item)
|
schedule.append(schedule_item)
|
||||||
|
|
||||||
print(f"Successfully loaded {len(schedule)} items from Google Sheets")
|
print(f"Successfully loaded {len(schedule)} items from Google Sheets")
|
||||||
return schedule
|
return schedule
|
||||||
|
|
||||||
except requests.RequestException as e:
|
except requests.RequestException as e:
|
||||||
print(f"Error fetching from Google Sheets: {e}")
|
print(f"Error fetching from Google Sheets: {e}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error parsing Google Sheets data: {e}")
|
print(f"Error parsing Google Sheets data: {e}")
|
||||||
|
|
||||||
# Fallback to JSON file
|
# Fallback to JSON file
|
||||||
try:
|
try:
|
||||||
with open('schedule_data.json', 'r') as f:
|
with open("schedule_data.json", "r") as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
print("Loaded schedule from local JSON file")
|
print("Loaded schedule from local JSON file")
|
||||||
return data.get('schedule', [])
|
return data.get("schedule", [])
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print("Warning: schedule_data.json not found. Using empty schedule.")
|
print("Warning: schedule_data.json not found. Using empty schedule.")
|
||||||
return []
|
return []
|
||||||
@@ -79,6 +79,7 @@ def load_schedule_data():
|
|||||||
print("Warning: Invalid JSON in schedule_data.json. Using empty schedule.")
|
print("Warning: Invalid JSON in schedule_data.json. Using empty schedule.")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
# Load schedule data from JSON file
|
# Load schedule data from JSON file
|
||||||
SCHEDULE_DATA = load_schedule_data()
|
SCHEDULE_DATA = load_schedule_data()
|
||||||
|
|
||||||
@@ -90,6 +91,7 @@ def find(name, path):
|
|||||||
if name in files:
|
if name in files:
|
||||||
return os.path.join(root, name)
|
return os.path.join(root, name)
|
||||||
|
|
||||||
|
|
||||||
# Assets routes
|
# Assets routes
|
||||||
@app.route("/assets/<path:path>")
|
@app.route("/assets/<path:path>")
|
||||||
def send_assets(path):
|
def send_assets(path):
|
||||||
@@ -181,6 +183,7 @@ def api_schedule():
|
|||||||
SCHEDULE_DATA = current_schedule
|
SCHEDULE_DATA = current_schedule
|
||||||
return jsonify({"schedule": current_schedule})
|
return jsonify({"schedule": current_schedule})
|
||||||
|
|
||||||
|
|
||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -43,10 +43,10 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for item in schedule %}
|
{% for item in schedule %}
|
||||||
<tr class="{% if not item.primary_leader and not item.secondary_leader %}special-event{% endif %}">
|
<tr class="{% if not item.leaders %}special-event{% endif %}">
|
||||||
<td class="date-cell">{{ item.date }}</td>
|
<td class="date-cell">{{ item.date }}</td>
|
||||||
<td class="leader-cell">{% if item.primary_leader %}{{ item.primary_leader }}{% endif %}{% if item.primary_leader and item.secondary_leader %} & {% endif %}{% if item.secondary_leader %}{{ item.secondary_leader }}{% endif %}</td>
|
<td class="leader-cell">{% if item.leaders %}{% if item.leaders|length > 1 %}{{ item.leaders[:-1]|join(', ') }} & {{ item.leaders[-1] }}{% else %}{{ item.leaders[0] }}{% endif %}{% endif %}</td>
|
||||||
<td class="topic-cell" {% if item.primary_leader or item.secondary_leader %}data-leaders="Leaders: {% if item.primary_leader %}{{ item.primary_leader }}{% endif %}{% if item.primary_leader and item.secondary_leader %} & {% endif %}{% if item.secondary_leader %}{{ item.secondary_leader }}{% endif %}"{% endif %}>{{ item.topic }}</td>
|
<td class="topic-cell" {% if item.leaders %}data-leaders="Leaders: {% if item.leaders|length > 1 %}{{ item.leaders[:-1]|join(', ') }} & {{ item.leaders[-1] }}{% else %}{{ item.leaders[0] }}{% endif %}"{% endif %}>{{ item.topic }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -102,6 +102,8 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
{# <script>console.log({{schedule | tojson}});</script> #}
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user