feat: memo generation with filtering and sorting

This commit is contained in:
Oliver Hofmann 2026-05-16 17:17:44 +02:00
parent 239654767a
commit 08db8b8fb1
2 changed files with 134 additions and 0 deletions

49
src/teampulse/memo.py Normal file
View File

@ -0,0 +1,49 @@
from datetime import datetime
from pathlib import Path
from teampulse.models import AuditWindow
def generate_memo(window: AuditWindow) -> str:
filtered = [
e for e in window.entries
if e.display_name != window.presenter and e.display_name != window.moderator
]
sorted_entries = sorted(filtered, key=lambda e: e.email)
start = window.start_time.strftime("%H:%M:%S")
end = window.end_time.strftime("%H:%M:%S")
lines = [
"# Meeting Chat Audit",
f"Zeitfenster: {start} {end}",
"",
]
if not sorted_entries:
lines += [
f"## Teilnehmer am Vortrag von {window.presenter} (0)",
f"_Moderator: {window.moderator} — Vortragender und Moderator ausgeschlossen_",
"",
"_Keine Chat-Aktivität in diesem Zeitfenster._",
]
else:
lines += [
f"## Teilnehmer am Vortrag von {window.presenter} ({len(sorted_entries)})",
f"_Moderator: {window.moderator} — Vortragender und Moderator ausgeschlossen_",
"",
]
for entry in sorted_entries:
lines.append(f"- {entry.display_name} <{entry.email}>")
created = datetime.now().strftime("%Y-%m-%d %H:%M")
lines += ["", f"_Sortiert nach E-Mail-Adresse. Erstellt: {created}_"]
return "\n".join(lines)
def save_memo(content: str, directory: Path = Path("."), timestamp: datetime | None = None) -> Path:
ts = timestamp or datetime.now()
filename = f"audit_{ts.strftime('%Y%m%d_%H%M')}.md"
path = directory / filename
path.write_text(content, encoding="utf-8")
return path

85
tests/test_memo.py Normal file
View File

@ -0,0 +1,85 @@
from datetime import datetime
from pathlib import Path
import pytest
from teampulse.memo import generate_memo, save_memo
from teampulse.models import AuditEntry, AuditWindow
def make_window(**kwargs):
defaults = dict(
presenter="Anna Bauer",
moderator="Oliver Hofmann",
start_time=datetime(2026, 5, 16, 10, 3, 42),
end_time=datetime(2026, 5, 16, 10, 47, 15),
entries=[
AuditEntry("Thomas Wolf", "t.wolf@company.com"),
AuditEntry("Klaus Huber", "k.huber@company.com"),
AuditEntry("Sandra Vogel", "s.vogel@company.com"),
],
)
defaults.update(kwargs)
return AuditWindow(**defaults)
def test_memo_contains_presenter_name():
result = generate_memo(make_window())
assert "Anna Bauer" in result
def test_memo_contains_time_window():
result = generate_memo(make_window())
assert "10:03:42" in result
assert "10:47:15" in result
def test_memo_sorts_entries_by_email():
result = generate_memo(make_window())
idx_huber = result.index("k.huber@company.com")
idx_vogel = result.index("s.vogel@company.com")
idx_wolf = result.index("t.wolf@company.com")
assert idx_huber < idx_vogel < idx_wolf
def test_memo_excludes_presenter():
window = make_window(
entries=[
AuditEntry("Anna Bauer", "a.bauer@company.com"),
AuditEntry("Klaus Huber", "k.huber@company.com"),
]
)
result = generate_memo(window)
assert "a.bauer@company.com" not in result
assert "k.huber@company.com" in result
def test_memo_excludes_moderator():
window = make_window(
entries=[
AuditEntry("Oliver Hofmann", "o.hofmann@company.com"),
AuditEntry("Klaus Huber", "k.huber@company.com"),
]
)
result = generate_memo(window)
assert "o.hofmann@company.com" not in result
assert "k.huber@company.com" in result
def test_memo_empty_window():
window = make_window(entries=[])
result = generate_memo(window)
assert "Keine Chat-Aktivität" in result
def test_memo_contains_moderator_note():
result = generate_memo(make_window())
assert "Oliver Hofmann" in result
def test_save_memo_writes_file(tmp_path):
window = make_window()
path = save_memo(generate_memo(window), directory=tmp_path, timestamp=datetime(2026, 5, 16, 10, 51))
assert path.exists()
assert path.name == "audit_20260516_1051.md"
assert "Anna Bauer" in path.read_text()