#!/usr/bin/env bash # # Seed a fresh calrs instance with realistic data for taking screenshots. # Usage: # cargo build --release # ./seed_screenshots.sh # ./target/release/calrs serve --port 3000 --data-dir /tmp/calrs-screenshots # # Then open http://localhost:3000 and take screenshots. # Login: alice@example.com / password123 # set -euo pipefail CALRS="./target/release/calrs" DATA_DIR="/tmp/calrs-screenshots" DB="$DATA_DIR/calrs.db" PORT=39876 mkdir -p "$DATA_DIR" rm -f "$DB" # Helper: run SQL via python3 (no sqlite3 CLI needed) sql() { python3 -c "import sqlite3,sys; c=sqlite3.connect('$DB'); c.execute(sys.argv[1]); c.commit()" "$1"; } sql_val() { python3 -c "import sqlite3,sys; c=sqlite3.connect('$DB'); print(c.execute(sys.argv[1]).fetchone()[0])" "$1"; } echo "=== Seeding calrs for screenshots ===" # ── Start server, register users via HTTP, then stop ────────────────── echo "[1/7] Registering users..." $CALRS serve --port $PORT --data-dir "$DATA_DIR" & SERVE_PID=$! sleep 2 BASE="http://localhost:$PORT" COOKIE_JAR="/tmp/calrs-seed-cookies.txt" register_user() { local name="$1" email="$2" password="$3" rm -f "$COOKIE_JAR" curl -s -c "$COOKIE_JAR" -b "$COOKIE_JAR" "$BASE/auth/register" > /dev/null local csrf csrf=$(grep calrs_csrf "$COOKIE_JAR" | tail -1 | awk '{print $NF}') local encoded_name encoded_name=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$name'))") curl -s -o /dev/null -c "$COOKIE_JAR" -b "$COOKIE_JAR" \ -d "_csrf=$csrf&name=$encoded_name&email=$email&password=$password" \ "$BASE/auth/register" } register_user "Alice Martin" "alice@example.com" "password123" register_user "Bob Chen" "bob@example.com" "password123" register_user "Carol Davis" "carol@example.com" "password123" kill $SERVE_PID 2>/dev/null || true wait $SERVE_PID 2>/dev/null || true # ── Set usernames and profiles ──────────────────────────────────────── echo "[2/7] Setting up profiles..." sql "UPDATE users SET username = 'alice', title = 'Engineering Lead', bio = 'Building great products. Based in Paris.' WHERE email = 'alice@example.com'" sql "UPDATE users SET username = 'bob', title = 'Product Designer' WHERE email = 'bob@example.com'" sql "UPDATE users SET username = 'carol', title = 'Sales Manager' WHERE email = 'carol@example.com'" # ── Get IDs ─────────────────────────────────────────────────────────── ALICE_ID=$(sql_val "SELECT id FROM users WHERE email = 'alice@example.com'") BOB_ID=$(sql_val "SELECT id FROM users WHERE email = 'bob@example.com'") CAROL_ID=$(sql_val "SELECT id FROM users WHERE email = 'carol@example.com'") ALICE_ACCT=$(sql_val "SELECT id FROM accounts WHERE user_id = '$ALICE_ID'") BOB_ACCT=$(sql_val "SELECT id FROM accounts WHERE user_id = '$BOB_ID'") # ── Seed all data via a single python3 script ───────────────────────── echo "[3/7] Creating event types, bookings, team links..." python3 << PYEOF import sqlite3, uuid, datetime db = sqlite3.connect("$DB") c = db.cursor() def uid(): return str(uuid.uuid4()) today = datetime.date.today() def future(days): return (today + datetime.timedelta(days=days)).isoformat() ALICE_ID = "$ALICE_ID" BOB_ID = "$BOB_ID" CAROL_ID = "$CAROL_ID" ALICE_ACCT = "$ALICE_ACCT" BOB_ACCT = "$BOB_ACCT" # ── Event types ─────────────────────────────────────────────────────── et1 = uid() # 30-min intro et2 = uid() # 60-min deep dive (requires confirmation) et3 = uid() # 15-min quick chat et4 = uid() # VIP demo (private) et5 = uid() # disabled et_bob = uid() c.execute("INSERT INTO event_types (id, account_id, slug, title, description, duration_min, buffer_before, buffer_after, min_notice_min, enabled, location_type, location_value, requires_confirmation, reminder_minutes) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)", (et1, ALICE_ACCT, "intro", "30-Minute Intro Call", "A quick intro call to discuss your needs and see if we are a good fit.", 30, 5, 5, 60, 1, "link", "https://meet.example.com/alice", 0, 60)) c.execute("INSERT INTO event_types (id, account_id, slug, title, description, duration_min, buffer_before, buffer_after, min_notice_min, enabled, location_type, location_value, requires_confirmation, reminder_minutes, max_additional_guests) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", (et2, ALICE_ACCT, "deep-dive", "60-Minute Deep Dive", "In-depth technical discussion. Please share context in the notes.", 60, 10, 10, 120, 1, "link", "https://meet.example.com/alice-dd", 1, 1440, 3)) c.execute("INSERT INTO event_types (id, account_id, slug, title, duration_min, buffer_before, buffer_after, min_notice_min, enabled, location_type, location_value) VALUES (?,?,?,?,?,?,?,?,?,?,?)", (et3, ALICE_ACCT, "quick-chat", "15-Minute Quick Chat", 15, 0, 5, 30, 1, "phone", "+33 6 12 34 56 78")) c.execute("INSERT INTO event_types (id, account_id, slug, title, description, duration_min, buffer_before, buffer_after, min_notice_min, enabled, location_type, location_value, is_private, requires_confirmation) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)", (et4, ALICE_ACCT, "vip-demo", "VIP Product Demo", "Exclusive demo for selected prospects.", 45, 10, 10, 240, 1, "link", "https://meet.example.com/vip", 1, 1)) c.execute("INSERT INTO event_types (id, account_id, slug, title, duration_min, enabled) VALUES (?,?,?,?,?,?)", (et5, ALICE_ACCT, "old-meeting", "Old Meeting Type", 30, 0)) c.execute("INSERT INTO event_types (id, account_id, slug, title, description, duration_min, buffer_before, buffer_after, min_notice_min, enabled, location_type, location_value) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", (et_bob, BOB_ACCT, "design-review", "Design Review", "Review your designs and get feedback.", 45, 5, 5, 60, 1, "link", "https://meet.example.com/bob")) # ── Availability rules (Mon-Fri 09:00-12:00, 14:00-18:00) ──────────── for et in [et1, et2, et3, et4, et5, et_bob]: for day in [1, 2, 3, 4, 5]: c.execute("INSERT INTO availability_rules (id, event_type_id, day_of_week, start_time, end_time) VALUES (?,?,?,?,?)", (uid(), et, day, "09:00", "12:00")) c.execute("INSERT INTO availability_rules (id, event_type_id, day_of_week, start_time, end_time) VALUES (?,?,?,?,?)", (uid(), et, day, "14:00", "18:00")) # ── Confirmed bookings ─────────────────────────────────────────────── guests = [ (1, "David Park", "david@startup.io", "10:00", "10:30", et1), (2, "Emma Wilson", "emma@design.co", "14:00", "15:00", et2), (3, "Frank Mueller", "frank@company.de", "11:00", "11:30", et1), (5, "Grace Kim", "grace@agency.kr", "09:00", "09:15", et3), (7, "Hiro Tanaka", "hiro@tech.jp", "16:00", "16:30", et1), ] for days_ahead, name, email, t_start, t_end, et in guests: d = future(days_ahead) bid = uid() c.execute("INSERT INTO bookings (id, event_type_id, uid, guest_name, guest_email, guest_timezone, start_at, end_at, status, cancel_token, reschedule_token) VALUES (?,?,?,?,?,?,?,?,?,?,?)", (bid, et, f"{bid}@calrs", name, email, "UTC", f"{d}T{t_start}:00", f"{d}T{t_end}:00", "confirmed", uid(), uid())) # ── Pending bookings ───────────────────────────────────────────────── for days_ahead, name, email in [(2, "Ines Garcia", "ines@consulting.es"), (4, "Jake Thompson", "jake@venture.vc")]: d = future(days_ahead) bid = uid() c.execute("INSERT INTO bookings (id, event_type_id, uid, guest_name, guest_email, guest_timezone, start_at, end_at, status, cancel_token, reschedule_token, confirm_token, notes) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", (bid, et2, f"{bid}@calrs", name, email, "Europe/Paris", f"{d}T15:00:00", f"{d}T16:00:00", "pending", uid(), uid(), uid(), "Would love to discuss the enterprise plan.")) # ── Team links ──────────────────────────────────────────────────────── tl1 = uid() tl1_token = uid() c.execute("INSERT INTO team_links (id, token, title, duration_min, created_by_user_id, description, location_type, location_value) VALUES (?,?,?,?,?,?,?,?)", (tl1, tl1_token, "Product Sync", 30, ALICE_ID, "Weekly product sync with the team", "link", "https://meet.example.com/product")) c.execute("INSERT INTO team_link_members (id, team_link_id, user_id) VALUES (?,?,?)", (uid(), tl1, ALICE_ID)) c.execute("INSERT INTO team_link_members (id, team_link_id, user_id) VALUES (?,?,?)", (uid(), tl1, BOB_ID)) tl2 = uid() tl2_token = uid() c.execute("INSERT INTO team_links (id, token, title, duration_min, created_by_user_id, description, one_time_use) VALUES (?,?,?,?,?,?,?)", (tl2, tl2_token, "Hiring Interview", 60, ALICE_ID, "Technical interview — all panelists must be free", 1)) c.execute("INSERT INTO team_link_members (id, team_link_id, user_id) VALUES (?,?,?)", (uid(), tl2, ALICE_ID)) c.execute("INSERT INTO team_link_members (id, team_link_id, user_id) VALUES (?,?,?)", (uid(), tl2, BOB_ID)) c.execute("INSERT INTO team_link_members (id, team_link_id, user_id) VALUES (?,?,?)", (uid(), tl2, CAROL_ID)) # Team link booking d3 = future(3) tlb = uid() c.execute("INSERT INTO team_link_bookings (id, team_link_id, uid, guest_name, guest_email, guest_timezone, start_at, end_at, status, cancel_token) VALUES (?,?,?,?,?,?,?,?,?,?)", (tlb, tl1, f"{tlb}@calrs", "Lisa Wang", "lisa@partner.com", "Asia/Shanghai", f"{d3}T10:00:00", f"{d3}T10:30:00", "confirmed", uid())) # ── Invite for private event type ───────────────────────────────────── c.execute("INSERT INTO booking_invites (id, event_type_id, token, guest_name, guest_email, message, max_uses, used_count, created_by_user_id) VALUES (?,?,?,?,?,?,?,?,?)", (uid(), et4, uid(), "Sam Rivera", "sam@enterprise.com", "Hi Sam, here is your exclusive demo link!", 1, 0, ALICE_ID)) # ── Fake CalDAV sources ────────────────────────────────────────────── src1 = uid() src2 = uid() c.execute("INSERT INTO caldav_sources (id, account_id, name, url, username, password_enc, enabled, last_synced, write_calendar_href) VALUES (?,?,?,?,?,?,?,datetime('now', '-2 minutes'),?)", (src1, ALICE_ACCT, "Nextcloud", "https://cloud.example.com/remote.php/dav", "alice", "0000", 1, "/remote.php/dav/calendars/alice/personal/")) c.execute("INSERT INTO caldav_sources (id, account_id, name, url, username, password_enc, enabled, last_synced) VALUES (?,?,?,?,?,?,?,datetime('now', '-1 hour'))", (src2, ALICE_ACCT, "Google Calendar", "https://apidata.googleusercontent.com/caldav/v2/alice@gmail.com/", "alice@gmail.com", "0000", 1)) # Calendars cal1 = uid() cal2 = uid() cal3 = uid() c.execute("INSERT INTO calendars (id, source_id, href, display_name, is_busy) VALUES (?,?,?,?,?)", (cal1, src1, "/calendars/alice/personal/", "Personal", 1)) c.execute("INSERT INTO calendars (id, source_id, href, display_name, is_busy) VALUES (?,?,?,?,?)", (cal2, src1, "/calendars/alice/work/", "Work", 1)) c.execute("INSERT INTO calendars (id, source_id, href, display_name, is_busy) VALUES (?,?,?,?,?)", (cal3, src2, "/calendars/alice@gmail.com/events/", "Google Events", 0)) # ── Calendar events (busy times for troubleshoot) ───────────────────── for i in range(1, 6): d = future(i) eid = uid() c.execute("INSERT INTO events (id, calendar_id, uid, summary, start_at, end_at, raw_ical, etag, all_day, status) VALUES (?,?,?,?,?,?,?,?,?,?)", (eid, cal2, f"{eid}@nextcloud", "Team Standup", f"{d}T09:30:00", f"{d}T10:00:00", "BEGIN:VCALENDAR\r\nEND:VCALENDAR", f"etag-{i}", 0, "CONFIRMED")) d2 = future(2) c.execute("INSERT INTO events (id, calendar_id, uid, summary, start_at, end_at, raw_ical, etag, all_day, status) VALUES (?,?,?,?,?,?,?,?,?,?)", (uid(), cal1, f"{uid()}@nextcloud", "Lunch with Sarah", f"{d2}T12:00:00", f"{d2}T13:30:00", "BEGIN:VCALENDAR\r\nEND:VCALENDAR", "etag-lunch", 0, "CONFIRMED")) # Print event type ID for troubleshoot URL print(f"ET1_ID={et1}") db.commit() db.close() PYEOF echo "[4/7] Done seeding data." echo "" echo "=== Ready! ===" echo "" echo "Login credentials:" echo " alice@example.com / password123 (admin)" echo " bob@example.com / password123" echo " carol@example.com / password123" echo "" echo "Start the server:" echo " $CALRS serve --port 3000 --data-dir $DATA_DIR" echo "" echo "Then visit http://localhost:3000 and take screenshots." echo "" echo "Pages to screenshot:" echo " Dashboard overview http://localhost:3000/dashboard" echo " Event types http://localhost:3000/dashboard/event-types" echo " Bookings http://localhost:3000/dashboard/bookings" echo " Calendar sources http://localhost:3000/dashboard/sources" echo " Team links http://localhost:3000/dashboard/team-links" echo " Admin panel http://localhost:3000/dashboard/admin" echo " Profile & Settings http://localhost:3000/dashboard/settings" echo " Public profile http://localhost:3000/u/alice" echo " Slot picker http://localhost:3000/u/alice/intro" echo " Login page http://localhost:3000/auth/login (sign out first)" echo " Reschedule Click 'Reschedule' on a booking in dashboard" echo " Light mode Toggle theme in settings, retake key pages" echo " Mobile Resize browser to 375px width"