Skip to content

Commit d5aaba6

Browse files
update
1 parent 640f060 commit d5aaba6

2 files changed

Lines changed: 117 additions & 27 deletions

File tree

scripts/capture_trace_excerpt.py

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
START_MARKER = "<!-- TRACE_EXCERPT_START -->"
1212
END_MARKER = "<!-- TRACE_EXCERPT_END -->"
1313
DEFAULT_API_URL = os.environ.get("TRACE_API_URL", "http://localhost:8000")
14+
TRACE_USER_EMAIL = os.environ.get("TRACE_USER_EMAIL", "trace-demo@example.com")
15+
TRACE_USER_PASSWORD = os.environ.get("TRACE_USER_PASSWORD", "tracepass123")
16+
TRACE_USER_NAME = os.environ.get("TRACE_USER_NAME", "Trace Demo")
1417

1518

1619
def run_command(command: list[str], timeout: int = 60, check: bool = True) -> subprocess.CompletedProcess[str]:
@@ -48,20 +51,54 @@ def start_redis_monitor() -> subprocess.Popen[str]:
4851
)
4952

5053

51-
def create_demo_course(base_url: str) -> None:
54+
def get_or_create_token(base_url: str) -> str:
55+
register_payload = {
56+
"email": TRACE_USER_EMAIL,
57+
"password": TRACE_USER_PASSWORD,
58+
"full_name": TRACE_USER_NAME,
59+
}
60+
register_response = requests.post(
61+
f"{base_url}/auth/register",
62+
json=register_payload,
63+
timeout=15,
64+
)
65+
if register_response.status_code == 200:
66+
return register_response.json()["access_token"]
67+
68+
login_payload = {
69+
"email": TRACE_USER_EMAIL,
70+
"password": TRACE_USER_PASSWORD,
71+
}
72+
login_response = requests.post(
73+
f"{base_url}/auth/login",
74+
json=login_payload,
75+
timeout=15,
76+
)
77+
login_response.raise_for_status()
78+
return login_response.json()["access_token"]
79+
80+
81+
def create_demo_course(base_url: str, token: str) -> None:
5282
payload = {
53-
"title": "Trace Demo Course",
83+
"title": f"Trace Demo Course {int(time.time())}",
5484
"content": "Short content created only to exercise Redis-backed flows.",
5585
"is_public": True,
5686
}
57-
response = requests.post(f"{base_url}/courses", json=payload, timeout=15)
87+
response = requests.post(
88+
f"{base_url}/courses",
89+
json=payload,
90+
headers={"Authorization": f"Bearer {token}"},
91+
timeout=15,
92+
)
5893
response.raise_for_status()
5994

6095

61-
def trigger_api_activity(base_url: str) -> None:
96+
def trigger_api_activity(base_url: str, token: str) -> None:
97+
headers = {"Authorization": f"Bearer {token}"}
6298
requests.get(f"{base_url}/courses", timeout=10).raise_for_status()
6399
requests.get(f"{base_url}/courses/shared", timeout=10).raise_for_status()
64-
requests.get(f"{base_url}/courses", timeout=10).raise_for_status()
100+
requests.get(f"{base_url}/me", headers=headers, timeout=10).raise_for_status()
101+
requests.get(f"{base_url}/courses/my", headers=headers, timeout=10).raise_for_status()
65102

66103

67104
def trigger_worker_activity() -> str:
@@ -103,24 +140,21 @@ def tail_lines(text: str, max_lines: int = 40) -> str:
103140

104141
def build_redis_trace_excerpt(base_url: str) -> str:
105142
wait_for_api(base_url)
143+
token = get_or_create_token(base_url)
106144
monitor_process = start_redis_monitor()
107145

108146
try:
109147
time.sleep(2)
110-
create_demo_course(base_url)
111-
trigger_api_activity(base_url)
148+
create_demo_course(base_url, token)
149+
trigger_api_activity(base_url, token)
112150
worker_output = trigger_worker_activity()
113151
time.sleep(2)
114152
finally:
115153
monitor_stdout, monitor_stderr = stop_monitor(monitor_process)
116154

117155
monitor_block = tail_lines(monitor_stdout, max_lines=50)
118156
worker_block = tail_lines(worker_output, max_lines=20)
119-
120-
if monitor_stderr.strip():
121-
stderr_block = tail_lines(monitor_stderr, max_lines=20)
122-
else:
123-
stderr_block = "(empty)"
157+
stderr_block = tail_lines(monitor_stderr, max_lines=20) if monitor_stderr.strip() else "(empty)"
124158

125159
return (
126160
"```text\n"

scripts/demo.sh

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
#!/usr/bin/env bash
22
set -euo pipefail
33

4-
echo "=== EduBuilder Local Demo ==="
4+
API_URL="${TRACE_API_URL:-http://localhost:8000}"
5+
TRACE_USER_EMAIL="${TRACE_USER_EMAIL:-trace-demo@example.com}"
6+
TRACE_USER_PASSWORD="${TRACE_USER_PASSWORD:-tracepass123}"
7+
TRACE_USER_NAME="${TRACE_USER_NAME:-Trace Demo}"
8+
9+
export TRACE_API_URL="$API_URL"
10+
export TRACE_USER_EMAIL
11+
export TRACE_USER_PASSWORD
12+
export TRACE_USER_NAME
13+
14+
echo "=== EduBuilder EX3 Demo ==="
515
echo "1. Stopping any previous local stack..."
616
docker compose down -v >/dev/null 2>&1 || true
717

@@ -10,7 +20,7 @@ docker compose up -d --build
1020

1121
echo "3. Waiting for the API health endpoint..."
1222
for i in {1..30}; do
13-
if curl -fsS http://localhost:8000/health >/dev/null 2>&1; then
23+
if curl -fsS "$API_URL/health" >/dev/null 2>&1; then
1424
echo " API is healthy."
1525
break
1626
fi
@@ -21,26 +31,72 @@ for i in {1..30}; do
2131
fi
2232
done
2333

24-
echo "4. Seeding demo data inside the API container..."
25-
docker compose exec -T api python scripts/seed.py || true
34+
echo "4. Creating a public demo course through the authenticated API..."
35+
uv run python - <<'PY'
36+
import os
37+
import time
2638
27-
echo "5. Health check:"
28-
curl http://localhost:8000/health
29-
echo
39+
import requests
40+
41+
api_url = os.environ["TRACE_API_URL"]
42+
email = os.environ["TRACE_USER_EMAIL"]
43+
password = os.environ["TRACE_USER_PASSWORD"]
44+
full_name = os.environ["TRACE_USER_NAME"]
45+
46+
register = requests.post(
47+
f"{api_url}/auth/register",
48+
json={"email": email, "password": password, "full_name": full_name},
49+
timeout=20,
50+
)
51+
if register.status_code == 200:
52+
token = register.json()["access_token"]
53+
else:
54+
login = requests.post(
55+
f"{api_url}/auth/login",
56+
json={"email": email, "password": password},
57+
timeout=20,
58+
)
59+
login.raise_for_status()
60+
token = login.json()["access_token"]
3061
31-
echo "6. Rate-limit headers check:"
32-
curl -I http://localhost:8000/courses || true
62+
create = requests.post(
63+
f"{api_url}/courses",
64+
json={
65+
"title": f"Weekly Digest Demo {int(time.time())}",
66+
"content": "A short public course used to exercise the weekly digest enhancement.",
67+
"is_public": True,
68+
},
69+
headers={"Authorization": f"Bearer {token}"},
70+
timeout=20,
71+
)
72+
create.raise_for_status()
73+
course = create.json()
74+
print(f"Created course: {course['title']}")
75+
PY
76+
77+
echo "5. Triggering the worker so the weekly digest enhancement runs..."
78+
docker compose run --rm worker python scripts/refresh.py
79+
80+
echo "6. Refreshing the Redis trace excerpt required in docs/EX3-notes.md..."
81+
uv run python scripts/capture_trace_excerpt.py
82+
83+
echo "7. Quick checks:"
84+
curl "$API_URL/health"
85+
echo
86+
curl -I "$API_URL/courses" || true
3387
echo
3488

35-
echo "7. Open these URLs:"
89+
echo "8. Open these URLs:"
3690
echo " Frontend: http://localhost:8501"
3791
echo " API Docs: http://localhost:8000/docs"
3892
echo
3993

40-
echo "8. Suggested seeded users:"
41-
echo " admin@example.com / adminpass123"
42-
echo " user@example.com / userpass123"
94+
echo "9. What this demo already exercised:"
95+
echo " - authenticated course creation"
96+
echo " - public course listing"
97+
echo " - weekly digest worker run"
98+
echo " - Redis-backed trace capture into docs/EX3-notes.md"
4399
echo
44100

45-
echo "9. Showing live logs. Press Ctrl+C to stop log tailing; containers will keep running."
46-
docker compose logs -f
101+
echo "10. Showing recent worker logs. Press Ctrl+C to stop."
102+
docker compose logs --tail=50 -f worker

0 commit comments

Comments
 (0)