update
This commit is contained in:
@@ -1,14 +1,19 @@
|
||||
"""Was der Seite noch fehlt.
|
||||
|
||||
Jeder darf aufschreiben, was er sich wünscht. Alle sehen alle Wünsche,
|
||||
ändern darf jeder nur die eigenen — wie bei den Filmsammlungen.
|
||||
Jeder darf aufschreiben, was er sich wünscht, und für Wünsche anderer
|
||||
stimmen — eine Stimme je Person. Ergänzungen hängen als Anmerkungen unter
|
||||
dem Wunsch, damit der ursprüngliche Text stehen bleibt und die Diskussion
|
||||
nachvollziehbar ist. Der Host hakt ab, was umgesetzt ist: der Wunsch bleibt
|
||||
sichtbar, rutscht aber ans Ende.
|
||||
|
||||
Ändern darf jeder nur die eigenen, wie bei den Filmsammlungen.
|
||||
"""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from . import users
|
||||
from .db import connect
|
||||
from .users import besitzer, gehoert_mir
|
||||
from .users import WEM, besitzer, gehoert_mir
|
||||
|
||||
SCHEMA = """
|
||||
CREATE TABLE IF NOT EXISTS features (
|
||||
@@ -16,6 +21,28 @@ CREATE TABLE IF NOT EXISTS features (
|
||||
session_id TEXT NOT NULL,
|
||||
user_id INTEGER,
|
||||
text TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
done_at TEXT
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS feature_notes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
feature_id INTEGER NOT NULL,
|
||||
session_id TEXT NOT NULL,
|
||||
user_id INTEGER,
|
||||
text TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
"""
|
||||
|
||||
# Eigenes Statement, weil users.je_person() die Tabelle daraus neu bauen
|
||||
# könnte — hier ohne UNIQUE in der Spaltendefinition, die Eindeutigkeit
|
||||
# kommt aus den Indizes je Person.
|
||||
VOTES_SCHEMA = """
|
||||
CREATE TABLE IF NOT EXISTS feature_votes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
feature_id INTEGER NOT NULL,
|
||||
session_id TEXT NOT NULL,
|
||||
user_id INTEGER,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
"""
|
||||
@@ -23,21 +50,64 @@ CREATE TABLE IF NOT EXISTS features (
|
||||
MAX_LAENGE = 500
|
||||
|
||||
|
||||
def _jetzt():
|
||||
return datetime.now(timezone.utc).isoformat(timespec="seconds")
|
||||
|
||||
|
||||
def init():
|
||||
with connect() as conn:
|
||||
conn.executescript(SCHEMA)
|
||||
conn.executescript(VOTES_SCHEMA)
|
||||
users.user_id_nachruesten(conn, "features")
|
||||
# Die Tabelle stand vor der Spalte schon in bestehenden Datenbanken
|
||||
spalten = {r[1] for r in conn.execute("PRAGMA table_info(features)")}
|
||||
if "done_at" not in spalten:
|
||||
conn.execute("ALTER TABLE features ADD COLUMN done_at TEXT")
|
||||
# Eine Stimme je Person und Wunsch
|
||||
users.je_person(conn, "feature_votes", VOTES_SCHEMA, "feature_id")
|
||||
|
||||
|
||||
def alle(session_id):
|
||||
"""Alle Wünsche, jeder mit dem Namen seines Verfassers."""
|
||||
"""Alle Wünsche: offene nach Stimmen, erledigte dahinter.
|
||||
|
||||
Jeder Wunsch bringt den Namen des Verfassers, die Stimmenzahl, die
|
||||
eigene Stimme und seine Anmerkungen mit.
|
||||
"""
|
||||
ich = besitzer(session_id)
|
||||
with connect() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT f.*, u.name FROM features f "
|
||||
"SELECT f.*, u.name, "
|
||||
" (SELECT COUNT(*) FROM feature_votes v WHERE v.feature_id = f.id) "
|
||||
" AS votes "
|
||||
"FROM features f "
|
||||
"LEFT JOIN users u ON u.id = f.user_id "
|
||||
"ORDER BY f.created_at DESC"
|
||||
"ORDER BY f.done_at IS NOT NULL, votes DESC, f.created_at DESC"
|
||||
).fetchall()
|
||||
ich = besitzer(session_id)
|
||||
meine_stimmen = {
|
||||
r["feature_id"]
|
||||
for r in conn.execute(
|
||||
f"SELECT feature_id FROM feature_votes WHERE {WEM}",
|
||||
(ich, ich, session_id),
|
||||
)
|
||||
}
|
||||
notizen = conn.execute(
|
||||
"SELECT n.*, u.name FROM feature_notes n "
|
||||
"LEFT JOIN users u ON u.id = n.user_id "
|
||||
"ORDER BY n.created_at ASC"
|
||||
).fetchall()
|
||||
|
||||
je_wunsch = {}
|
||||
for n in notizen:
|
||||
je_wunsch.setdefault(n["feature_id"], []).append(
|
||||
{
|
||||
"id": n["id"],
|
||||
"text": n["text"],
|
||||
"name": n["name"],
|
||||
"created_at": n["created_at"],
|
||||
"mine": gehoert_mir(n, session_id, ich),
|
||||
}
|
||||
)
|
||||
|
||||
return [
|
||||
{
|
||||
**{
|
||||
@@ -46,6 +116,8 @@ def alle(session_id):
|
||||
if k not in ("session_id", "user_id")
|
||||
},
|
||||
"mine": gehoert_mir(r, session_id, ich),
|
||||
"voted": r["id"] in meine_stimmen,
|
||||
"notes": je_wunsch.get(r["id"], []),
|
||||
}
|
||||
for r in rows
|
||||
]
|
||||
@@ -60,12 +132,7 @@ def anlegen(session_id, text):
|
||||
conn.execute(
|
||||
"INSERT INTO features (session_id, user_id, text, created_at) "
|
||||
"VALUES (?, ?, ?, ?)",
|
||||
(
|
||||
session_id,
|
||||
besitzer(session_id),
|
||||
text,
|
||||
datetime.now(timezone.utc).isoformat(timespec="seconds"),
|
||||
),
|
||||
(session_id, besitzer(session_id), text, _jetzt()),
|
||||
)
|
||||
return alle(session_id)
|
||||
|
||||
@@ -81,10 +148,73 @@ def aendern(feature_id, text):
|
||||
).rowcount
|
||||
|
||||
|
||||
def erledigen(feature_id, erledigt):
|
||||
"""Der Host hakt ab — oder holt einen Wunsch wieder hervor."""
|
||||
with connect() as conn:
|
||||
return conn.execute(
|
||||
"UPDATE features SET done_at = ? WHERE id = ?",
|
||||
(_jetzt() if erledigt else None, feature_id),
|
||||
).rowcount
|
||||
|
||||
|
||||
def abstimmen(feature_id, session_id):
|
||||
"""Stimme setzen oder zurücknehmen. Gibt None zurück, wenn es den
|
||||
Wunsch nicht gibt, sonst ob die Stimme jetzt steht."""
|
||||
ich = besitzer(session_id)
|
||||
with connect() as conn:
|
||||
weg = conn.execute(
|
||||
f"DELETE FROM feature_votes WHERE feature_id = ? AND {WEM}",
|
||||
(feature_id, ich, ich, session_id),
|
||||
).rowcount
|
||||
if weg:
|
||||
return False
|
||||
da = conn.execute(
|
||||
"SELECT 1 FROM features WHERE id = ?", (feature_id,)
|
||||
).fetchone()
|
||||
if not da:
|
||||
return None
|
||||
conn.execute(
|
||||
"INSERT INTO feature_votes (feature_id, session_id, user_id, created_at) "
|
||||
"VALUES (?, ?, ?, ?)",
|
||||
(feature_id, session_id, ich, _jetzt()),
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
def anmerken(feature_id, session_id, text):
|
||||
"""Eine Ergänzung unter den Wunsch hängen."""
|
||||
text = (text or "").strip()[:MAX_LAENGE]
|
||||
if not text:
|
||||
return False
|
||||
with connect() as conn:
|
||||
da = conn.execute(
|
||||
"SELECT 1 FROM features WHERE id = ?", (feature_id,)
|
||||
).fetchone()
|
||||
if not da:
|
||||
return False
|
||||
conn.execute(
|
||||
"INSERT INTO feature_notes "
|
||||
"(feature_id, session_id, user_id, text, created_at) "
|
||||
"VALUES (?, ?, ?, ?, ?)",
|
||||
(feature_id, session_id, besitzer(session_id), text, _jetzt()),
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
def anmerkung_loeschen(note_id):
|
||||
"""Ohne Sitzungsbindung — den Knopf zeigt die Oberfläche nur dem Host."""
|
||||
with connect() as conn:
|
||||
return conn.execute(
|
||||
"DELETE FROM feature_notes WHERE id = ?", (note_id,)
|
||||
).rowcount
|
||||
|
||||
|
||||
def loeschen(feature_id):
|
||||
"""Ohne Sitzungsbindung — den Knopf zeigt die Oberfläche nur dem
|
||||
Verfasser und dem Host."""
|
||||
Verfasser und dem Host. Stimmen und Anmerkungen gehen mit."""
|
||||
with connect() as conn:
|
||||
conn.execute("DELETE FROM feature_votes WHERE feature_id = ?", (feature_id,))
|
||||
conn.execute("DELETE FROM feature_notes WHERE feature_id = ?", (feature_id,))
|
||||
return conn.execute(
|
||||
"DELETE FROM features WHERE id = ?", (feature_id,)
|
||||
).rowcount
|
||||
|
||||
Reference in New Issue
Block a user