3m-portal/editor.html
Vadym Samoilenko 53a85c788d Add full auth system: SQLite sessions, email invites, admin console
- Real email/password login backed by SQLite (better-sqlite3)
- HttpOnly cookie sessions with 8h sliding TTL
- Admin role: invite users via Mailgun magic-link, manage roles/status
- Per-user One2Edit username mapping for job filtering
- Self-service forgot-password / reset-password via email
- Admin console (admin.html) with user table, invite modal, row actions
- New pages: change-password, forgot-password, reset-password, accept-invite
- Gated /api proxy: requires valid session, anti-hijack sessionId check
- Bootstrap initial admins from INITIAL_ADMINS env var on first boot
- Remove Oliver login button, SSO buttons, and legacy api.js/login.js
- deploy.sh: add build-essential (for native module), npm install, data dir

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 11:26:40 +01:00

134 lines
4.6 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3M - Job Editor</title>
<link rel="icon" type="image/png" href="Images/Favicon_logo.png">
<!-- One2Edit CSS and JS -->
<link rel="stylesheet" href="https://oliver.one2edit.com/css/one2edit.css" type="text/css" media="screen"/>
<script type="text/javascript" src="https://oliver.one2edit.com/scripts/one2edit.js"></script>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}
#flashContent {
width: 100vw;
height: 100vh;
}
.loading-message {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
color: #666;
font-size: 18px;
}
.error-message {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
color: #c33;
font-size: 16px;
max-width: 500px;
padding: 20px;
background: #fee;
border-radius: 8px;
}
</style>
</head>
<body>
<div id="flashContent">
<div class="loading-message" id="loadingMessage">
<p>Loading editor...</p>
</div>
<div class="error-message" id="editorError" style="display:none;"></div>
</div>
<script>
const urlParams = new URLSearchParams(window.location.search);
const jobId = urlParams.get('jobId');
function showError(msg) {
document.getElementById('loadingMessage').style.display = 'none';
const el = document.getElementById('editorError');
el.textContent = msg;
el.style.display = 'block';
}
async function initEditor() {
if (!jobId) {
showError('Missing job information. Please go back to the dashboard and try again.');
return;
}
let me;
try {
const res = await fetch('/api/auth/me');
if (!res.ok) { window.location.href = 'login.html'; return; }
me = await res.json();
} catch {
window.location.href = 'login.html';
return;
}
const externSessionId = me.externSessionId;
const authConfig = me.authConfig || {};
if (!externSessionId) {
showError('Missing session information. Please go back to the dashboard and try again.');
return;
}
one2edit.debug = true;
console.log('Using externSessionId for SDK:', externSessionId);
one2edit.create({
flashvars: {
server: 'https://oliver.one2edit.com/',
sessionId: externSessionId,
clientId: parseInt(authConfig.clientId),
jobEditor: { jobId: parseInt(jobId) }
}
});
one2edit.addEventListener(one2edit.events.Event.INITIALIZE, function() {
console.log('Event: INITIALIZE');
const loadingMsg = document.getElementById('loadingMessage');
if (loadingMsg) loadingMsg.style.display = 'none';
one2edit.editor.showMenu(false);
});
one2edit.addEventListener(one2edit.events.Event.EDITOR_INITIALIZE, function() {
console.log('Event: EDITOR_INITIALIZE');
one2edit.editor.toolbar.removeElement(one2edit.editor.toolbar.getElementById('toolbar_tool_search_replace'));
one2edit.editor.toolbar.removeElement(one2edit.editor.toolbar.getElementById('toolbar_download_pdf'));
one2edit.editor.toolbar.removeElement(one2edit.editor.toolbar.getElementById('toolbar_rotate'));
});
one2edit.addEventListener(one2edit.events.Event.EDITOR_ERROR, function(event) {
console.error('Event: EDITOR_ERROR', event);
showError('Error loading editor. Please try again.');
});
one2edit.addEventListener(one2edit.events.Event.EDITOR_CLOSE, function() {
console.log('Event: EDITOR_CLOSE');
window.location.href = 'dashboard.html';
});
}
initEditor();
</script>
</body>
</html>