inaktive veranstaltungen zeigen keinen teilnahmeberreich mehr, veranstaltungsortsuche verbessert

This commit is contained in:
kai
2026-08-25 13:15:08 +02:00
parent 60d8c941de
commit 714194615f
3 changed files with 85 additions and 7 deletions
+26 -3
View File
@@ -2,6 +2,7 @@ import os
import uuid import uuid
import secrets import secrets
import hashlib import hashlib
import re
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from datetime import datetime, timedelta from datetime import datetime, timedelta
@@ -1147,6 +1148,7 @@ def concert_detail(request: Request, concert_id: int):
] ]
attending_users = [item for item in attendance if item["status"] == "attending"] attending_users = [item for item in attendance if item["status"] == "attending"]
ticket_seekers = [item for item in attendance if item["status"] == "ticket_search"] ticket_seekers = [item for item in attendance if item["status"] == "ticket_search"]
maybe_users = [item for item in attendance if item["status"] == "maybe"]
current_attendance = next( current_attendance = next(
(item["status"] for item in attendance if item["user_id"] == user["id"]), (item["status"] for item in attendance if item["user_id"] == user["id"]),
None, None,
@@ -1165,6 +1167,8 @@ def concert_detail(request: Request, concert_id: int):
attending_count=len(attending_users), attending_count=len(attending_users),
ticket_seekers=ticket_seekers, ticket_seekers=ticket_seekers,
ticket_seeker_count=len(ticket_seekers), ticket_seeker_count=len(ticket_seekers),
maybe_users=maybe_users,
maybe_count=len(maybe_users),
) )
@@ -1606,6 +1610,12 @@ def search_venues(q: str):
return [] return []
results = [] results = []
query_tokens = [
token
for token in re.findall(r"[a-z0-9]+", q.lower())
if len(token) >= 3
]
token_match = " AND ".join("name ILIKE %s" for _ in query_tokens) or "FALSE"
# ======================================================== # ========================================================
@@ -1616,7 +1626,7 @@ def search_venues(q: str):
with connection.cursor() as cursor: with connection.cursor() as cursor:
cursor.execute(""" cursor.execute(f"""
SELECT SELECT
id, id,
name, name,
@@ -1633,6 +1643,7 @@ def search_venues(q: str):
name ILIKE %s name ILIKE %s
OR city ILIKE %s OR city ILIKE %s
OR street ILIKE %s OR street ILIKE %s
OR ({token_match})
ORDER BY ORDER BY
CASE CASE
WHEN LOWER(name) = LOWER(%s) WHEN LOWER(name) = LOWER(%s)
@@ -1653,11 +1664,13 @@ def search_venues(q: str):
f"%{q}%", f"%{q}%",
*[f"%{token}%" for token in query_tokens],
q, q,
f"{q}%", f"{q}%",
f"%{q}%" f"%{q}%",
)) ))
@@ -1717,9 +1730,11 @@ def search_venues(q: str):
"User-Agent": "PinguConcerts/1.0" "User-Agent": "PinguConcerts/1.0"
} }
external_query = re.sub(r"\bhall\b", "halle", q, flags=re.IGNORECASE)
params = { params = {
"q": q, "q": external_query,
"format": "jsonv2", "format": "jsonv2",
@@ -1876,6 +1891,14 @@ def search_venues(q: str):
score = 0 score = 0
name_tokens = re.findall(r"[a-z0-9]+", name_lower)
matched_tokens = sum(
any(candidate.startswith(token) or token.startswith(candidate)
for candidate in name_tokens)
for token in query_tokens
)
score += matched_tokens * 30
if name_lower == query_lower: if name_lower == query_lower:
+21 -2
View File
@@ -196,7 +196,9 @@
{% endif %} {% endif %}
<section class="attendance-section" id="attendance"> {% if not concert.is_past %}
<section class="attendance-section" id="attendance">
<h2> <h2>
🐧 Wer ist dabei? 🐧 Wer ist dabei?
@@ -241,6 +243,7 @@
<details class="attendance-list"> <details class="attendance-list">
<summary> <summary>
{{ attending_count }} Zusage{% if attending_count != 1 %}n{% endif %} {{ attending_count }} Zusage{% if attending_count != 1 %}n{% endif %}
· {{ maybe_count }} Vielleicht
· {{ ticket_seeker_count }} sucht Ticket · {{ ticket_seeker_count }} sucht Ticket
</summary> </summary>
@@ -260,6 +263,20 @@
{% endif %} {% endif %}
</div> </div>
<div>
<h3>? Vielleicht</h3>
{% if maybe_users %}
<ul>
{% for maybe_user in maybe_users %}
<li>{{ maybe_user.name }}</li>
{% endfor %}
</ul>
{% else %}
<p>Noch keine Vielleicht-Angaben.</p>
{% endif %}
</div>
<div> <div>
<h3>🎟️ Sucht ein Ticket</h3> <h3>🎟️ Sucht ein Ticket</h3>
@@ -277,7 +294,9 @@
</div> </div>
</details> </details>
</section> </section>
{% endif %}
<section class="comments-section" id="comments"> <section class="comments-section" id="comments">
+38 -2
View File
@@ -389,6 +389,27 @@ const selectedVenue =
let searchTimeout = null; let searchTimeout = null;
let venueRequestController = null;
function clearVenueSelection() {
[
"venue-id",
"venue-name",
"venue-city",
"venue-street",
"venue-postal-code",
"venue-country",
"venue-latitude",
"venue-longitude"
].forEach(
id => {
document.getElementById(id).value = "";
}
);
}
venueSearch.addEventListener( venueSearch.addEventListener(
@@ -410,6 +431,8 @@ venueSearch.addEventListener(
selectedVenue.style.display = selectedVenue.style.display =
"none"; "none";
clearVenueSelection();
if (query.length < 2) { if (query.length < 2) {
@@ -426,7 +449,7 @@ venueSearch.addEventListener(
); );
}, },
300 450
); );
} }
@@ -443,9 +466,18 @@ async function searchVenues(
try { try {
if (venueRequestController) {
venueRequestController.abort();
}
venueRequestController = new AbortController();
const response = const response =
await fetch( await fetch(
`/api/venues/search?q=${encodeURIComponent(query)}` `/api/venues/search?q=${encodeURIComponent(query)}`,
{
signal: venueRequestController.signal
}
); );
@@ -554,6 +586,10 @@ async function searchVenues(
} catch (error) { } catch (error) {
if (error.name === "AbortError") {
return;
}
console.error( console.error(
"Venue search failed:", "Venue search failed:",
error error