- 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>
134 lines
4.6 KiB
HTML
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>
|