feat: fix DDMA eligibility — patient list, name extraction, PDF page, OTP session
- Filter patient list by userId so each user sees only their own patients - Sort patients by updatedAt DESC so recently checked patients appear first - Add updatedAt field to Patient model (DB migration via raw SQL + db:generate) - Fix DDMA name extraction: read from detail page "Name:" label, not search results row text which included appended dates - Fix PDF capture: use driver.get() instead of click() to avoid race condition that was saving the search results page instead of the patient detail page - Strip trailing bare dates from extracted names (e.g. "Rodriguez 04/27/2026") - Handle "Last, First" comma format and single-word last names in splitName - Normalize insuranceId consistently in createOrUpdatePatientByInsuranceId - Fix OTP persistent session: stop clearing LocalStorage/IndexedDB on startup (these hold the DDMA device trust token that skips OTP on subsequent logins) - Increase post-navigation wait time for full page render before PDF generation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -44,28 +44,26 @@ class DDMABrowserManager:
|
||||
|
||||
def clear_session_on_startup(self):
|
||||
"""
|
||||
Clear session cookies from Chrome profile on startup.
|
||||
This forces a fresh login after PC restart.
|
||||
Preserves device trust tokens (LocalStorage, IndexedDB) to avoid OTPs.
|
||||
Clear only login cookies on startup to force credential re-entry after restart.
|
||||
NEVER clears Local Storage or IndexedDB — those hold the DDMA device trust token
|
||||
that allows the portal to skip OTP for recognised devices.
|
||||
"""
|
||||
print("[DDMA BrowserManager] Clearing session on startup...")
|
||||
print("[DDMA BrowserManager] Clearing login cookies on startup (preserving device trust)...")
|
||||
|
||||
try:
|
||||
# Clear credentials tracking file
|
||||
# Reset credentials tracking so the next login re-saves the hash
|
||||
if os.path.exists(self._credentials_file):
|
||||
os.remove(self._credentials_file)
|
||||
print("[DDMA BrowserManager] Cleared credentials tracking file")
|
||||
|
||||
# Clear session-related Chrome profile files
|
||||
# Only remove cookie / login-data files — these expire the session so the
|
||||
# user must re-enter credentials, but the device trust token is untouched.
|
||||
session_files = [
|
||||
"Cookies",
|
||||
"Cookies-journal",
|
||||
"Login Data",
|
||||
"Login Data-journal",
|
||||
"Web Data",
|
||||
"Web Data-journal",
|
||||
]
|
||||
|
||||
for filename in session_files:
|
||||
for base in [os.path.join(self.profile_dir, "Default"), self.profile_dir]:
|
||||
filepath = os.path.join(base, filename)
|
||||
@@ -76,55 +74,12 @@ class DDMABrowserManager:
|
||||
except Exception as e:
|
||||
print(f"[DDMA BrowserManager] Could not remove {filename}: {e}")
|
||||
|
||||
# Clear Session Storage (contains login state)
|
||||
session_storage_dir = os.path.join(self.profile_dir, "Default", "Session Storage")
|
||||
if os.path.exists(session_storage_dir):
|
||||
try:
|
||||
shutil.rmtree(session_storage_dir)
|
||||
print("[DDMA BrowserManager] Cleared Session Storage")
|
||||
except Exception as e:
|
||||
print(f"[DDMA BrowserManager] Could not clear Session Storage: {e}")
|
||||
|
||||
# Clear Local Storage (may contain auth tokens)
|
||||
local_storage_dir = os.path.join(self.profile_dir, "Default", "Local Storage")
|
||||
if os.path.exists(local_storage_dir):
|
||||
try:
|
||||
shutil.rmtree(local_storage_dir)
|
||||
print("[DDMA BrowserManager] Cleared Local Storage")
|
||||
except Exception as e:
|
||||
print(f"[DDMA BrowserManager] Could not clear Local Storage: {e}")
|
||||
|
||||
# Clear IndexedDB (may contain auth tokens)
|
||||
indexeddb_dir = os.path.join(self.profile_dir, "Default", "IndexedDB")
|
||||
if os.path.exists(indexeddb_dir):
|
||||
try:
|
||||
shutil.rmtree(indexeddb_dir)
|
||||
print("[DDMA BrowserManager] Cleared IndexedDB")
|
||||
except Exception as e:
|
||||
print(f"[DDMA BrowserManager] Could not clear IndexedDB: {e}")
|
||||
|
||||
# Clear browser caches
|
||||
cache_dirs = [
|
||||
os.path.join(self.profile_dir, "Default", "Cache"),
|
||||
os.path.join(self.profile_dir, "Default", "Code Cache"),
|
||||
os.path.join(self.profile_dir, "Default", "GPUCache"),
|
||||
os.path.join(self.profile_dir, "Default", "Service Worker"),
|
||||
os.path.join(self.profile_dir, "Cache"),
|
||||
os.path.join(self.profile_dir, "Code Cache"),
|
||||
os.path.join(self.profile_dir, "GPUCache"),
|
||||
os.path.join(self.profile_dir, "Service Worker"),
|
||||
os.path.join(self.profile_dir, "ShaderCache"),
|
||||
]
|
||||
for cache_dir in cache_dirs:
|
||||
if os.path.exists(cache_dir):
|
||||
try:
|
||||
shutil.rmtree(cache_dir)
|
||||
print(f"[DDMA BrowserManager] Cleared {os.path.basename(cache_dir)}")
|
||||
except Exception as e:
|
||||
print(f"[DDMA BrowserManager] Could not clear {os.path.basename(cache_dir)}: {e}")
|
||||
# Local Storage, IndexedDB, and Session Storage are intentionally
|
||||
# NOT cleared — they contain the DDMA device trust token that prevents
|
||||
# OTP from being required on every login.
|
||||
|
||||
self._needs_session_clear = True
|
||||
print("[DDMA BrowserManager] Session cleared - will require fresh login")
|
||||
print("[DDMA BrowserManager] Startup clear done — device trust preserved, OTP not required")
|
||||
|
||||
except Exception as e:
|
||||
print(f"[DDMA BrowserManager] Error clearing session: {e}")
|
||||
|
||||
Reference in New Issue
Block a user