GDPRScanner/static/js/state.js
StyxX65 d8083eb0c0 feat: interface PIN, bulk disposition tagging, Google Drive delta scan, OCR memory fixes
- Interface PIN: optional session-level auth gate for the main scanner UI
  (Settings → Security → Interface PIN). Salted SHA-256 in config.json,
  rate-limited (5 attempts/5 min per IP). /view and viewer auth exempt.
  New /login page, before_request hook, GET/POST/DELETE /api/interface/pin,
  POST /api/interface/pin/verify, POST /api/interface/logout.

- Bulk disposition tagging: Select mode (filter bar "Vælg" button) reveals
  per-card checkboxes. Bulk tag bar at bottom of grid; POST /api/db/disposition/bulk.
  Disposition stats bar (total · unreviewed · retain · delete · % reviewed)
  updates after every save.

- Google Drive delta scan: uses Drive Changes API when delta is enabled.
  Per-user token stored as gdrive:{email} in delta.json. Load-then-merge
  save avoids racing with concurrent M365 token writes.

- PDF OCR OOM fix: render one page at a time with convert_from_path
  (first_page=N, last_page=N). Added _ocr_mem_ok() psutil guard (500 MB
  threshold) before each page render across scan_pdf, redact_fitz_pdf,
  redact_pdf.

- Email test message translation fix: routes/email.py returns structured
  {ok, method, recipients} instead of a hardcoded English string;
  scheduler.js builds the translated message client-side.

- Docs: CHANGELOG, README, TODO, MANUAL-EN, MANUAL-DA all updated.
  Lang files (en/da/de) extended with bulk, interface PIN, and SMTP keys.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 18:46:45 +02:00

37 lines
1.0 KiB
JavaScript

// state.js — shared mutable state for GDPRScanner
// Imported by every module that needs cross-module state.
// Use S.varName everywhere instead of bare varName.
export const S = {
// Scan results
flaggedData: [],
filteredData: [],
totalCPR: 0,
isListView: false,
// SSE connection
es: null,
_userStartedScan: false,
// Scan running flags + progress
_m365ScanRunning: false,
_googleScanRunning: false,
_fileScanRunning: false,
_srcPct: { m365: 0, google: 0, file: 0 },
_progressCurrentUser: '',
// Users
_allUsers: [],
// Auth
_currentAppMode: null,
// Profiles
_profiles: [],
_activeProfileId: null,
_pendingProfileSources: [],
_pendingGoogleSources: null,
// Sources
_fileSources: [],
// History browser
_historyRefScanId: null, // null = live/SSE, number = viewing a past session
// Bulk disposition
_selectMode: false,
_selectedIds: new Set(),
};