From d23ed1831aec806984a4afb6a1711435f9261ccd Mon Sep 17 00:00:00 2001 From: Stephen Adamson Date: Thu, 28 May 2026 16:33:31 +0100 Subject: [PATCH] chore: update init scripts, dev script, and remove stale HAR file Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- init-scripts/init-script.sql | 99 ++++++++++++++++++++ local-dev-2.sh | 35 +++++-- reserve.har | 176 ----------------------------------- 3 files changed, 124 insertions(+), 186 deletions(-) delete mode 100644 reserve.har diff --git a/init-scripts/init-script.sql b/init-scripts/init-script.sql index b94f93a..d8d66fe 100644 --- a/init-scripts/init-script.sql +++ b/init-scripts/init-script.sql @@ -1385,6 +1385,105 @@ CREATE TABLE square_deposits ( CREATE INDEX idx_square_deposits_deposited ON square_deposits(deposited_at); +-- ======================================= +-- CARDDAV / CALDAV TABLES (used by SabreDAV sync in Go backend) +-- ======================================= + +CREATE TABLE IF NOT EXISTS dav_principals ( + id SERIAL PRIMARY KEY, + uri VARCHAR(255) NOT NULL UNIQUE, + email VARCHAR(255), + displayname VARCHAR(255) +); + +CREATE TABLE IF NOT EXISTS dav_calendars ( + id SERIAL PRIMARY KEY, + principaluri VARCHAR(255) NOT NULL, + displayname VARCHAR(255), + uri VARCHAR(255) NOT NULL, + description TEXT, + calendarorder INT DEFAULT 0, + calendarcolor VARCHAR(10), + timezone TEXT, + components VARCHAR(255), + transparent BOOLEAN DEFAULT FALSE, + UNIQUE(principaluri, uri) +); + +CREATE TABLE IF NOT EXISTS dav_calendarobjects ( + id SERIAL PRIMARY KEY, + calendardata TEXT, + uri VARCHAR(255) NOT NULL, + calendarid INTEGER NOT NULL REFERENCES dav_calendars(id) ON DELETE CASCADE, + lastmodified INTEGER, + etag VARCHAR(32), + size INTEGER, + componenttype VARCHAR(8), + firstoccurence INTEGER, + lastoccurence INTEGER, + uid VARCHAR(255), + UNIQUE(calendarid, uri) +); + +CREATE TABLE IF NOT EXISTS dav_addressbooks ( + id SERIAL PRIMARY KEY, + principaluri VARCHAR(255) NOT NULL, + displayname VARCHAR(255), + uri VARCHAR(255) NOT NULL, + description TEXT, + synctoken INTEGER DEFAULT 1, + UNIQUE(principaluri, uri) +); + +CREATE TABLE IF NOT EXISTS dav_cards ( + id SERIAL PRIMARY KEY, + addressbookid INTEGER NOT NULL REFERENCES dav_addressbooks(id) ON DELETE CASCADE, + carddata TEXT, + uri VARCHAR(255) NOT NULL, + lastmodified INTEGER, + etag VARCHAR(32), + size INTEGER, + UNIQUE(addressbookid, uri) +); + +CREATE TABLE IF NOT EXISTS dav_addressbookchanges ( + id SERIAL PRIMARY KEY, + uri VARCHAR(255) NOT NULL, + synctoken INTEGER NOT NULL, + addressbookid INTEGER NOT NULL REFERENCES dav_addressbooks(id) ON DELETE CASCADE, + operation SMALLINT NOT NULL +); + +CREATE TABLE IF NOT EXISTS dav_calendarchanges ( + id SERIAL PRIMARY KEY, + uri VARCHAR(255) NOT NULL, + synctoken INTEGER NOT NULL, + calendarid INTEGER NOT NULL REFERENCES dav_calendars(id) ON DELETE CASCADE, + operation SMALLINT NOT NULL +); + +CREATE TABLE IF NOT EXISTS dav_users ( + id SERIAL PRIMARY KEY, + username VARCHAR(255) NOT NULL UNIQUE, + digesta1 VARCHAR(32) NOT NULL +); + +CREATE INDEX IF NOT EXISTS idx_calendarobjects_calendarid ON dav_calendarobjects(calendarid); +CREATE INDEX IF NOT EXISTS idx_cards_addressbookid ON dav_cards(addressbookid); + +-- Seed default principal, addressbook, and calendar for CardDAV/CalDAV sync +INSERT INTO dav_principals (uri, email, displayname) +SELECT 'principals/default', 'admin@example.com', 'Default User' +WHERE NOT EXISTS (SELECT 1 FROM dav_principals WHERE uri = 'principals/default'); + +INSERT INTO dav_addressbooks (principaluri, displayname, uri, description, synctoken) +SELECT 'principals/default', 'Contacts', 'default', 'Default address book', 1 +WHERE NOT EXISTS (SELECT 1 FROM dav_addressbooks WHERE uri = 'default'); + +INSERT INTO dav_calendars (principaluri, displayname, uri, description, components, transparent) +SELECT 'principals/default', 'Default Calendar', 'default', 'Default calendar', 'VEVENT,VTODO', false +WHERE NOT EXISTS (SELECT 1 FROM dav_calendars WHERE uri = 'default'); + -- ======================================= -- FUNCTION USAGE SUMMARY -- ======================================= diff --git a/local-dev-2.sh b/local-dev-2.sh index 23b7ec2..030a0a8 100755 --- a/local-dev-2.sh +++ b/local-dev-2.sh @@ -398,14 +398,15 @@ get_svc() { echo "${SERVICE_IDS[$1]}"; } # =========================================================================== echo -e "\n${C_BLUE}๐Ÿงช Creating Patch Tests...${C_RESET}" -# Gel Allergy Test covers: Gel Polish Full Set (idx 6), Luxury Gel Manicure (idx 7) -GEL_SVC_1="${SERVICE_IDS[6]}" -GEL_SVC_2="${SERVICE_IDS[7]}" +# Gel Allergy Test covers: Gel Manicure BIAB (idx 1), Gel Polish Full Set (idx 6), Luxury Gel Manicure (idx 7) +GEL_SVC_1="${SERVICE_IDS[1]}" +GEL_SVC_6="${SERVICE_IDS[6]}" +GEL_SVC_7="${SERVICE_IDS[7]}" # Insert patch test directly via SQL (no creation API endpoint exists) # service_ids cast explicitly to uuid[] to handle typed columns PATCH_TEST_RESULT=$(docker exec postgres psql -U myuser -d mydb -tAc \ - "INSERT INTO patch_tests (name, description, notice_duration_hours, expiry_months, service_ids) VALUES ('Gel Allergy Test', 'Mandatory patch test for all gel polish services. Must be completed at least 24 hours before your first gel appointment.', 24, 6, ARRAY['${GEL_SVC_1}','${GEL_SVC_2}']) RETURNING id;" 2>&1) + "INSERT INTO patch_tests (name, description, notice_duration_hours, expiry_months, service_ids) VALUES ('Gel Allergy Test', 'Mandatory patch test for all gel polish services. Must be completed at least 24 hours before your first gel appointment.', 24, 6, ARRAY['${GEL_SVC_1}','${GEL_SVC_6}','${GEL_SVC_7}']) RETURNING id;" 2>&1) PATCH_TEST_ID=$(echo "$PATCH_TEST_RESULT" | head -1 | tr -d '\r\t ') # Validate it looks like a UUID; print raw output if not to help diagnose @@ -414,12 +415,26 @@ if [[ -z "$PATCH_TEST_ID" || ! "$PATCH_TEST_ID" =~ ^[0-9a-f-]{8,}$ ]]; then PATCH_TEST_ID="" fi -# Record that Grace has already completed her patch test via the API -if [[ -n "$PATCH_TEST_ID" && -n "$GRACE_ID" ]]; then - api_post "$BASE_URL/admin/users/$GRACE_ID/patch-tests" \ - "{\"patch_test_id\":\"$PATCH_TEST_ID\"}" \ - "Record patch test for Grace" "$ADMIN_TOKEN" > /dev/null - echo "${C_GREEN}โœ… Patch test seeded (SQL) and recorded for Grace Fletcher${C_RESET}" +# Record patch tests for ALL users who book gel services so no booking gets 400'd +PATCH_TEST_USERS=( + "$GRACE_ID:Grace Fletcher" # Luxury Gel Manicure / Gel Full Set + "$EMMA_ID:Emma Johnson" # Gel Manicure (BIAB) โ€” regular gel client + "$ISLA_ID:Isla Davies" # Gel Manicure (BIAB) + Nail Art + "$LILY_ID:Lily Wilson" # Gel Manicure (BIAB) + Nail Art +) +patch_recorded=0 +if [[ -n "$PATCH_TEST_ID" ]]; then + for entry in "${PATCH_TEST_USERS[@]}"; do + uid="${entry%%:*}" + name="${entry#*:}" + if [[ -n "$uid" ]]; then + api_post "$BASE_URL/admin/users/$uid/patch-tests" \ + "{\"patch_test_id\":\"$PATCH_TEST_ID\"}" \ + "Record patch test for $name" "$ADMIN_TOKEN" > /dev/null \ + && patch_recorded=$((patch_recorded + 1)) + fi + done + echo "${C_GREEN}โœ… Patch test seeded (SQL) and recorded for $patch_recorded users${C_RESET}" else echo "${C_YELLOW}โš ๏ธ Patch test seeding failed (check DB connection or patch_tests table)${C_RESET}" fi diff --git a/reserve.har b/reserve.har deleted file mode 100644 index 18481f8..0000000 --- a/reserve.har +++ /dev/null @@ -1,176 +0,0 @@ -{ - "log": { - "version": "1.2", - "creator": { - "name": "Zen", - "version": "1.19.12b" - }, - "browser": { - "name": "Zen", - "version": "1.19.12b" - }, - "pages": [ - { - "id": "page_1", - "pageTimings": { - "onContentLoad": -82849, - "onLoad": -82148 - }, - "startedDateTime": "2026-05-17T17:55:39.809+01:00", - "title": "http://192.168.1.135:5173/book" - } - ], - "entries": [ - { - "startedDateTime": "2026-05-17T17:55:39.809+01:00", - "request": { - "bodySize": 87, - "method": "POST", - "url": "http://192.168.1.135:5173/api/bookings/reserve", - "httpVersion": "HTTP/1.1", - "headers": [ - { - "name": "Host", - "value": "192.168.1.135:5173" - }, - { - "name": "User-Agent", - "value": "Mozilla/5.0 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0" - }, - { - "name": "Accept", - "value": "*/*" - }, - { - "name": "Accept-Language", - "value": "en-US,en;q=0.9" - }, - { - "name": "Accept-Encoding", - "value": "gzip, deflate" - }, - { - "name": "Referer", - "value": "http://192.168.1.135:5173/book" - }, - { - "name": "Content-Type", - "value": "application/json" - }, - { - "name": "Content-Length", - "value": "87" - }, - { - "name": "Origin", - "value": "http://192.168.1.135:5173" - }, - { - "name": "Sec-GPC", - "value": "1" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Priority", - "value": "u=4" - }, - { - "name": "Pragma", - "value": "no-cache" - }, - { - "name": "Cache-Control", - "value": "no-cache" - } - ], - "cookies": [], - "queryString": [], - "headersSize": 449, - "postData": { - "mimeType": "application/json", - "params": [], - "text": "{\"start_time\":\"2026-05-21T16:00:00.000Z\",\"service_ids\":[\"cf628115690e\",\"543de40e5079\"]}" - } - }, - "response": { - "status": 400, - "statusText": "Bad Request", - "httpVersion": "HTTP/1.1", - "headers": [ - { - "name": "Vary", - "value": "Origin" - }, - { - "name": "content-length", - "value": "67" - }, - { - "name": "content-type", - "value": "text/plain; charset=utf-8" - }, - { - "name": "date", - "value": "Sun, 17 May 2026 16:55:39 GMT" - }, - { - "name": "referrer-policy", - "value": "strict-origin-when-cross-origin" - }, - { - "name": "strict-transport-security", - "value": "max-age=31536000; includeSubDomains" - }, - { - "name": "x-content-type-options", - "value": "nosniff" - }, - { - "name": "x-frame-options", - "value": "DENY" - }, - { - "name": "x-xss-protection", - "value": "1; mode=block" - }, - { - "name": "Connection", - "value": "keep-alive" - }, - { - "name": "Keep-Alive", - "value": "timeout=5" - } - ], - "cookies": [], - "content": { - "mimeType": "text/plain; charset=utf-8", - "size": 67, - "text": "Cannot book this time - services would extend beyond closing hours\n" - }, - "redirectURL": "", - "headersSize": 390, - "bodySize": 457 - }, - "cache": {}, - "timings": { - "blocked": -1, - "dns": 0, - "connect": 0, - "ssl": 0, - "send": 0, - "wait": 7, - "receive": 0 - }, - "time": 7, - "_securityState": "insecure", - "serverIPAddress": "192.168.1.135", - "connection": "5173", - "pageref": "page_1" - } - ] - } -} \ No newline at end of file