Files
crank/apps/ui/js/auth.js
T
2026-03-31 16:08:20 +03:00

225 lines
6.0 KiB
JavaScript

(function() {
var STORAGE_KEY = 'crank_user';
var sessionCache = null;
var sessionPromise = null;
function currentWorkspaceLabel() {
if (window.getCurrentWorkspace) {
var workspace = window.getCurrentWorkspace();
if (workspace && workspace.name) {
return workspace.name;
}
}
try {
return localStorage.getItem('crank_workspace_slug') || 'workspace';
} catch (_error) {
return 'workspace';
}
}
function isLoginPage() {
return /\/html\/login\.html$/.test(window.location.pathname);
}
function loginUrl() {
return (window.APP_BASE || '') + 'html/login.html';
}
function homeUrl() {
return (window.APP_BASE || '') + 'index.html';
}
function clearUserMirror() {
sessionCache = null;
sessionPromise = null;
try {
localStorage.removeItem(STORAGE_KEY);
} catch (_error) {}
renderShellIdentity(null);
}
function primaryMembership(session) {
if (!(session && session.memberships && session.memberships.length)) {
return null;
}
if (window.getCurrentWorkspace) {
var currentWorkspace = window.getCurrentWorkspace();
if (currentWorkspace) {
var matched = session.memberships.find(function(item) {
return item.workspace && item.workspace.id === currentWorkspace.id;
});
if (matched) {
return matched;
}
}
}
return session.memberships[0];
}
function initials(displayName, email) {
var source = displayName || email || 'Crank';
return source
.split(/\s+/)
.filter(Boolean)
.slice(0, 2)
.map(function(part) { return part.charAt(0).toUpperCase(); })
.join('') || 'CR';
}
function persistUserMirror(session) {
var membership = primaryMembership(session);
var user = {
id: session.user.id,
name: session.user.display_name,
email: session.user.email,
role: membership ? String(membership.role || '').replace(/^\w/, function(char) { return char.toUpperCase(); }) : 'Viewer',
workspace: membership ? membership.workspace.slug : '',
workspaceId: membership ? membership.workspace.id : '',
initials: initials(session.user.display_name, session.user.email),
};
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(user));
} catch (_error) {}
}
function mirroredUser() {
try {
return JSON.parse(localStorage.getItem(STORAGE_KEY));
} catch (_error) {
return null;
}
}
function renderShellIdentity(session) {
var membership = primaryMembership(session);
var fallbackUser = mirroredUser();
var displayName = session && session.user
? (session.user.display_name || session.user.email || 'Crank')
: (fallbackUser && fallbackUser.name) || 'Crank';
var email = session && session.user
? session.user.email
: fallbackUser && fallbackUser.email;
var role = membership
? String(membership.role || '').replace(/^\w/, function(char) { return char.toUpperCase(); })
: (fallbackUser && fallbackUser.role) || 'Viewer';
var workspace = membership && membership.workspace
? (membership.workspace.display_name || membership.workspace.slug || membership.workspace.id)
: currentWorkspaceLabel();
var avatarValue = initials(displayName, email);
document.querySelectorAll('.nav-avatar').forEach(function(element) {
element.textContent = avatarValue;
});
document.querySelectorAll('.user-dropdown-name').forEach(function(element) {
element.textContent = displayName;
});
document.querySelectorAll('.user-dropdown-role').forEach(function(element) {
element.textContent = role + ' · ' + workspace;
});
}
function replaceSession(session) {
sessionCache = session;
persistUserMirror(session);
renderShellIdentity(session);
window.dispatchEvent(new CustomEvent('crank:sessionchange', { detail: session }));
return session;
}
async function fetchSession(force) {
if (!force && sessionCache) {
return sessionCache;
}
if (!force && sessionPromise) {
return sessionPromise;
}
sessionPromise = window.CrankApi.getSession()
.then(function(session) {
return replaceSession(session);
})
.catch(function(error) {
clearUserMirror();
throw error;
})
.finally(function() {
sessionPromise = null;
});
return sessionPromise;
}
async function guardProtectedPage() {
try {
return await fetchSession(false);
} catch (error) {
if (error && error.status === 401) {
window.location.replace(loginUrl());
return null;
}
throw error;
}
}
async function guardLoginPage() {
try {
await fetchSession(false);
window.location.replace(homeUrl());
} catch (error) {
if (!error || error.status !== 401) {
throw error;
}
}
}
async function login(email, password) {
var session = await window.CrankApi.login({
email: email,
password: password,
});
replaceSession(session);
window.location.href = homeUrl();
}
async function logout() {
try {
await window.CrankApi.logout();
} finally {
clearUserMirror();
window.location.href = loginUrl();
}
}
function handleUnauthorized() {
if (isLoginPage()) {
clearUserMirror();
return;
}
clearUserMirror();
window.location.replace(loginUrl());
}
window.CrankAuth = {
fetchSession: fetchSession,
replaceSession: replaceSession,
guardProtectedPage: guardProtectedPage,
guardLoginPage: guardLoginPage,
login: login,
logout: logout,
handleUnauthorized: handleUnauthorized,
};
window.addEventListener('crank:workspacechange', function() {
renderShellIdentity(sessionCache);
});
window.addEventListener('crank:sessionchange', function(event) {
renderShellIdentity(event.detail || sessionCache);
});
document.addEventListener('DOMContentLoaded', function() {
renderShellIdentity(sessionCache);
});
}());