Wiki-Foto-System: Gallery-Flow, Community-Fotos, Wiki-Fotos-Badge
- review_submission: Fotos ins gallery/-Verzeichnis statt breeds/ kopieren; foto_url der Rasse nur überschreiben wenn noch keins vorhanden (Erstbild) - Rassen-Detail-API: user_fotos (approved submissions) mitliefern - Rassen-Listen-API: user_foto-Subquery als Fallback wenn foto_url leer - achievements: neue Badge-Kategorie "Wiki-Fotos" (bronze 1, silber 3, gold 10) mit wiki_fotos-Metrik in check_and_award und my_achievements - Badge-Check + Push nach Foto-Approval - wiki.js: Karten-Bild nutzt r.foto_url || r.user_foto - wiki.js: Detail-Ansicht zeigt Community-Foto-Galerie (scrollbar, clickable) - Dockerfile: breeds/gallery + breeds/submissions im Image anlegen - SW by-v366, APP_VER 351
This commit is contained in:
parent
b608d5635f
commit
6064a1d750
6 changed files with 111 additions and 43 deletions
|
|
@ -16,7 +16,8 @@ RUN pip install --no-cache-dir -r requirements.txt
|
||||||
COPY backend/ .
|
COPY backend/ .
|
||||||
|
|
||||||
# Media-Verzeichnis
|
# Media-Verzeichnis
|
||||||
RUN mkdir -p /data/media/dogs /data/media/diary /data/media/poison
|
RUN mkdir -p /data/media/dogs /data/media/diary /data/media/poison \
|
||||||
|
/data/media/breeds/gallery /data/media/breeds/submissions
|
||||||
|
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,18 @@ CATEGORIES = [
|
||||||
("diamant", 365, "Ein ganzes Jahr"),
|
("diamant", 365, "Ein ganzes Jahr"),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "wiki_fotos",
|
||||||
|
"name": "Wiki-Fotos",
|
||||||
|
"emoji": "📸",
|
||||||
|
"metrik": "wiki_fotos",
|
||||||
|
"einheit": " Foto(s)",
|
||||||
|
"stufen": [
|
||||||
|
("bronze", 1, "Erster Klick"),
|
||||||
|
("silber", 3, "Foto-Fan"),
|
||||||
|
("gold", 10, "Wiki-Fotograf"),
|
||||||
|
],
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
# Flat-Liste aller Badge-IDs für DB-Kompatibilität
|
# Flat-Liste aller Badge-IDs für DB-Kompatibilität
|
||||||
|
|
@ -129,19 +141,21 @@ def check_and_award(user_id: int, conn):
|
||||||
COALESCE((SELECT SUM(w.walked_km) FROM route_walks w WHERE w.user_id=?), 0),
|
COALESCE((SELECT SUM(w.walked_km) FROM route_walks w WHERE w.user_id=?), 0),
|
||||||
1) AS total_km,
|
1) AS total_km,
|
||||||
(SELECT COUNT(*) FROM routes r WHERE r.user_id=? AND r.is_valid=1) AS routen,
|
(SELECT COUNT(*) FROM routes r WHERE r.user_id=? AND r.is_valid=1) AS routen,
|
||||||
(SELECT COUNT(*) FROM user_map_pois p WHERE p.user_id=?) AS pois
|
(SELECT COUNT(*) FROM user_map_pois p WHERE p.user_id=?) AS pois,
|
||||||
|
(SELECT COUNT(*) FROM wiki_foto_submissions WHERE user_id=? AND status='approved') AS wiki_fotos
|
||||||
FROM (SELECT 1)
|
FROM (SELECT 1)
|
||||||
""", (user_id, user_id, user_id, user_id)).fetchone()
|
""", (user_id, user_id, user_id, user_id, user_id)).fetchone()
|
||||||
|
|
||||||
streak_row = conn.execute(
|
streak_row = conn.execute(
|
||||||
"SELECT current_streak FROM users WHERE id=?", (user_id,)
|
"SELECT current_streak FROM users WHERE id=?", (user_id,)
|
||||||
).fetchone()
|
).fetchone()
|
||||||
|
|
||||||
metrics = {
|
metrics = {
|
||||||
"total_km": stats["total_km"] if stats else 0,
|
"total_km": stats["total_km"] if stats else 0,
|
||||||
"routen": stats["routen"] if stats else 0,
|
"routen": stats["routen"] if stats else 0,
|
||||||
"pois": stats["pois"] if stats else 0,
|
"pois": stats["pois"] if stats else 0,
|
||||||
"streak": (streak_row["current_streak"] if streak_row else 0),
|
"streak": (streak_row["current_streak"] if streak_row else 0),
|
||||||
|
"wiki_fotos": stats["wiki_fotos"] if stats else 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
earned = {r["badge_id"] for r in
|
earned = {r["badge_id"] for r in
|
||||||
|
|
@ -183,6 +197,7 @@ async def my_achievements(user=Depends(get_current_user)):
|
||||||
1) AS total_km,
|
1) AS total_km,
|
||||||
(SELECT COUNT(*) FROM routes r WHERE r.user_id=? AND r.is_valid=1) AS routen,
|
(SELECT COUNT(*) FROM routes r WHERE r.user_id=? AND r.is_valid=1) AS routen,
|
||||||
(SELECT COUNT(*) FROM user_map_pois p WHERE p.user_id=?) AS pois,
|
(SELECT COUNT(*) FROM user_map_pois p WHERE p.user_id=?) AS pois,
|
||||||
|
(SELECT COUNT(*) FROM wiki_foto_submissions WHERE user_id=? AND status='approved') AS wiki_fotos,
|
||||||
ROUND(
|
ROUND(
|
||||||
COALESCE((SELECT SUM(r.distanz_km) FROM routes r WHERE r.user_id=? AND r.is_valid=1), 0) +
|
COALESCE((SELECT SUM(r.distanz_km) FROM routes r WHERE r.user_id=? AND r.is_valid=1), 0) +
|
||||||
COALESCE((SELECT SUM(w.walked_km) FROM route_walks w WHERE w.user_id=?), 0),
|
COALESCE((SELECT SUM(w.walked_km) FROM route_walks w WHERE w.user_id=?), 0),
|
||||||
|
|
@ -190,7 +205,7 @@ async def my_achievements(user=Depends(get_current_user)):
|
||||||
+ (SELECT COUNT(*) FROM user_map_pois p WHERE p.user_id=?)*5
|
+ (SELECT COUNT(*) FROM user_map_pois p WHERE p.user_id=?)*5
|
||||||
+ (SELECT COUNT(*) FROM routes r WHERE r.user_id=? AND r.is_valid=1)*10 AS punkte
|
+ (SELECT COUNT(*) FROM routes r WHERE r.user_id=? AND r.is_valid=1)*10 AS punkte
|
||||||
FROM (SELECT 1)
|
FROM (SELECT 1)
|
||||||
""", (uid, uid, uid, uid, uid, uid, uid, uid)).fetchone()
|
""", (uid, uid, uid, uid, uid, uid, uid, uid, uid)).fetchone()
|
||||||
|
|
||||||
streak_row = conn.execute(
|
streak_row = conn.execute(
|
||||||
"SELECT current_streak, max_streak FROM users WHERE id=?", (uid,)
|
"SELECT current_streak, max_streak FROM users WHERE id=?", (uid,)
|
||||||
|
|
@ -215,10 +230,11 @@ async def my_achievements(user=Depends(get_current_user)):
|
||||||
""", (stats["punkte"] if stats else 0,)).fetchone()
|
""", (stats["punkte"] if stats else 0,)).fetchone()
|
||||||
|
|
||||||
metrics = {
|
metrics = {
|
||||||
"total_km": stats["total_km"] if stats else 0,
|
"total_km": stats["total_km"] if stats else 0,
|
||||||
"routen": stats["routen"] if stats else 0,
|
"routen": stats["routen"] if stats else 0,
|
||||||
"pois": stats["pois"] if stats else 0,
|
"pois": stats["pois"] if stats else 0,
|
||||||
"streak": (streak_row["current_streak"] if streak_row else 0),
|
"streak": (streak_row["current_streak"] if streak_row else 0),
|
||||||
|
"wiki_fotos": stats["wiki_fotos"] if stats else 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Kategorien mit aktuellem Tier + Fortschritt aufbauen
|
# Kategorien mit aktuellem Tier + Fortschritt aufbauen
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,10 @@ from auth import get_current_user, get_current_user_optional
|
||||||
from ratelimit import check as rl_check, block_ip
|
from ratelimit import check as rl_check, block_ip
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
MEDIA_DIR = os.getenv("MEDIA_DIR", "/data/media")
|
MEDIA_DIR = os.getenv("MEDIA_DIR", "/data/media")
|
||||||
BREEDS_DIR = os.path.join(MEDIA_DIR, "breeds")
|
BREEDS_DIR = os.path.join(MEDIA_DIR, "breeds")
|
||||||
SUBMIT_DIR = os.path.join(BREEDS_DIR, "submissions")
|
SUBMIT_DIR = os.path.join(BREEDS_DIR, "submissions")
|
||||||
|
GALLERY_DIR = os.path.join(BREEDS_DIR, "gallery")
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
@ -119,7 +120,10 @@ async def get_rassen(
|
||||||
with db() as conn:
|
with db() as conn:
|
||||||
rows = conn.execute(f"""
|
rows = conn.execute(f"""
|
||||||
SELECT id, name, gruppe, groesse, aktivitaet, erfahrung,
|
SELECT id, name, gruppe, groesse, aktivitaet, erfahrung,
|
||||||
foto_url, slug, kinder_geeignet, wohnung_geeignet
|
foto_url, slug, kinder_geeignet, wohnung_geeignet,
|
||||||
|
(SELECT s.foto_url FROM wiki_foto_submissions s
|
||||||
|
WHERE s.rasse_id = wiki_rassen.id AND s.status='approved'
|
||||||
|
ORDER BY s.reviewed_at DESC LIMIT 1) AS user_foto
|
||||||
FROM wiki_rassen
|
FROM wiki_rassen
|
||||||
{where}
|
{where}
|
||||||
ORDER BY name ASC
|
ORDER BY name ASC
|
||||||
|
|
@ -166,8 +170,18 @@ async def get_rasse(rasse_slug: str, request: Request):
|
||||||
(rasse_slug,),
|
(rasse_slug,),
|
||||||
).fetchall()
|
).fetchall()
|
||||||
|
|
||||||
|
user_fotos = conn.execute("""
|
||||||
|
SELECT s.foto_url, u.name AS user_name, s.created_at
|
||||||
|
FROM wiki_foto_submissions s
|
||||||
|
JOIN users u ON u.id = s.user_id
|
||||||
|
WHERE s.rasse_id = ? AND s.status = 'approved'
|
||||||
|
ORDER BY s.reviewed_at DESC
|
||||||
|
LIMIT 10
|
||||||
|
""", (rasse["id"],)).fetchall()
|
||||||
|
|
||||||
result = dict(rasse)
|
result = dict(rasse)
|
||||||
result["berichte"] = [dict(r) for r in rows]
|
result["berichte"] = [dict(r) for r in rows]
|
||||||
|
result["user_fotos"] = [dict(r) for r in user_fotos]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -400,47 +414,61 @@ async def review_submission(sub_id: int, data: ReviewModel, user=Depends(get_cur
|
||||||
).fetchone()
|
).fetchone()
|
||||||
|
|
||||||
if data.action == "approve":
|
if data.action == "approve":
|
||||||
# Ziel-Dateiname aus external_id ableiten
|
# Ins gallery-Verzeichnis verschieben
|
||||||
ext_id = rasse["external_id"] if rasse else None
|
os.makedirs(GALLERY_DIR, exist_ok=True)
|
||||||
if ext_id and str(ext_id).startswith("wd_"):
|
src = sub["foto_url"].replace("/media/", MEDIA_DIR + "/", 1)
|
||||||
qid = str(ext_id).replace("wd_", "")
|
dest_name = f"{rasse['slug']}_{sub_id}.jpg"
|
||||||
dest_name = f"{qid}.jpg"
|
dest = os.path.join(GALLERY_DIR, dest_name)
|
||||||
elif ext_id:
|
|
||||||
dest_name = f"{ext_id}.jpg"
|
|
||||||
else:
|
|
||||||
dest_name = f"{rasse['slug']}.jpg"
|
|
||||||
|
|
||||||
os.makedirs(BREEDS_DIR, exist_ok=True)
|
|
||||||
src = sub["foto_url"].replace("/media/", MEDIA_DIR + "/", 1)
|
|
||||||
dest = os.path.join(BREEDS_DIR, dest_name)
|
|
||||||
try:
|
try:
|
||||||
shutil.copy2(src, dest)
|
shutil.copy2(src, dest)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(500, f"Datei konnte nicht kopiert werden: {e}")
|
raise HTTPException(500, f"Datei konnte nicht kopiert werden: {e}")
|
||||||
|
|
||||||
new_url = f"/media/breeds/{dest_name}"
|
new_url = f"/media/breeds/gallery/{dest_name}"
|
||||||
conn.execute(
|
|
||||||
"UPDATE wiki_rassen SET foto_url=? WHERE id=?",
|
# Nur als Hauptbild setzen wenn noch keins vorhanden
|
||||||
(new_url, rasse["id"])
|
if not rasse["foto_url"]:
|
||||||
)
|
conn.execute(
|
||||||
|
"UPDATE wiki_rassen SET foto_url=? WHERE id=?",
|
||||||
|
(new_url, rasse["id"])
|
||||||
|
)
|
||||||
|
|
||||||
conn.execute("""
|
conn.execute("""
|
||||||
UPDATE wiki_foto_submissions
|
UPDATE wiki_foto_submissions
|
||||||
SET status='approved', reviewed_by=?, reviewed_at=datetime('now')
|
SET status='approved', foto_url=?, reviewed_by=?, reviewed_at=datetime('now')
|
||||||
WHERE id=?
|
WHERE id=?
|
||||||
""", (user["id"], sub_id))
|
""", (new_url, user["id"], sub_id))
|
||||||
|
|
||||||
# Push-Notification an Einreicher
|
# Push-Notification an Einreicher
|
||||||
try:
|
try:
|
||||||
from routes.push import send_push_to_user
|
from routes.push import send_push_to_user
|
||||||
send_push_to_user(sub["user_id"], {
|
send_push_to_user(sub["user_id"], {
|
||||||
"title": "Foto freigeschalten!",
|
"title": "Foto freigeschalten!",
|
||||||
"body": f"Dein Foto wurde im Wiki veröffentlicht.",
|
"body": "Dein Foto wurde im Wiki veröffentlicht.",
|
||||||
"type": "wiki_foto_approved",
|
"type": "wiki_foto_approved",
|
||||||
"data": {"page": "wiki"},
|
"data": {"page": "wiki"},
|
||||||
})
|
})
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Badge-Check
|
||||||
|
try:
|
||||||
|
from routes.achievements import check_and_award
|
||||||
|
with db() as conn2:
|
||||||
|
new_badges = check_and_award(sub["user_id"], conn2)
|
||||||
|
if new_badges:
|
||||||
|
try:
|
||||||
|
send_push_to_user(sub["user_id"], {
|
||||||
|
"title": "\U0001f3c5 Neues Badge!",
|
||||||
|
"body": f"Du hast '{new_badges[0]['name']}' verdient!",
|
||||||
|
"type": "badge_earned",
|
||||||
|
"data": {"page": "achievements"},
|
||||||
|
})
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
else: # reject
|
else: # reject
|
||||||
conn.execute("""
|
conn.execute("""
|
||||||
UPDATE wiki_foto_submissions
|
UPDATE wiki_foto_submissions
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
Router, State-Management, Navigation, Initialisierung.
|
Router, State-Management, Navigation, Initialisierung.
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
const APP_VER = '347'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
const APP_VER = '351'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||||
|
|
||||||
const App = (() => {
|
const App = (() => {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -371,10 +371,11 @@ window.Page_wiki = (() => {
|
||||||
const _DOG_SILHOUETTE = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="48" height="48" fill="currentColor" aria-hidden="true"><path d="M200,56H180V48a12,12,0,0,0-24,0v8H132a44,44,0,0,0-43.3,36.3L80,140H60a28,28,0,0,0-28,28v16a12,12,0,0,0,12,12H204a12,12,0,0,0,12-12V100A44.05,44.05,0,0,0,200,56Zm20,128H44V168a4,4,0,0,1,4-4H84.9l4.16-41.57A20,20,0,0,1,108.86,104H156a4,4,0,0,1,0,8H128a4,4,0,0,0,0,8h28a12,12,0,0,0,12-12,11.84,11.84,0,0,0-.1-1.52A20,20,0,0,1,196,124Zm0-60a20,20,0,0,1-7.77,15.82A27.84,27.84,0,0,0,180,132V120a12,12,0,0,1,12-12h16a4,4,0,0,0,4-4V100A20,20,0,0,1,220,124ZM168,48a4,4,0,0,1,8,0V72H168Z"/></svg>`;
|
const _DOG_SILHOUETTE = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="48" height="48" fill="currentColor" aria-hidden="true"><path d="M200,56H180V48a12,12,0,0,0-24,0v8H132a44,44,0,0,0-43.3,36.3L80,140H60a28,28,0,0,0-28,28v16a12,12,0,0,0,12,12H204a12,12,0,0,0,12-12V100A44.05,44.05,0,0,0,200,56Zm20,128H44V168a4,4,0,0,1,4-4H84.9l4.16-41.57A20,20,0,0,1,108.86,104H156a4,4,0,0,1,0,8H128a4,4,0,0,0,0,8h28a12,12,0,0,0,12-12,11.84,11.84,0,0,0-.1-1.52A20,20,0,0,1,196,124Zm0-60a20,20,0,0,1-7.77,15.82A27.84,27.84,0,0,0,180,132V120a12,12,0,0,1,12-12h16a4,4,0,0,0,4-4V100A20,20,0,0,1,220,124ZM168,48a4,4,0,0,1,8,0V72H168Z"/></svg>`;
|
||||||
|
|
||||||
function _breedCardHtml(r) {
|
function _breedCardHtml(r) {
|
||||||
const photoHtml = r.foto_url
|
const fotoUrl = r.foto_url || r.user_foto || '';
|
||||||
? `<img class="wiki-breed-photo" src="${_esc(r.foto_url)}" loading="lazy" alt="${_esc(r.name)}" onerror="this.style.display='none';this.nextElementSibling.style.display='flex'">`
|
const photoHtml = fotoUrl
|
||||||
|
? `<img class="wiki-breed-photo" src="${_esc(fotoUrl)}" loading="lazy" alt="${_esc(r.name)}" onerror="this.style.display='none';this.nextElementSibling.style.display='flex'">`
|
||||||
: '';
|
: '';
|
||||||
const fallbackHtml = `<div class="wiki-breed-photo-fallback" style="${r.foto_url ? 'display:none' : ''}">${_DOG_SILHOUETTE}</div>`;
|
const fallbackHtml = `<div class="wiki-breed-photo-fallback" style="${fotoUrl ? 'display:none' : ''}">${_DOG_SILHOUETTE}</div>`;
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="wiki-breed-card" data-slug="${_esc(r.slug)}">
|
<div class="wiki-breed-card" data-slug="${_esc(r.slug)}">
|
||||||
|
|
@ -727,10 +728,32 @@ window.Page_wiki = (() => {
|
||||||
|
|
||||||
const berichteHtml = _renderBerichteHtml(rasse.berichte || [], slug);
|
const berichteHtml = _renderBerichteHtml(rasse.berichte || [], slug);
|
||||||
|
|
||||||
|
const userFotosHtml = (rasse.user_fotos || []).length
|
||||||
|
? `<div style="margin-top:var(--space-3)">
|
||||||
|
<div style="font-size:var(--text-xs);color:var(--c-text-muted);
|
||||||
|
font-weight:700;text-transform:uppercase;letter-spacing:.05em;
|
||||||
|
margin-bottom:var(--space-2)">📸 Community-Fotos</div>
|
||||||
|
<div style="display:flex;gap:var(--space-2);overflow-x:auto;padding-bottom:4px">
|
||||||
|
${rasse.user_fotos.map(f => `
|
||||||
|
<div style="flex-shrink:0">
|
||||||
|
<img src="${_esc(f.foto_url)}" alt="${_esc(f.user_name)}"
|
||||||
|
style="height:80px;width:80px;object-fit:cover;
|
||||||
|
border-radius:var(--radius-md);cursor:pointer"
|
||||||
|
onclick="document.querySelector('.wiki-detail-photo')?.setAttribute('src','${_esc(f.foto_url)}')">
|
||||||
|
<div style="font-size:9px;color:var(--c-text-muted);text-align:center;
|
||||||
|
margin-top:2px;max-width:80px;overflow:hidden;text-overflow:ellipsis;
|
||||||
|
white-space:nowrap">von ${_esc(f.user_name)}</div>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
: '';
|
||||||
|
|
||||||
const body = `
|
const body = `
|
||||||
${/* 1. Hero */ ''}
|
${/* 1. Hero */ ''}
|
||||||
<div class="wiki-detail-hero" style="text-align:center;margin-bottom:var(--space-4)">
|
<div class="wiki-detail-hero" style="text-align:center;margin-bottom:var(--space-4)">
|
||||||
${photoHtml}
|
${photoHtml}
|
||||||
|
${userFotosHtml}
|
||||||
<h1 style="font-size:var(--text-xl);font-weight:var(--weight-bold);margin:var(--space-2) 0 var(--space-1)">${_esc(rasse.name)}</h1>
|
<h1 style="font-size:var(--text-xl);font-weight:var(--weight-bold);margin:var(--space-2) 0 var(--space-1)">${_esc(rasse.name)}</h1>
|
||||||
${rasse.herkunft ? `<div style="font-size:var(--text-sm);color:var(--c-text-secondary)">${UI.icon('map-pin')} ${_esc(rasse.herkunft)}</div>` : ''}
|
${rasse.herkunft ? `<div style="font-size:var(--text-sm);color:var(--c-text-secondary)">${UI.icon('map-pin')} ${_esc(rasse.herkunft)}</div>` : ''}
|
||||||
${rasse.gruppe ? `<div style="font-size:var(--text-sm);color:var(--c-text-muted);margin-top:2px">${_esc(rasse.gruppe)}</div>` : ''}
|
${rasse.gruppe ? `<div style="font-size:var(--text-sm);color:var(--c-text-muted);margin-top:2px">${_esc(rasse.gruppe)}</div>` : ''}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
Offline-Cache + Push Notifications + Tile-Cache
|
Offline-Cache + Push Notifications + Tile-Cache
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
const CACHE_VERSION = 'by-v365';
|
const CACHE_VERSION = 'by-v366';
|
||||||
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