Cleanup: training_exercises.js_exercise_id — ID-Mismatch bereinigt, JOIN mit exercise_progress, Fuß-Umbenennung — SW by-v508, APP_VER 485
This commit is contained in:
parent
9e9b87af35
commit
ad3b73d687
5 changed files with 75 additions and 31 deletions
|
|
@ -1482,3 +1482,24 @@ def _migrate(conn_factory):
|
||||||
);
|
);
|
||||||
CREATE INDEX IF NOT EXISTS idx_bj_user ON breeder_jahresberichte(user_id, jahr DESC);
|
CREATE INDEX IF NOT EXISTS idx_bj_user ON breeder_jahresberichte(user_id, jahr DESC);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
# js_exercise_id zu training_exercises — verbindet training_exercises mit exercise_progress
|
||||||
|
existing_te = [row[1] for row in conn.execute("PRAGMA table_info(training_exercises)").fetchall()]
|
||||||
|
if 'js_exercise_id' not in existing_te:
|
||||||
|
import re as _re
|
||||||
|
_CAT_TO_TAB = {
|
||||||
|
'Grundkommando': 'grundkommandos', 'Trick': 'tricks',
|
||||||
|
'Problemverhalten': 'problemverhalten', 'Mentale Auslastung': 'mentale-auslastung',
|
||||||
|
'Hundesport': 'hundesport', 'Körperpflege': 'koerperpflege',
|
||||||
|
'Welpe Basics': 'welpe-basics', 'Grundlagen': 'grundlagen',
|
||||||
|
}
|
||||||
|
conn.execute("ALTER TABLE training_exercises ADD COLUMN js_exercise_id TEXT")
|
||||||
|
# "Fuß (Leinenführigkeit)" → "Fuß" (damit es mit alten exercise_progress-Einträgen matcht)
|
||||||
|
conn.execute("UPDATE training_exercises SET name='Fuß' WHERE exercise_id='gk_fuss'")
|
||||||
|
rows = conn.execute("SELECT id, name, kategorie FROM training_exercises").fetchall()
|
||||||
|
for row in rows:
|
||||||
|
tab = _CAT_TO_TAB.get(row['kategorie'], row['kategorie'].lower().replace(' ', '-'))
|
||||||
|
js_id = tab + '_' + _re.sub(r'[\s/]+', '_', row['name'])
|
||||||
|
conn.execute("UPDATE training_exercises SET js_exercise_id=? WHERE id=?", (js_id, row['id']))
|
||||||
|
conn.execute("CREATE INDEX IF NOT EXISTS idx_te_js_id ON training_exercises(js_exercise_id)")
|
||||||
|
logger.info("Migration: training_exercises.js_exercise_id hinzugefügt, 'Fuß' bereinigt.")
|
||||||
|
|
|
||||||
|
|
@ -159,36 +159,58 @@ async def get_welcome_dashboard(dog_id: int, user=Depends(get_current_user)):
|
||||||
"SELECT COUNT(*) AS n FROM diary WHERE dog_id=?", (dog_id,)
|
"SELECT COUNT(*) AS n FROM diary WHERE dog_id=?", (dog_id,)
|
||||||
).fetchone()["n"]
|
).fetchone()["n"]
|
||||||
|
|
||||||
# Tagesübung — aus exercise_progress im JS-Format (tab_Name), tagesstabil
|
# Tagesübung — JOIN mit training_exercises via js_exercise_id, tagesstabil
|
||||||
import datetime as _dt
|
import datetime as _dt
|
||||||
day_num = (_dt.date.today() - _dt.date(2024, 1, 1)).days
|
day_num = (_dt.date.today() - _dt.date(2024, 1, 1)).days
|
||||||
|
|
||||||
# Nur exercise_ids im JS-Format (starten mit bekanntem Tab-Namen)
|
# Versuche JOIN (funktioniert wenn js_exercise_id-Spalte vorhanden)
|
||||||
_KNOWN_PREFIXES = (
|
try:
|
||||||
'grundkommandos_', 'tricks_', 'problemverhalten_',
|
joined = conn.execute(
|
||||||
'mentale-auslastung_', 'hundesport_', 'koerperpflege_', 'welpe-basics_',
|
"""SELECT ep.exercise_id, te.name, te.kategorie AS kategorie_raw,
|
||||||
'grundlagen_',
|
te.schwierigkeit, te.js_exercise_id
|
||||||
)
|
FROM exercise_progress ep
|
||||||
raw_progress = conn.execute(
|
JOIN training_exercises te ON te.js_exercise_id = ep.exercise_id
|
||||||
"""SELECT exercise_id FROM exercise_progress
|
WHERE ep.user_id = ? AND ep.status IN ('noch-nicht', 'manchmal', 'meistens')
|
||||||
WHERE user_id = ? AND status IN ('noch-nicht', 'manchmal', 'meistens')
|
ORDER BY ep.updated_at ASC LIMIT 50""",
|
||||||
ORDER BY updated_at ASC LIMIT 50""",
|
(user["id"],)
|
||||||
(user["id"],)
|
).fetchall()
|
||||||
).fetchall()
|
except Exception:
|
||||||
|
joined = []
|
||||||
valid = [r["exercise_id"] for r in raw_progress
|
|
||||||
if any(r["exercise_id"].startswith(p) for p in _KNOWN_PREFIXES)]
|
|
||||||
|
|
||||||
daily_exercise = None
|
daily_exercise = None
|
||||||
if valid:
|
if joined:
|
||||||
ex_id = valid[day_num % len(valid)]
|
row = joined[day_num % len(joined)]
|
||||||
# Tab + Name aus exercise_id ableiten
|
# Tab-ID aus exercise_id ableiten (alles vor erstem '_' + '_')
|
||||||
for prefix in _KNOWN_PREFIXES:
|
ex_id = row["exercise_id"]
|
||||||
if ex_id.startswith(prefix):
|
tab = ex_id.split('_')[0] if '_' in ex_id else ex_id
|
||||||
tab = prefix.rstrip('_')
|
daily_exercise = {
|
||||||
name = ex_id[len(prefix):].replace('_', ' ')
|
"exercise_id": ex_id,
|
||||||
daily_exercise = {"exercise_id": ex_id, "name": name, "kategorie": tab}
|
"name": row["name"],
|
||||||
break
|
"kategorie": tab,
|
||||||
|
"schwierigkeit": row["schwierigkeit"],
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
# Fallback: exercise_progress ohne JOIN (Legacy-IDs ohne Matching in DB)
|
||||||
|
_KNOWN_PREFIXES = (
|
||||||
|
'grundkommandos_', 'tricks_', 'problemverhalten_',
|
||||||
|
'mentale-auslastung_', 'hundesport_', 'koerperpflege_', 'welpe-basics_',
|
||||||
|
)
|
||||||
|
raw = conn.execute(
|
||||||
|
"""SELECT exercise_id FROM exercise_progress
|
||||||
|
WHERE user_id = ? AND status IN ('noch-nicht', 'manchmal', 'meistens')
|
||||||
|
ORDER BY updated_at ASC LIMIT 50""",
|
||||||
|
(user["id"],)
|
||||||
|
).fetchall()
|
||||||
|
valid = [r["exercise_id"] for r in raw
|
||||||
|
if any(r["exercise_id"].startswith(p) for p in _KNOWN_PREFIXES)]
|
||||||
|
if valid:
|
||||||
|
ex_id = valid[day_num % len(valid)]
|
||||||
|
for prefix in _KNOWN_PREFIXES:
|
||||||
|
if ex_id.startswith(prefix):
|
||||||
|
tab = prefix.rstrip('_')
|
||||||
|
name = ex_id[len(prefix):].replace('_', ' ')
|
||||||
|
daily_exercise = {"exercise_id": ex_id, "name": name, "kategorie": tab}
|
||||||
|
break
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"random_photo": random_photo,
|
"random_photo": random_photo,
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ async def get_exercises():
|
||||||
}
|
}
|
||||||
with db() as conn:
|
with db() as conn:
|
||||||
rows = conn.execute("""
|
rows = conn.execute("""
|
||||||
SELECT exercise_id, name, kategorie, schwierigkeit, alter_ab,
|
SELECT exercise_id, js_exercise_id, name, kategorie, schwierigkeit, alter_ab,
|
||||||
dauer, beschreibung, schritte, tipp
|
dauer, beschreibung, schritte, tipp
|
||||||
FROM training_exercises ORDER BY kategorie, name
|
FROM training_exercises ORDER BY kategorie, name
|
||||||
""").fetchall()
|
""").fetchall()
|
||||||
|
|
@ -37,9 +37,10 @@ async def get_exercises():
|
||||||
for r in rows:
|
for r in rows:
|
||||||
tab = CAT_TO_TAB.get(r['kategorie'], r['kategorie'].lower().replace(' ', '-'))
|
tab = CAT_TO_TAB.get(r['kategorie'], r['kategorie'].lower().replace(' ', '-'))
|
||||||
by_tab.setdefault(tab, []).append({
|
by_tab.setdefault(tab, []).append({
|
||||||
'exercise_id': r['exercise_id'],
|
'exercise_id': r['exercise_id'],
|
||||||
'name': r['name'],
|
'js_exercise_id': r['js_exercise_id'],
|
||||||
'kategorie': tab,
|
'name': r['name'],
|
||||||
|
'kategorie': tab,
|
||||||
'schwierigkeit': r['schwierigkeit'] or 'mittel',
|
'schwierigkeit': r['schwierigkeit'] or 'mittel',
|
||||||
'alter': r['alter_ab'],
|
'alter': r['alter_ab'],
|
||||||
'dauer': r['dauer'],
|
'dauer': r['dauer'],
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
Router, State-Management, Navigation, Initialisierung.
|
Router, State-Management, Navigation, Initialisierung.
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
const APP_VER = '484'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
const APP_VER = '485'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||||
|
|
||||||
const App = (() => {
|
const App = (() => {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
Offline-Cache + Push Notifications + Tile-Cache
|
Offline-Cache + Push Notifications + Tile-Cache
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
const CACHE_VERSION = 'by-v507';
|
const CACHE_VERSION = 'by-v508';
|
||||||
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
||||||
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
|
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue