|
import type { Request, Response, Application } from 'express'; |
|
import path from 'path'; |
|
import { readFileSync, existsSync } from 'fs'; |
|
|
|
function safeReadFile(filePath: string, encoding: BufferEncoding = 'utf-8'): string { |
|
if (existsSync(filePath)) { |
|
try { |
|
return readFileSync(filePath, encoding); |
|
} catch (e) { |
|
console.error(`Error reading file ${filePath} (safeReadFile):`, e); |
|
return ''; |
|
} |
|
} |
|
console.warn(`Warning: File not found at ${filePath} (safeReadFile). Returning empty string.`); |
|
return ''; |
|
} |
|
|
|
export function html(app: Application): void { |
|
const fileSystemPublicBasePath = path.resolve(__dirname, '..', 'public'); |
|
const header = safeReadFile(path.join(fileSystemPublicBasePath, 'templates', 'header.html')); |
|
const chatheadai = safeReadFile(path.join(fileSystemPublicBasePath, 'templates', 'chatheadai.html')); |
|
const footer = safeReadFile(path.join(fileSystemPublicBasePath, 'templates', 'footer.html')); |
|
|
|
function renderPage(title: string, scriptPath: string): string { |
|
const hostScript = safeReadFile(path.join(fileSystemPublicBasePath, 'src', scriptPath)); |
|
const basePublicPath = '/private/server/exocore/web/public'; |
|
|
|
return ` |
|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8" /> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> |
|
<link rel="icon" type="image/jpeg" href="https://i.ibb.co/G4vDj7Fm/FB-IMG-1749809298614.jpg"> |
|
<title>${title}</title> |
|
<script> |
|
(function() { |
|
const getToken = () => localStorage.getItem('exocore-token') || ''; |
|
const getCookies = () => localStorage.getItem('exocore-cookies') || ''; |
|
const baseRedirectPath = '/private/server/exocore/web/public'; |
|
const panelLoginLandingUrl = baseRedirectPath; |
|
const accountLoginUrl = \`\${baseRedirectPath}/login\`; |
|
const registerUrl = \`\${baseRedirectPath}/register\`; |
|
const otpUrl = \`\${baseRedirectPath}/otp\`; |
|
const forgotPasswordUrl = \`\${baseRedirectPath}/forgot-password\`; |
|
const currentPathname = window.location.pathname; |
|
const isPanelLoginSuccess = localStorage.getItem('panelLogin') === 'success'; |
|
const hasAccountAuthTokens = getToken() && getCookies(); |
|
|
|
if (!isPanelLoginSuccess) { |
|
if (currentPathname !== panelLoginLandingUrl) { |
|
console.log("'panelLogin' is not 'success'. Redirecting to panel login landing page..."); |
|
window.location.href = panelLoginLandingUrl; |
|
throw new Error("Redirecting to panel login landing to halt script execution."); |
|
} |
|
return; |
|
} |
|
|
|
const postPanelLogin_AccountAuthPages = [accountLoginUrl, registerUrl, otpUrl, forgotPasswordUrl]; |
|
|
|
if (!hasAccountAuthTokens) { |
|
if (!postPanelLogin_AccountAuthPages.includes(currentPathname)) { |
|
console.log('User has panel access but no account session tokens. Redirecting to account login page...'); |
|
window.location.href = accountLoginUrl; |
|
throw new Error("Redirecting to account login to halt script execution."); |
|
} |
|
return; |
|
} |
|
})(); |
|
</script> |
|
<script src="https://cdn.jsdelivr.net/npm/ansi_up@5.1.0/ansi_up.min.js"></script> |
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" /> |
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css" /> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css"> |
|
<style> |
|
html, body { height: 100%; margin: 0; } |
|
.page-wrapper { min-height: 100%; display: flex; flex-direction: column; } |
|
.page-content { flex: 1; } |
|
#app { min-height: 100vh; } |
|
h2, h3, h4 { color: #333; margin-top: 0.5rem; margin-bottom: 1rem; } |
|
ul { list-style-type: none; padding: 0; margin: 0; } |
|
li { padding: 0.2rem 0; } |
|
.status-box { padding: 0.5rem; margin: 0.5rem 0; border: 1px solid #ddd; background: #f9f9f9; border-radius: 4px; display: flex; align-items: center; justify-content: space-between; } |
|
input[type="file"] { display: none; } |
|
@media (max-width: 767px) { |
|
.main-content-flex { flex-direction: column; gap: 15px !important; } |
|
.file-list-panel, .file-editor-panel { width: 100%; min-width: unset !important; } |
|
} |
|
pre { background: #1e1e1e; padding: 1em; overflow: auto; border-radius: 5px; color: #ccc; } |
|
code { font-family: 'monospace'; display: block; } |
|
</style> |
|
</head> |
|
<body> |
|
<div class="page-wrapper"> |
|
${header} |
|
<div id="app" class="page-content"></div> |
|
${chatheadai} |
|
${footer} |
|
</div> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> |
|
<script> |
|
document.addEventListener('DOMContentLoaded', () => { |
|
if (typeof hljs !== 'undefined') { |
|
hljs.highlightAll(); |
|
} |
|
}); |
|
</script> |
|
<script> |
|
async function checkProjectStatusAndRedirect() { |
|
const projectStatusUrl = '/private/server/exocore/web/project/status'; |
|
const redirectUrl = '${basePublicPath}/project'; |
|
if (window.location.pathname === redirectUrl) { |
|
console.log('Currently on the project setup page. Status check will not redirect further from here.'); |
|
return; |
|
} |
|
try { |
|
const response = await fetch(projectStatusUrl, { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' }, |
|
}); |
|
if (!response.ok) { |
|
console.error(\`Failed to fetch project status. Server responded with \${response.status}: \${response.statusText}\`); |
|
return; |
|
} |
|
const statusData = await response.json(); |
|
if (statusData && typeof statusData.exists === 'boolean' && !statusData.exists) { |
|
console.log('Project status indicates it does not exist or is not properly configured. Redirecting to project setup...'); |
|
window.location.href = redirectUrl; |
|
} else if (statusData && statusData.exists === true) { |
|
console.log('Project exists. No redirection necessary from project status check.'); |
|
} else { |
|
console.warn('Received an unexpected or malformed response from the project status API:', statusData); |
|
} |
|
} catch (error) { |
|
console.error('Error during project status check or processing:', error); |
|
} |
|
} |
|
const currentPathnameForProjectCheck = window.location.pathname; |
|
const baseRedirectPathForProjectCheck = '/private/server/exocore/web/public'; |
|
const accountLoginUrlForProjectCheck = \`\${baseRedirectPathForProjectCheck}/login\`; |
|
const registerUrlForProjectCheck = \`\${baseRedirectPathForProjectCheck}/register\`; |
|
const otpUrlForProjectCheck = \`\${baseRedirectPathForProjectCheck}/otp\`; |
|
if ( localStorage.getItem('exocore-token') && |
|
localStorage.getItem('exocore-cookies') && |
|
localStorage.getItem('panelLogin') === 'success' && |
|
currentPathnameForProjectCheck !== accountLoginUrlForProjectCheck && |
|
currentPathnameForProjectCheck !== registerUrlForProjectCheck && |
|
currentPathnameForProjectCheck !== otpUrlForProjectCheck |
|
) { |
|
checkProjectStatusAndRedirect(); |
|
} |
|
</script> |
|
<script type="module">${hostScript}</script> |
|
</body> |
|
</html>`; |
|
} |
|
|
|
const urlSegmentForPublicRoutes = '/private/server/exocore/web/public'; |
|
|
|
app.get(`${urlSegmentForPublicRoutes}/register`, (_req: Request, res: Response): void => { |
|
res.setHeader('Content-Type', 'text/html'); |
|
res.send(renderPage('Signup', 'register.js')); |
|
}); |
|
|
|
app.get(`${urlSegmentForPublicRoutes}/login`, (_req: Request, res: Response): void => { |
|
res.setHeader('Content-Type', 'text/html'); |
|
res.send(renderPage('Login', 'login.js')); |
|
}); |
|
|
|
app.get(`${urlSegmentForPublicRoutes}/project`, (_req: Request, res: Response): void => { |
|
res.setHeader('Content-Type', 'text/html'); |
|
res.send(renderPage('Project', 'project.js')); |
|
}); |
|
|
|
app.get(`${urlSegmentForPublicRoutes}/otp`, (_req: Request, res: Response): void => { |
|
res.setHeader('Content-Type', 'text/html'); |
|
res.send(renderPage('Otp', 'otp.js')); |
|
}); |
|
|
|
app.get(`${urlSegmentForPublicRoutes}/profile`, (_req: Request, res: Response): void => { |
|
res.setHeader('Content-Type', 'text/html'); |
|
res.send(renderPage('Profile', 'profile.js')); |
|
}); |
|
|
|
app.get(`${urlSegmentForPublicRoutes}/forgot-password`, (_req: Request, res: Response): void => { |
|
res.setHeader('Content-Type', 'text/html'); |
|
res.send(renderPage('ForgotPass', 'forgot.js')); |
|
}); |
|
|
|
app.get(`${urlSegmentForPublicRoutes}/dashboard`, (_req: Request, res: Response): void => { |
|
res.setHeader('Content-Type', 'text/html'); |
|
res.send(renderPage('Dashboard', 'dashboard.js')); |
|
}); |
|
|
|
app.get(`${urlSegmentForPublicRoutes}/plans`, (_req: Request, res: Response): void => { |
|
res.setHeader('Content-Type', 'text/html'); |
|
res.send(renderPage('plans', 'plans.js')); |
|
}); |
|
|
|
app.get(`${urlSegmentForPublicRoutes}/console`, (_req: Request, res: Response): void => { |
|
res.setHeader('Content-Type', 'text/html'); |
|
res.send(renderPage('Console', 'console.js')); |
|
}); |
|
|
|
app.get(`${urlSegmentForPublicRoutes}/shell`, (_req: Request, res: Response): void => { |
|
res.setHeader('Content-Type', 'text/html'); |
|
res.send(renderPage('Shell', 'shell.js')); |
|
}); |
|
|
|
app.get(`${urlSegmentForPublicRoutes}/manager`, (_req: Request, res: Response): void => { |
|
res.setHeader('Content-Type', 'text/html'); |
|
res.send(renderPage('File Manager', 'FileManager.js')); |
|
}); |
|
|
|
app.get(urlSegmentForPublicRoutes, (_req: Request, res: Response): void => { |
|
const panelHtmlFilePath = path.join(fileSystemPublicBasePath, 'panel.html'); |
|
|
|
if (!existsSync(panelHtmlFilePath)) { |
|
console.warn(`Static file not found: ${panelHtmlFilePath} for URL ${urlSegmentForPublicRoutes}. Sending 404.`); |
|
res.status(404).send('Page not found.'); |
|
return; |
|
} |
|
|
|
try { |
|
const fileContent = readFileSync(panelHtmlFilePath, 'utf-8'); |
|
res.setHeader('Content-Type', 'text/html'); |
|
res.send(fileContent); |
|
} catch (error) { |
|
console.error(`Error reading static file ${panelHtmlFilePath} for URL ${urlSegmentForPublicRoutes}:`, error); |
|
res.status(500).send('Error loading page.'); |
|
} |
|
}); |
|
} |
|
|