Feature: 3 Community-Features — Foto-Challenge, Stamm-Gassis, Rassen-Chip (SW by-v700)
- Foto-Challenge der Woche: DB-Tabellen, routes/challenges.py (current/submit/vote/winners), Scheduler-Job jeden Montag 08:00, walks.js Challenge-Tab mit Banner, Galerie, Voting-Herz - Gassi-Zeiten-Pool: DB-Tabelle gassi_zeiten, routes/gassi_zeiten.py (CRUD + Umkreis), walks.js Stamm-Gassis-Tab mit Karten, Wochentag-Selector, Mitmachen→Chat - Rassen-Treffen-Chip: GET /api/friends/same-breed, dog-profile.js zeigt Chip wenn andere User gleiche Rasse haben, Klick → Forum mit Rassen-Suche vorausgefüllt
This commit is contained in:
parent
d6206d378e
commit
aa4849d947
10 changed files with 1322 additions and 22 deletions
304
backend/routes/challenges.py
Normal file
304
backend/routes/challenges.py
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
"""BAN YARO — Foto-Challenge der Woche"""
|
||||
|
||||
import os
|
||||
import uuid
|
||||
import logging
|
||||
from datetime import date, timedelta
|
||||
from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Form
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
from database import db
|
||||
from auth import get_current_user, get_current_user_optional
|
||||
from media_utils import convert_media, generate_preview
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
MEDIA_DIR = os.getenv("MEDIA_DIR", "/data/media")
|
||||
CHALLENGE_DIR = os.path.join(MEDIA_DIR, "challenges")
|
||||
|
||||
_CHALLENGE_THEMEN = [
|
||||
"Bestes Schnüffel-Foto 👃",
|
||||
"Action-Aufnahme 🏃",
|
||||
"Schlafendes Tier 😴",
|
||||
"Gassi im Regen 🌧️",
|
||||
"Hundeblick in die Kamera 👀",
|
||||
"Spielzeit mit Freunden 🐕",
|
||||
"Herbstspaziergang 🍂",
|
||||
"Beste Sprung-Aufnahme 🦘",
|
||||
"Hund am Wasser 🌊",
|
||||
"Erstes Mal im Schnee ❄️",
|
||||
"Genuss-Moment 🦴",
|
||||
"Versteckt im Gebüsch 🌿",
|
||||
"Tierisches Selfie 🤳",
|
||||
"Hund & Kind 👶",
|
||||
"Hund & Katze zusammen 🐱",
|
||||
"Der beste Buddel-Moment 🐾",
|
||||
"Freude beim Apportieren 🎾",
|
||||
"Hund in seiner Lieblingshöhle 🛋️",
|
||||
"Sonnenuntergangs-Gassi 🌅",
|
||||
"Hundebegegnung auf dem Spaziergang 🐕🐕",
|
||||
"Ausdrucksstarker Hundeblick 😍",
|
||||
"Hund im Herbstlaub 🍁",
|
||||
"Welpenfoto 🍼",
|
||||
"Seniorenhund im Porträt 👴",
|
||||
"Lustigste Schlafposition 💤",
|
||||
"Hund trägt etwas 🎀",
|
||||
"Hund + Besitzer Spiegelfoto 🪞",
|
||||
"Hund auf Abenteuer 🏕️",
|
||||
"Beste Lauf-Action 💨",
|
||||
"Hund im Café ☕",
|
||||
]
|
||||
|
||||
|
||||
def _current_week_monday() -> str:
|
||||
today = date.today()
|
||||
monday = today - timedelta(days=today.weekday())
|
||||
return monday.isoformat()
|
||||
|
||||
|
||||
def _current_week_sunday() -> str:
|
||||
monday = date.fromisoformat(_current_week_monday())
|
||||
return (monday + timedelta(days=6)).isoformat()
|
||||
|
||||
|
||||
def _ensure_current_challenge(conn) -> int:
|
||||
"""Stellt sicher dass eine Challenge für die aktuelle Woche existiert. Gibt die ID zurück."""
|
||||
monday = _current_week_monday()
|
||||
sunday = _current_week_sunday()
|
||||
|
||||
existing = conn.execute(
|
||||
"SELECT id FROM foto_challenge WHERE start_date = ?", (monday,)
|
||||
).fetchone()
|
||||
if existing:
|
||||
return existing["id"]
|
||||
|
||||
# Thema aus Rotation wählen (Wochennummer % Anzahl Themen)
|
||||
week_num = date.today().isocalendar()[1]
|
||||
thema = _CHALLENGE_THEMEN[week_num % len(_CHALLENGE_THEMEN)]
|
||||
|
||||
cur = conn.execute(
|
||||
"INSERT INTO foto_challenge (thema, beschreibung, start_date, end_date, created_by) "
|
||||
"VALUES (?, ?, ?, ?, NULL)",
|
||||
(thema, f"Diese Woche: {thema}", monday, sunday)
|
||||
)
|
||||
return cur.lastrowid
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# GET /api/challenges/current
|
||||
# ------------------------------------------------------------------
|
||||
@router.get("/current")
|
||||
async def get_current_challenge(user=Depends(get_current_user_optional)):
|
||||
with db() as conn:
|
||||
challenge_id = _ensure_current_challenge(conn)
|
||||
challenge = conn.execute(
|
||||
"SELECT * FROM foto_challenge WHERE id = ?", (challenge_id,)
|
||||
).fetchone()
|
||||
|
||||
submissions = conn.execute("""
|
||||
SELECT cs.id, cs.user_id, cs.dog_id, cs.foto_url, cs.caption, cs.votes, cs.created_at,
|
||||
u.name AS user_name, u.avatar_url,
|
||||
d.name AS dog_name, d.foto_url AS dog_foto_url
|
||||
FROM challenge_submissions cs
|
||||
LEFT JOIN users u ON u.id = cs.user_id
|
||||
LEFT JOIN dogs d ON d.id = cs.dog_id
|
||||
WHERE cs.challenge_id = ?
|
||||
ORDER BY cs.votes DESC, cs.created_at ASC
|
||||
""", (challenge_id,)).fetchall()
|
||||
|
||||
my_submission = None
|
||||
my_votes = set()
|
||||
if user:
|
||||
mine = conn.execute(
|
||||
"SELECT id FROM challenge_submissions WHERE challenge_id=? AND user_id=?",
|
||||
(challenge_id, user["id"])
|
||||
).fetchone()
|
||||
if mine:
|
||||
my_submission = mine["id"]
|
||||
voted_rows = conn.execute(
|
||||
"SELECT cv.submission_id FROM challenge_votes cv "
|
||||
"JOIN challenge_submissions cs ON cs.id = cv.submission_id "
|
||||
"WHERE cv.user_id = ? AND cs.challenge_id = ?",
|
||||
(user["id"], challenge_id)
|
||||
).fetchall()
|
||||
my_votes = {r["submission_id"] for r in voted_rows}
|
||||
|
||||
# Countdown bis Sonntag
|
||||
end = date.fromisoformat(challenge["end_date"])
|
||||
days_left = (end - date.today()).days + 1
|
||||
|
||||
result_subs = []
|
||||
for s in submissions:
|
||||
sd = dict(s)
|
||||
sd["i_voted"] = (sd["id"] in my_votes) if user else False
|
||||
result_subs.append(sd)
|
||||
|
||||
return {
|
||||
"challenge": dict(challenge),
|
||||
"submissions": result_subs,
|
||||
"my_submission_id": my_submission,
|
||||
"days_left": max(0, days_left),
|
||||
}
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# POST /api/challenges/{id}/submit
|
||||
# ------------------------------------------------------------------
|
||||
@router.post("/{challenge_id}/submit", status_code=201)
|
||||
async def submit_photo(
|
||||
challenge_id: int,
|
||||
caption: Optional[str] = Form(None),
|
||||
dog_id: Optional[int] = Form(None),
|
||||
foto: UploadFile = File(...),
|
||||
user=Depends(get_current_user),
|
||||
):
|
||||
with db() as conn:
|
||||
challenge = conn.execute(
|
||||
"SELECT * FROM foto_challenge WHERE id = ?", (challenge_id,)
|
||||
).fetchone()
|
||||
if not challenge:
|
||||
raise HTTPException(404, "Challenge nicht gefunden.")
|
||||
|
||||
today = date.today().isoformat()
|
||||
if today > challenge["end_date"]:
|
||||
raise HTTPException(400, "Die Challenge ist bereits beendet.")
|
||||
|
||||
# Doppelt-Check
|
||||
existing = conn.execute(
|
||||
"SELECT id FROM challenge_submissions WHERE challenge_id=? AND user_id=?",
|
||||
(challenge_id, user["id"])
|
||||
).fetchone()
|
||||
if existing:
|
||||
raise HTTPException(409, "Du hast bereits ein Foto eingereicht.")
|
||||
|
||||
# Foto speichern
|
||||
os.makedirs(CHALLENGE_DIR, exist_ok=True)
|
||||
orig_filename = foto.filename or "foto.jpg"
|
||||
ext = os.path.splitext(orig_filename)[1] or ".jpg"
|
||||
base = uuid.uuid4().hex
|
||||
|
||||
raw = await foto.read()
|
||||
|
||||
# HEIC→JPEG Konvertierung falls nötig
|
||||
try:
|
||||
converted, out_ext = convert_media(raw, orig_filename)
|
||||
except Exception:
|
||||
converted, out_ext = raw, ext
|
||||
|
||||
save_filename = f"{base}{out_ext}"
|
||||
save_path = os.path.join(CHALLENGE_DIR, save_filename)
|
||||
with open(save_path, "wb") as f:
|
||||
f.write(converted)
|
||||
foto_url = f"/media/challenges/{save_filename}"
|
||||
|
||||
# Preview
|
||||
try:
|
||||
preview = generate_preview(converted, out_ext)
|
||||
if preview:
|
||||
prev_path = os.path.join(CHALLENGE_DIR, f"{base}_preview.webp")
|
||||
with open(prev_path, "wb") as f:
|
||||
f.write(preview)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
with db() as conn:
|
||||
cur = conn.execute(
|
||||
"INSERT INTO challenge_submissions (challenge_id, user_id, dog_id, foto_url, caption) "
|
||||
"VALUES (?, ?, ?, ?, ?)",
|
||||
(challenge_id, user["id"], dog_id, foto_url, caption)
|
||||
)
|
||||
row = conn.execute("""
|
||||
SELECT cs.*, u.name AS user_name, d.name AS dog_name
|
||||
FROM challenge_submissions cs
|
||||
LEFT JOIN users u ON u.id = cs.user_id
|
||||
LEFT JOIN dogs d ON d.id = cs.dog_id
|
||||
WHERE cs.id = ?
|
||||
""", (cur.lastrowid,)).fetchone()
|
||||
|
||||
return dict(row)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# POST /api/challenges/submissions/{id}/vote — Toggle-Vote
|
||||
# ------------------------------------------------------------------
|
||||
@router.post("/submissions/{submission_id}/vote")
|
||||
async def vote_submission(submission_id: int, user=Depends(get_current_user)):
|
||||
with db() as conn:
|
||||
sub = conn.execute(
|
||||
"SELECT * FROM challenge_submissions WHERE id = ?", (submission_id,)
|
||||
).fetchone()
|
||||
if not sub:
|
||||
raise HTTPException(404, "Einreichung nicht gefunden.")
|
||||
if sub["user_id"] == user["id"]:
|
||||
raise HTTPException(400, "Du kannst nicht für dein eigenes Foto abstimmen.")
|
||||
|
||||
existing = conn.execute(
|
||||
"SELECT id FROM challenge_votes WHERE submission_id=? AND user_id=?",
|
||||
(submission_id, user["id"])
|
||||
).fetchone()
|
||||
|
||||
if existing:
|
||||
# Toggle: Vote entfernen
|
||||
conn.execute(
|
||||
"DELETE FROM challenge_votes WHERE submission_id=? AND user_id=?",
|
||||
(submission_id, user["id"])
|
||||
)
|
||||
conn.execute(
|
||||
"UPDATE challenge_submissions SET votes = MAX(0, votes - 1) WHERE id=?",
|
||||
(submission_id,)
|
||||
)
|
||||
voted = False
|
||||
else:
|
||||
conn.execute(
|
||||
"INSERT INTO challenge_votes (submission_id, user_id) VALUES (?, ?)",
|
||||
(submission_id, user["id"])
|
||||
)
|
||||
conn.execute(
|
||||
"UPDATE challenge_submissions SET votes = votes + 1 WHERE id=?",
|
||||
(submission_id,)
|
||||
)
|
||||
voted = True
|
||||
|
||||
votes = conn.execute(
|
||||
"SELECT votes FROM challenge_submissions WHERE id=?", (submission_id,)
|
||||
).fetchone()["votes"]
|
||||
|
||||
return {"voted": voted, "votes": votes}
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# GET /api/challenges/winners — letzte 4 Gewinner
|
||||
# ------------------------------------------------------------------
|
||||
@router.get("/winners")
|
||||
async def get_winners():
|
||||
with db() as conn:
|
||||
# Vergangene Challenges (ohne aktuelle Woche)
|
||||
monday = _current_week_monday()
|
||||
challenges = conn.execute(
|
||||
"SELECT id, thema, start_date, end_date FROM foto_challenge "
|
||||
"WHERE end_date < ? ORDER BY end_date DESC LIMIT 4",
|
||||
(monday,)
|
||||
).fetchall()
|
||||
|
||||
winners = []
|
||||
for ch in challenges:
|
||||
winner = conn.execute("""
|
||||
SELECT cs.id, cs.user_id, cs.foto_url, cs.caption, cs.votes,
|
||||
u.name AS user_name, u.avatar_url,
|
||||
d.name AS dog_name
|
||||
FROM challenge_submissions cs
|
||||
LEFT JOIN users u ON u.id = cs.user_id
|
||||
LEFT JOIN dogs d ON d.id = cs.dog_id
|
||||
WHERE cs.challenge_id = ?
|
||||
ORDER BY cs.votes DESC, cs.created_at ASC
|
||||
LIMIT 1
|
||||
""", (ch["id"],)).fetchone()
|
||||
|
||||
winners.append({
|
||||
"challenge": dict(ch),
|
||||
"winner": dict(winner) if winner else None,
|
||||
})
|
||||
|
||||
return winners
|
||||
|
|
@ -342,3 +342,56 @@ async def remove_friend(friend_user_id: int, user=Depends(get_current_user)):
|
|||
AND ((requester_id=? AND addressee_id=?) OR (requester_id=? AND addressee_id=?))
|
||||
""", (uid, friend_user_id, friend_user_id, uid))
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# GET /api/friends/same-breed — andere User mit gleicher Rasse
|
||||
# ------------------------------------------------------------------
|
||||
@router.get("/same-breed")
|
||||
async def same_breed(user=Depends(get_current_user)):
|
||||
"""Findet andere User mit Hunden derselben Rasse. Gibt Anzahl + Forum-Suche zurück."""
|
||||
uid = user["id"]
|
||||
with db() as conn:
|
||||
# Rassen des eingeloggten Users
|
||||
my_dogs = conn.execute(
|
||||
"SELECT rasse FROM dogs WHERE user_id=? AND rasse IS NOT NULL AND rasse != ''",
|
||||
(uid,)
|
||||
).fetchall()
|
||||
|
||||
if not my_dogs:
|
||||
return {"count": 0, "rassen": [], "forum_query": None}
|
||||
|
||||
rassen = list({d["rasse"].strip() for d in my_dogs if d["rasse"]})
|
||||
|
||||
# Andere User (nicht ich) die eine dieser Rassen haben
|
||||
ph = ",".join("?" * len(rassen))
|
||||
count_row = conn.execute(f"""
|
||||
SELECT COUNT(DISTINCT d.user_id) AS cnt
|
||||
FROM dogs d
|
||||
WHERE d.user_id != ?
|
||||
AND d.rasse IN ({ph})
|
||||
""", (uid, *rassen)).fetchone()
|
||||
|
||||
count = count_row["cnt"] if count_row else 0
|
||||
|
||||
# Für jede Rasse: wie viele andere User
|
||||
rassen_detail = []
|
||||
for rasse in rassen:
|
||||
n = conn.execute(
|
||||
"SELECT COUNT(DISTINCT user_id) AS cnt FROM dogs "
|
||||
"WHERE user_id != ? AND rasse = ?",
|
||||
(uid, rasse)
|
||||
).fetchone()["cnt"]
|
||||
if n > 0:
|
||||
rassen_detail.append({"rasse": rasse, "count": n})
|
||||
|
||||
rassen_detail.sort(key=lambda x: -x["count"])
|
||||
|
||||
# Forum-Suche-Link für die häufigste Rasse
|
||||
forum_query = rassen_detail[0]["rasse"] if rassen_detail else None
|
||||
|
||||
return {
|
||||
"count": count,
|
||||
"rassen": rassen_detail,
|
||||
"forum_query": forum_query,
|
||||
}
|
||||
|
|
|
|||
190
backend/routes/gassi_zeiten.py
Normal file
190
backend/routes/gassi_zeiten.py
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
"""BAN YARO — Gassi-Zeiten-Pool (regelmäßige Gassi-Zeiten mit Gleichgesinnten)"""
|
||||
|
||||
import json
|
||||
import math
|
||||
import logging
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional, List
|
||||
from database import db
|
||||
from auth import get_current_user
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
def _haversine(lat1, lon1, lat2, lon2):
|
||||
R = 6_371_000
|
||||
p1, p2 = math.radians(lat1), math.radians(lat2)
|
||||
dp = math.radians(lat2 - lat1)
|
||||
dl = math.radians(lon2 - lon1)
|
||||
a = math.sin(dp / 2) ** 2 + math.cos(p1) * math.cos(p2) * math.sin(dl / 2) ** 2
|
||||
return 2 * R * math.asin(math.sqrt(a))
|
||||
|
||||
|
||||
class GassiZeitCreate(BaseModel):
|
||||
dog_id: Optional[int] = None
|
||||
wochentage: List[str] # ["mo", "mi", "fr"]
|
||||
uhrzeit: str # "17:00"
|
||||
ort_name: Optional[str] = None
|
||||
lat: Optional[float] = None
|
||||
lon: Optional[float] = None
|
||||
radius_m: int = 500
|
||||
notiz: Optional[str] = None
|
||||
|
||||
|
||||
class GassiZeitUpdate(BaseModel):
|
||||
aktiv: Optional[int] = None
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# GET /api/gassi-zeiten — alle in der Nähe (oder eigene)
|
||||
# ------------------------------------------------------------------
|
||||
@router.get("")
|
||||
async def list_gassi_zeiten(
|
||||
lat: Optional[float] = None,
|
||||
lon: Optional[float] = None,
|
||||
radius: int = 5000, # Meter
|
||||
nur_eigene: bool = False,
|
||||
user=Depends(get_current_user),
|
||||
):
|
||||
with db() as conn:
|
||||
if nur_eigene:
|
||||
rows = conn.execute("""
|
||||
SELECT gz.*, u.name AS user_name, u.avatar_url,
|
||||
d.name AS dog_name, d.foto_url AS dog_foto_url, d.rasse AS dog_rasse
|
||||
FROM gassi_zeiten gz
|
||||
LEFT JOIN users u ON u.id = gz.user_id
|
||||
LEFT JOIN dogs d ON d.id = gz.dog_id
|
||||
WHERE gz.user_id = ?
|
||||
ORDER BY gz.uhrzeit ASC
|
||||
""", (user["id"],)).fetchall()
|
||||
else:
|
||||
rows = conn.execute("""
|
||||
SELECT gz.*, u.name AS user_name, u.avatar_url,
|
||||
d.name AS dog_name, d.foto_url AS dog_foto_url, d.rasse AS dog_rasse
|
||||
FROM gassi_zeiten gz
|
||||
LEFT JOIN users u ON u.id = gz.user_id
|
||||
LEFT JOIN dogs d ON d.id = gz.dog_id
|
||||
WHERE gz.aktiv = 1
|
||||
ORDER BY gz.uhrzeit ASC
|
||||
""").fetchall()
|
||||
|
||||
result = []
|
||||
for r in rows:
|
||||
d = dict(r)
|
||||
# wochentage JSON parsen
|
||||
try:
|
||||
d["wochentage"] = json.loads(d["wochentage"]) if isinstance(d["wochentage"], str) else d["wochentage"]
|
||||
except Exception:
|
||||
d["wochentage"] = []
|
||||
d["is_mine"] = (d["user_id"] == user["id"])
|
||||
|
||||
# Distanz-Filter
|
||||
if lat is not None and lon is not None and d.get("lat") and d.get("lon"):
|
||||
dist = _haversine(lat, lon, d["lat"], d["lon"])
|
||||
if not nur_eigene and dist > radius:
|
||||
continue
|
||||
d["distance_m"] = int(dist)
|
||||
else:
|
||||
d["distance_m"] = None
|
||||
|
||||
result.append(d)
|
||||
|
||||
# Sortierung: eigene zuerst, dann nach Distanz
|
||||
result.sort(key=lambda x: (0 if x["is_mine"] else 1, x.get("distance_m") or 99999))
|
||||
return result
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# POST /api/gassi-zeiten — eigene Zeit anlegen
|
||||
# ------------------------------------------------------------------
|
||||
@router.post("", status_code=201)
|
||||
async def create_gassi_zeit(data: GassiZeitCreate, user=Depends(get_current_user)):
|
||||
if not data.wochentage:
|
||||
raise HTTPException(400, "Mindestens ein Wochentag muss angegeben werden.")
|
||||
if not data.uhrzeit:
|
||||
raise HTTPException(400, "Uhrzeit muss angegeben werden.")
|
||||
|
||||
wochentage_json = json.dumps(data.wochentage)
|
||||
|
||||
with db() as conn:
|
||||
# Hund-Prüfung
|
||||
if data.dog_id:
|
||||
dog = conn.execute(
|
||||
"SELECT id FROM dogs WHERE id=? AND user_id=?", (data.dog_id, user["id"])
|
||||
).fetchone()
|
||||
if not dog:
|
||||
raise HTTPException(403, "Hund nicht gefunden oder gehört nicht dir.")
|
||||
|
||||
cur = conn.execute("""
|
||||
INSERT INTO gassi_zeiten (user_id, dog_id, wochentage, uhrzeit,
|
||||
ort_name, lat, lon, radius_m, notiz)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""", (user["id"], data.dog_id, wochentage_json, data.uhrzeit,
|
||||
data.ort_name, data.lat, data.lon, data.radius_m, data.notiz))
|
||||
|
||||
row = conn.execute("""
|
||||
SELECT gz.*, u.name AS user_name, d.name AS dog_name, d.foto_url AS dog_foto_url
|
||||
FROM gassi_zeiten gz
|
||||
LEFT JOIN users u ON u.id = gz.user_id
|
||||
LEFT JOIN dogs d ON d.id = gz.dog_id
|
||||
WHERE gz.id = ?
|
||||
""", (cur.lastrowid,)).fetchone()
|
||||
|
||||
result = dict(row)
|
||||
try:
|
||||
result["wochentage"] = json.loads(result["wochentage"])
|
||||
except Exception:
|
||||
pass
|
||||
result["is_mine"] = True
|
||||
return result
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# PATCH /api/gassi-zeiten/{id} — pausieren / aktivieren
|
||||
# ------------------------------------------------------------------
|
||||
@router.patch("/{gz_id}")
|
||||
async def update_gassi_zeit(gz_id: int, data: GassiZeitUpdate, user=Depends(get_current_user)):
|
||||
with db() as conn:
|
||||
gz = conn.execute(
|
||||
"SELECT * FROM gassi_zeiten WHERE id=?", (gz_id,)
|
||||
).fetchone()
|
||||
if not gz:
|
||||
raise HTTPException(404, "Gassi-Zeit nicht gefunden.")
|
||||
if gz["user_id"] != user["id"]:
|
||||
raise HTTPException(403, "Nicht deine Gassi-Zeit.")
|
||||
|
||||
updates = data.model_dump(exclude_none=True)
|
||||
if updates:
|
||||
cols = ", ".join(f"{k} = ?" for k in updates)
|
||||
conn.execute(f"UPDATE gassi_zeiten SET {cols} WHERE id=?", [*updates.values(), gz_id])
|
||||
|
||||
row = conn.execute(
|
||||
"SELECT * FROM gassi_zeiten WHERE id=?", (gz_id,)
|
||||
).fetchone()
|
||||
|
||||
result = dict(row)
|
||||
try:
|
||||
result["wochentage"] = json.loads(result["wochentage"])
|
||||
except Exception:
|
||||
pass
|
||||
result["is_mine"] = True
|
||||
return result
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# DELETE /api/gassi-zeiten/{id}
|
||||
# ------------------------------------------------------------------
|
||||
@router.delete("/{gz_id}", status_code=204)
|
||||
async def delete_gassi_zeit(gz_id: int, user=Depends(get_current_user)):
|
||||
with db() as conn:
|
||||
gz = conn.execute(
|
||||
"SELECT * FROM gassi_zeiten WHERE id=?", (gz_id,)
|
||||
).fetchone()
|
||||
if not gz:
|
||||
raise HTTPException(404, "Gassi-Zeit nicht gefunden.")
|
||||
if gz["user_id"] != user["id"]:
|
||||
raise HTTPException(403, "Nicht deine Gassi-Zeit.")
|
||||
conn.execute("DELETE FROM gassi_zeiten WHERE id=?", (gz_id,))
|
||||
Loading…
Add table
Add a link
Reference in a new issue