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:
103
index.html
103
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,7 +122,21 @@
|
||||
localStorage.setItem("apikey", accessToken);
|
||||
storedApiKey = accessToken;
|
||||
|
||||
// Get user info from the token
|
||||
// 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));
|
||||
|
||||
// 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('.');
|
||||
@@ -124,18 +159,19 @@
|
||||
|
||||
userInfo = {email: userData.email || "Utilisateur connecté"};
|
||||
localStorage.setItem("userInfo", JSON.stringify(userInfo));
|
||||
} catch (e) {
|
||||
console.error("Error decoding token:", e);
|
||||
} catch (parseError) {
|
||||
console.error("Error decoding token:", parseError);
|
||||
// Fallback to a generic user object
|
||||
userInfo = {email: "Utilisateur connecté"};
|
||||
localStorage.setItem("userInfo", JSON.stringify(userInfo));
|
||||
}
|
||||
|
||||
// Remove token from URL
|
||||
window.history.replaceState({}, document.title, "/");
|
||||
|
||||
// Update UI
|
||||
renderLoginSection();
|
||||
});
|
||||
|
||||
// Remove token from URL
|
||||
window.history.replaceState({}, document.title, "/");
|
||||
}
|
||||
|
||||
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