Files
boc/backups/2026-07-12-1023/landvex-prod/autofill-login.html
T
Bernt 58ca4e68db feat(boc): Complete Business Operations Center v1.0
- Go backend API with full CRUD for all modules (CRM, Sales, Finance, HR, Legal, Marketing, Support, Purchase, Inventory, Projects, Automation, Analytics)
- Rust analytics service with parallel report generation
- C runtime with POSIX shared memory IPC
- PostgreSQL schema with 30+ tables, full migrations
- Redis cache, sessions, pub/sub
- Kafka event streaming with Zookeeper
- WebSocket hub for real-time updates
- Automation engine with cron jobs, workflows, event triggers
- JWT authentication, multi-tenant from start
- Docker Compose with all services
- Nginx reverse proxy with rate limiting
- Integration tests passing
- Feature gap analysis against Fortnox/Odoo/Visma

Refs: BOC-001
2026-07-12 12:41:35 +00:00

125 lines
5.3 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Loggar in...</title>
<style>
body { background: #0a0e1a; color: #e2e8f0; font-family: system-ui; display: flex;
align-items: center; justify-content: center; min-height: 100vh; margin: 0; }
.box { text-align: center; }
.spinner { width: 40px; height: 40px; border: 3px solid #1e293b;
border-top: 3px solid #6366f1; border-radius: var(--radius-full); animation: spin 0.8s linear infinite;
margin: 0 auto 16px; }
@keyframes spin { to { transform: rotate(360deg); } }
h2 { margin: 0 0 8px; font-size: 1.2rem; }
p { color: #64748b; font-size: 0.85rem; margin: 0; }
#creds { background: #1e293b; border-radius: var(--radius-md); padding: 16px; margin-top: 20px;
text-align: left; min-width: 280px; display: none; }
.row { display: flex; justify-content: space-between; align-items: center;
margin-bottom: 10px; gap: 12px; }
label { color: #94a3b8; font-size: 0.8rem; min-width: 80px; }
code { color: #fbbf24; font-size: 0.85rem; flex: 1; }
.copy-btn { background: #6366f1; color: #fff; border: none; border-radius: var(--radius-sm);
padding: 3px 10px; cursor: pointer; font-size: 0.75rem; white-space: nowrap; }
.open-btn { display: inline-flex; align-items: center; gap: 8px; background: #6366f1;
color: #fff; text-decoration: none; padding: 10px 24px; border-radius: var(--radius-md);
font-weight: 700; font-size: 0.9rem; margin-top: 16px; }
</style>
</head>
<body>
<div class="box">
<div id="loading">
<div class="spinner"></div>
<h2>Hämtar inloggningsuppgifter...</h2>
<p>Omdirigerar till plattformen</p>
</div>
<div id="creds">
<h2 id="plat-title" style="margin:0 0 16px;font-size:1rem;color:#e2e8f0"></h2>
<div class="row">
<label>Användarnamn</label>
<code id="show-user"></code>
<button class="copy-btn" onclick="copy('show-user',this)">Kopiera</button>
</div>
<div class="row">
<label>Lösenord</label>
<code id="show-pw"></code>
<button class="copy-btn" onclick="copy('show-pw',this)">Kopiera</button>
</div>
<div class="row">
<label>E-post</label>
<code id="show-email"></code>
<button class="copy-btn" onclick="copy('show-email',this)">Kopiera</button>
</div>
<a id="open-link" href="#" target="_blank" class="open-btn">Öppna inloggningssidan →</a>
<p style="margin-top:12px;color:#475569;font-size:0.75rem">
Logga in på plattformen och kom tillbaka hit för att godkänna jobbet.
</p>
</div>
</div>
<script>
function copy(id, btn) {
const text = document.getElementById(id).textContent;
navigator.clipboard.writeText(text).then(() => {
const orig = btn.textContent;
btn.textContent = '<svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M3 8L6.5 11.5L13 4.5" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
setTimeout(() => btn.textContent = orig, 1500);
});
}
async function init() {
const params = new URLSearchParams(location.search);
const company = params.get('company') || '';
const platform = params.get('platform') || '';
const token = params.get('token') || localStorage.getItem('qz_auth_token') || '';
if (!company || !platform || !token) {
document.getElementById('loading').innerHTML =
'<h2 style="color:#f87171">Saknar parametrar</h2><p>company, platform och token krävs.</p>';
return;
}
try {
const res = await fetch('/api/social-account/credentials?company=' + encodeURIComponent(company) + '&reveal=1', {
headers: { 'Authorization': 'Bearer ' + token }
});
if (!res.ok) throw new Error('HTTP ' + res.status);
const creds = await res.json();
const c = creds.find(x => x.platform === platform);
if (!c) throw new Error('Inga credentials för ' + company + '/' + platform);
const PLATFORM_URLS = {
pinterest: 'https://www.pinterest.com/login/',
tiktok: 'https://www.tiktok.com/login/',
instagram: 'https://www.instagram.com/accounts/login/',
snapchat: 'https://accounts.snapchat.com/',
reddit: 'https://www.reddit.com/login/',
linkedin: 'https://www.linkedin.com/login/',
twitter: 'https://twitter.com/login',
x: 'https://twitter.com/login',
facebook: 'https://www.facebook.com/login/',
spotify: 'https://accounts.spotify.com/login',
glassdoor: 'https://www.glassdoor.com/profile/login',
indeed: 'https://employers.indeed.com/',
};
document.getElementById('show-user').textContent = c.username || c.email || '—';
document.getElementById('show-pw').textContent = c.password || '—';
document.getElementById('show-email').textContent = c.email || '—';
document.getElementById('plat-title').textContent =
platform.charAt(0).toUpperCase() + platform.slice(1) + ' — ' + company;
const loginUrl = PLATFORM_URLS[platform.toLowerCase()] || 'https://' + platform + '.com/login';
document.getElementById('open-link').href = loginUrl;
document.getElementById('loading').style.display = 'none';
document.getElementById('creds').style.display = 'block';
} catch(e) {
document.getElementById('loading').innerHTML =
'<h2 style="color:#f87171">Fel</h2><p>' + e.message + '</p>';
}
}
init();
</script>
</body>
</html>