From c160446eac9987fa85b42690d3fffb7a4b6b0e0d Mon Sep 17 00:00:00 2001
From: Feiko Wielsma
Date: Wed, 26 Nov 2025 17:47:20 +0100
Subject: [PATCH] Enhance event registration system: - Update Google Sheets
integration to support optional tab names. - Add functionality to fetch and
display public participants. - Revise event configuration in YAML for clarity
and consistency. - Improve form layout with additional fields for contact
information and meal preferences. - Create a new home page template for event
selection. - Update success page to link back to the participants list.
---
app.py | 129 +++++++++++++++++++++++++++++++----------
docker-compose.yaml | 2 +
events.yaml | 16 ++---
templates/form.html | 58 +++++++++++++++++-
templates/home.html | 51 ++++++++++++++++
templates/success.html | 5 +-
6 files changed, 219 insertions(+), 42 deletions(-)
create mode 100644 templates/home.html
diff --git a/app.py b/app.py
index 952497f..f1071ae 100644
--- a/app.py
+++ b/app.py
@@ -12,72 +12,141 @@ def load_config():
return yaml.safe_load(f)
# Connect to Google Sheets
-def get_google_sheet(sheet_id):
+# UPDATED: Now accepts an optional tab_name
+def get_google_sheet(sheet_id, tab_name=None):
gc = gspread.service_account(filename='credentials.json')
try:
sh = gc.open_by_key(sheet_id)
- return sh.sheet1 # Assumes data goes into the first tab
+ if tab_name:
+ # Open specific tab by name
+ return sh.worksheet(tab_name)
+ else:
+ # Default to first tab
+ return sh.sheet1
except Exception as e:
- print(f"Error connecting to Google Sheet: {e}")
+ print(f"Error connecting to Google Sheet (ID: {sheet_id}, Tab: {tab_name}): {e}")
return None
+# NEW: Fetch and filter participants for public display
+# UPDATED: Now accepts tab_name
+def get_public_participants(sheet_id, tab_name=None):
+ sheet = get_google_sheet(sheet_id, tab_name)
+ if not sheet:
+ return []
+
+ try:
+ # Get all rows
+ rows = sheet.get_all_values()
+
+ # Skip header row (assuming row 1 is header)
+ if len(rows) > 1:
+ data_rows = rows[1:]
+ else:
+ return []
+
+ public_list = []
+ for row in data_rows:
+ # Ensure row is long enough to avoid errors
+ if len(row) < 17:
+ continue
+
+ # Extract ONLY non-sensitive columns based on our save order
+ # 1: Klasse, 2: Zeilnummer, 3: Bootnaam, 4: Boottype
+ # 7: Naam, 10: Plaats, 16: Vereniging
+ entry = {
+ 'klasse': row[1],
+ 'zeilnummer': row[2],
+ 'bootnaam': row[3],
+ 'boottype': row[4],
+ 'naam': row[7],
+ 'plaats': row[10],
+ 'vereniging': row[16]
+ }
+ public_list.append(entry)
+
+ return public_list
+ except Exception as e:
+ print(f"Error fetching participants: {e}")
+ return []
+
@app.route('/')
def home():
- # List all available active events
config = load_config()
events = config.get('events', {})
return render_template('home.html', events=events)
-# Dynamic Route for any event defined in YAML
@app.route('/', methods=['GET', 'POST'])
def event_form(event_slug):
config = load_config()
events = config.get('events', {})
- # Check if event exists in config
+ # Check for global sheet_id fallback
+ global_sheet_id = config.get('master_sheet_id')
+
if event_slug not in events:
abort(404)
event_data = events[event_slug]
+ # Determine which Sheet ID to use (Event specific > Global)
+ sheet_id = event_data.get('sheet_id', global_sheet_id)
+ # Get Tab Name (optional)
+ tab_name = event_data.get('tab_name')
+
+ # Ensure we have a valid sheet ID before proceeding
+ if not sheet_id:
+ return "Configuration Error: No 'sheet_id' found in event config or 'master_sheet_id' in root config."
+
+ # Update event_data with resolved sheet_id so templates work correctly
+ event_data['sheet_id'] = sheet_id
+
if request.method == 'POST':
- # 1. Collect Form Data
form_data = [
- datetime.now().strftime("%Y-%m-%d %H:%M:%S"), # Timestamp
- request.form.get('klasse'),
- request.form.get('zeilnummer'),
- request.form.get('bootnaam'),
- request.form.get('boottype'),
- # Checkboxes (Join them or separate columns? Let's join for simplicity)
- ", ".join([k for k in ['genua', 'rolfok', 'spinaker', 'halfwinder', 'genaker', 'dacron'] if k in request.form]),
- request.form.get('schroef'),
- request.form.get('naam'),
- request.form.get('straat'),
- request.form.get('postcode'),
- request.form.get('plaats'),
- request.form.get('land'),
- request.form.get('telefoonmobiel'),
- request.form.get('email'),
- request.form.get('startlicentienummer'),
- request.form.get('vereniging'),
- request.form.get('opmerkingen')
+ datetime.now().strftime("%Y-%m-%d %H:%M:%S"), # 0: Timestamp
+ request.form.get('klasse'), # 1: Klasse
+ request.form.get('zeilnummer'), # 2: Zeilnummer
+ request.form.get('bootnaam'), # 3: Bootnaam
+ request.form.get('boottype'), # 4: Boottype
+ ", ".join([k for k in ['genua', 'rolfok', 'spinaker', 'halfwinder', 'genaker', 'dacron'] if k in request.form]), # 5: Zeilvoering
+ request.form.get('schroef'), # 6: Schroef
+ request.form.get('naam'), # 7: Naam (Keep public)
+ request.form.get('straat'), # 8: Straat (PRIVATE)
+ request.form.get('postcode'), # 9: Postcode (PRIVATE)
+ request.form.get('plaats'), # 10: Plaats
+ request.form.get('land'), # 11: Land
+ request.form.get('telefoonmobiel'), # 12: Mobiel (PRIVATE)
+ request.form.get('telefoonvast'), # 13: Vast (PRIVATE)
+ request.form.get('email'), # 14: Email (PRIVATE)
+ request.form.get('startlicentienummer'), # 15: Licentie
+ request.form.get('vereniging'), # 16: Vereniging
+ request.form.get('buffet', '0'), # 17: Buffet
+ request.form.get('ontbijt', '0'), # 18: Ontbijt
+ request.form.get('opmerkingen') # 19: Opmerkingen
]
- # 2. Push to Google Sheet
- sheet = get_google_sheet(event_data['sheet_id'])
+ sheet = get_google_sheet(sheet_id, tab_name)
if sheet:
sheet.append_row(form_data)
return redirect(url_for('success', event_slug=event_slug))
else:
- return "Error: Could not connect to Google Sheet. Check server logs."
+ return f"Error: Could not connect to Google Sheet Tab '{tab_name}'. Check server logs."
- return render_template('form.html', event=event_data, slug=event_slug)
+ # GET Request: Fetch participants to show at bottom of form
+ participants = get_public_participants(sheet_id, tab_name)
+ return render_template('form.html', event=event_data, slug=event_slug, participants=participants)
@app.route('//success')
def success(event_slug):
config = load_config()
event_data = config['events'].get(event_slug)
- return render_template('success.html', event=event_data)
+
+ # Resolve sheet ID for the success page link too
+ global_sheet_id = config.get('master_sheet_id')
+ sheet_id = event_data.get('sheet_id', global_sheet_id)
+ event_data['sheet_id'] = sheet_id
+
+ # Pass slug so we can link back
+ return render_template('success.html', event=event_data, slug=event_slug)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
\ No newline at end of file
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 872493c..9cc027f 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -4,6 +4,8 @@ services:
build: .
container_name: sailing_forms
restart: unless-stopped
+ ports:
+ - "5000:5000"
volumes:
# Mount the config file so you can edit it without rebuilding
- ./events.yaml:/app/events.yaml
diff --git a/events.yaml b/events.yaml
index b68d804..2527f35 100644
--- a/events.yaml
+++ b/events.yaml
@@ -1,18 +1,14 @@
# Define as many events as you want here.
# The key (e.g., 'zomeravond') becomes the URL: domain.com/zomeravond
+master_sheet_id: "1k-eTke2GGmcMtq2-acvWPvjgfDeUHBsR0_Bd_tAbLx0"
events:
zomeravond:
- title: "Inschrijving Zomeravondregatta"
- sheet_id: "1k-eTke2GGmcMtq2-acvWPvjgfDeUHBsR0_Bd_tAbLx0"
+ title: "Zomeravondregatta 2026"
+ tab_name: "Zomeravond 2026"
description: "De gezelligste avondwedstrijd van het jaar."
papklokken:
- title: "Papklokkenrace 2025"
- sheet_id: "1k-eTke2GGmcMtq2-acvWPvjgfDeUHBsR0_Bd_tAbLx0"
- description: "Sluit het seizoen af in stijl."
-
- winterwedstrijd:
- title: "Winter Bokaal"
- sheet_id: "1k-eTke2GGmcMtq2-acvWPvjgfDeUHBsR0_Bd_tAbLx0"
- description: "Alleen voor de echte bikkels."
\ No newline at end of file
+ title: "Papklokkenrace 2026"
+ tab_name: "Papklokken 2026"
+ description: "Sluit het seizoen af in stijl."
\ No newline at end of file
diff --git a/templates/form.html b/templates/form.html
index e89921a..c162aec 100644
--- a/templates/form.html
+++ b/templates/form.html
@@ -94,9 +94,13 @@
-
+
+
+
+
+
@@ -111,6 +115,19 @@
+
+ Eten & Drinken
+
+
@@ -134,6 +151,45 @@
+
+
+
+
+
+
+
+
+
Wedstrijd Inschrijvingen
+
Kies hieronder de wedstrijd waarvoor je je wilt inschrijven.
+
+
+
+
+
+ {% for slug, data in events.items() %}
+
+
+
+
+
{{ data.title }}
+
{{ data.description }}
+
Inschrijven →
+
+
+
+ {% endfor %}
+
+
+
+
diff --git a/templates/home.html b/templates/home.html
new file mode 100644
index 0000000..efca349
--- /dev/null
+++ b/templates/home.html
@@ -0,0 +1,51 @@
+
+
+