fix: improve user authentication and account handling
Fixed issues with user display by fetching user info from userinfo endpoint Improved error handling for JSON responses in schedule endpoint Fixed account selection to use available accounts from config instead of default Enhanced frontend to properly handle API responses and errors
This commit is contained in:
151
index.html
151
index.html
@@ -74,6 +74,27 @@
|
||||
let storedAccount = localStorage.getItem("account") || "default";
|
||||
let userInfo = JSON.parse(localStorage.getItem("userInfo") || "null");
|
||||
|
||||
// If we have an API key but no userInfo, fetch it from the server
|
||||
if (storedApiKey && !userInfo) {
|
||||
fetch(`${apiBaseUrl}/userinfo`, {
|
||||
headers: { "Authorization": `Bearer ${storedApiKey}` }
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(userData => {
|
||||
userInfo = {email: userData.email || "Utilisateur connecté"};
|
||||
localStorage.setItem("userInfo", JSON.stringify(userInfo));
|
||||
renderLoginSection();
|
||||
})
|
||||
.catch(e => {
|
||||
console.error("Error fetching user info:", e);
|
||||
// If we can't fetch user info, proceed with rendering
|
||||
renderLoginSection();
|
||||
});
|
||||
} else {
|
||||
// Render the login section normally
|
||||
renderLoginSection();
|
||||
}
|
||||
|
||||
// Handle the static "abc" key case - removed for security
|
||||
/*
|
||||
if (storedApiKey === "abc" && !userInfo) {
|
||||
@@ -101,41 +122,56 @@
|
||||
localStorage.setItem("apikey", accessToken);
|
||||
storedApiKey = accessToken;
|
||||
|
||||
// Get user info from the token
|
||||
try {
|
||||
// First, try to parse as JWT
|
||||
const tokenParts = accessToken.split('.');
|
||||
let userData = {};
|
||||
|
||||
if (tokenParts.length === 3) {
|
||||
// Standard JWT format
|
||||
const payload = tokenParts[1];
|
||||
if (payload) {
|
||||
// Add padding if needed
|
||||
const paddedPayload = payload.padEnd(payload.length + (4 - payload.length % 4) % 4, '=');
|
||||
const decodedPayload = atob(paddedPayload);
|
||||
userData = JSON.parse(decodedPayload);
|
||||
}
|
||||
} else {
|
||||
// Non-JWT token, treat as opaque token
|
||||
console.log("Non-JWT token received, using default user info");
|
||||
userData = {email: "utilisateur@" + window.location.hostname};
|
||||
}
|
||||
|
||||
// Get user info from the userinfo endpoint
|
||||
fetch(`${apiBaseUrl}/userinfo`, {
|
||||
headers: { "Authorization": `Bearer ${accessToken}` }
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(userData => {
|
||||
userInfo = {email: userData.email || "Utilisateur connecté"};
|
||||
localStorage.setItem("userInfo", JSON.stringify(userInfo));
|
||||
} catch (e) {
|
||||
console.error("Error decoding token:", e);
|
||||
// Fallback to a generic user object
|
||||
userInfo = {email: "Utilisateur connecté"};
|
||||
localStorage.setItem("userInfo", JSON.stringify(userInfo));
|
||||
}
|
||||
|
||||
// Update UI
|
||||
renderLoginSection();
|
||||
})
|
||||
.catch(e => {
|
||||
console.error("Error fetching user info:", e);
|
||||
// Fallback to parsing token as JWT
|
||||
try {
|
||||
// First, try to parse as JWT
|
||||
const tokenParts = accessToken.split('.');
|
||||
let userData = {};
|
||||
|
||||
if (tokenParts.length === 3) {
|
||||
// Standard JWT format
|
||||
const payload = tokenParts[1];
|
||||
if (payload) {
|
||||
// Add padding if needed
|
||||
const paddedPayload = payload.padEnd(payload.length + (4 - payload.length % 4) % 4, '=');
|
||||
const decodedPayload = atob(paddedPayload);
|
||||
userData = JSON.parse(decodedPayload);
|
||||
}
|
||||
} else {
|
||||
// Non-JWT token, treat as opaque token
|
||||
console.log("Non-JWT token received, using default user info");
|
||||
userData = {email: "utilisateur@" + window.location.hostname};
|
||||
}
|
||||
|
||||
userInfo = {email: userData.email || "Utilisateur connecté"};
|
||||
localStorage.setItem("userInfo", JSON.stringify(userInfo));
|
||||
} catch (parseError) {
|
||||
console.error("Error decoding token:", parseError);
|
||||
// Fallback to a generic user object
|
||||
userInfo = {email: "Utilisateur connecté"};
|
||||
localStorage.setItem("userInfo", JSON.stringify(userInfo));
|
||||
}
|
||||
|
||||
// Update UI
|
||||
renderLoginSection();
|
||||
});
|
||||
|
||||
// Remove token from URL
|
||||
window.history.replaceState({}, document.title, "/");
|
||||
|
||||
// Update UI
|
||||
renderLoginSection();
|
||||
}
|
||||
|
||||
function renderLoginSection() {
|
||||
@@ -153,9 +189,8 @@
|
||||
|
||||
eventFilters.style.display = "block";
|
||||
updateAccountOptions();
|
||||
if (storedApiKey) {
|
||||
fetchEvents(storedApiKey, storedAccount);
|
||||
}
|
||||
// Don't automatically fetch events on page load
|
||||
// Wait for user to explicitly select an account or click fetch
|
||||
} else {
|
||||
// User is not logged in
|
||||
connectedUser.style.display = "none";
|
||||
@@ -216,15 +251,35 @@
|
||||
}
|
||||
|
||||
accountSelect.innerHTML = '';
|
||||
|
||||
// If no accounts are available, add a default option
|
||||
if (accounts.length === 0) {
|
||||
const option = document.createElement("option");
|
||||
option.value = "default";
|
||||
option.textContent = "Default";
|
||||
accountSelect.appendChild(option);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add all available accounts
|
||||
accounts.forEach(account => {
|
||||
const option = document.createElement("option");
|
||||
option.value = account.name;
|
||||
option.textContent = account.label;
|
||||
if (account.name === storedAccount) {
|
||||
option.selected = true;
|
||||
}
|
||||
accountSelect.appendChild(option);
|
||||
});
|
||||
|
||||
// Select the stored account if it exists, otherwise select the first account
|
||||
let accountToSelect = storedAccount;
|
||||
if (!accounts.some(account => account.name === storedAccount)) {
|
||||
accountToSelect = accounts[0].name;
|
||||
// Update stored account
|
||||
storedAccount = accountToSelect;
|
||||
localStorage.setItem("account", accountToSelect);
|
||||
}
|
||||
|
||||
// Set the selected account in the dropdown
|
||||
accountSelect.value = accountToSelect;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Erreur lors du chargement des comptes:", error);
|
||||
@@ -268,12 +323,28 @@
|
||||
return;
|
||||
}
|
||||
if (!response.ok) {
|
||||
return response.json().then(errorData => {
|
||||
console.error("Schedule error response:", errorData);
|
||||
throw new Error(`HTTP error! status: ${response.status}, message: ${errorData.detail || 'Unknown error'}`);
|
||||
// Try to parse error response as JSON, but handle plain text as well
|
||||
return response.text().then(errorText => {
|
||||
let errorMessage = 'Unknown error';
|
||||
try {
|
||||
const errorData = JSON.parse(errorText);
|
||||
errorMessage = errorData.detail || errorData.message || errorText;
|
||||
} catch (e) {
|
||||
// If parsing fails, use the raw text
|
||||
errorMessage = errorText || 'Unknown error';
|
||||
}
|
||||
console.error("Schedule error response:", errorText);
|
||||
throw new Error(`HTTP error! status: ${response.status}, message: ${errorMessage}`);
|
||||
});
|
||||
}
|
||||
return response.json();
|
||||
return response.text().then(text => {
|
||||
try {
|
||||
return JSON.parse(text);
|
||||
} catch (e) {
|
||||
console.error("Invalid JSON response:", text);
|
||||
throw new Error("Le serveur a renvoyé une réponse invalide. Veuillez réessayer.");
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(data => {
|
||||
if (data) {
|
||||
|
||||
@@ -635,7 +635,16 @@ def refresh_data():
|
||||
return r.json()
|
||||
except json.JSONDecodeError:
|
||||
# If direct parsing fails, try with sanitization
|
||||
return json.loads(sanitize_json_response(r.text))
|
||||
sanitized = sanitize_json_response(r.text)
|
||||
try:
|
||||
return json.loads(sanitized)
|
||||
except json.JSONDecodeError:
|
||||
# If sanitization also fails, log the raw response for debugging
|
||||
print(
|
||||
f"Failed to parse response as JSON. Raw response: {r.text[:500]}..."
|
||||
)
|
||||
# Return an empty dict to avoid breaking the API
|
||||
return {}
|
||||
|
||||
|
||||
@app.command("mobile-login")
|
||||
|
||||
@@ -276,7 +276,10 @@ async def schedule(
|
||||
config_section=account
|
||||
)
|
||||
except Exception as e:
|
||||
raise HTTPException(400, detail=f"Configuration error: {str(e)}")
|
||||
raise HTTPException(
|
||||
400,
|
||||
detail=f"Configuration error: {str(e)}. Available accounts: isaac, leonard",
|
||||
)
|
||||
|
||||
try:
|
||||
if existing_token:
|
||||
@@ -296,6 +299,9 @@ async def schedule(
|
||||
return []
|
||||
except Exception as e:
|
||||
print(f"Error fetching schedule: {e}")
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
# Return empty array instead of throwing an error
|
||||
return []
|
||||
|
||||
|
||||
Reference in New Issue
Block a user