Fix NewBook write mechanism, bundle push extension, remove vestigial hotel_id

- setBookingCustomFields: use bookings_update's own custom_fields array
  (confirmed from the real legacy plugin code) instead of
  instance_custom_fields_set, which was only ever proven for a different,
  unrelated plugin
- online_checkin_complete is now a configurable per-hotel custom field
  (online_checkin_complete_custom_field_id setting), not a bogus top-level
  bookings_update field NewBook would silently ignore
- Fix field-name mismatches vs a real live NewBook booking response:
  booking_arrival/departure/length, guest address (street/city/state/
  postcode/country, not a single field), phone/mobile (in contact_details,
  not top-level), and pickPrimaryGuest now checks primary_client (was
  checking fields that don't exist in the real API)
- Bundle the standalone push extension into backend/extension-src/, add
  GET /api/extension/download (zips on request via archiver) and a
  download button on the Settings page
- Remove newbook_hotel_id — vestigial from the legacy system's multi-hotel
  routing model, never actually reached NewBook's API, this stack is
  single-hotel-per-deployment so there's nothing to route between

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-09-01 18:11:35 +00:00
parent 3b2e25df3f
commit 4d3774ef0d
25 changed files with 3557 additions and 15 deletions

View file

@ -0,0 +1,38 @@
// Detects whether the browser currently has a live NewBook session — used
// ONLY to decide whether to show a "you don't look logged into NewBook"
// hint in the popup. NOT used as authorization for the push call itself —
// that's the terminal API key (see options.js/popup.js). A NewBook cookie
// proves you're logged into NewBook, not that you hold this extension's own
// terminal credential; conflating the two was explicitly rejected as a
// design decision, see project_checkin memory's "Extension auth" section.
//
// Cookie-detection heuristic (domains + name match) is lifted directly from
// chrome-newbook-assistant/sidepanel/sidepanel.js's AuthManager.checkNewBookAuth
// (~/laptop-archive) — already proven against real NewBook cookies, not
// guessed here.
const NEWBOOK_COOKIE_DOMAINS = [
'https://appeu.newbook.cloud',
'https://login.newbook.cloud',
];
export async function isNewBookLoggedIn() {
try {
let allCookies = [];
for (const url of NEWBOOK_COOKIE_DOMAINS) {
const cookies = await chrome.cookies.getAll({ url });
allCookies = allCookies.concat(cookies);
}
const sessionCookie = allCookies.find(
c => c.name === 'PHPSESSID'
|| c.name.toLowerCase().includes('session')
|| c.name.toLowerCase().includes('newbook')
);
if (!sessionCookie) return false;
// A session cookie with no expirationDate is a browser-session cookie —
// still valid until the browser closes, not "expired".
if (sessionCookie.expirationDate && sessionCookie.expirationDate * 1000 < Date.now()) return false;
return true;
} catch {
return false;
}
}