feat: add account selection support in web UI
Add support for multiple MyIce accounts in the web interface: - Create /accounts endpoint to fetch available accounts from config files - Update index.html to dynamically show available accounts - Modify /schedule and /game endpoints to accept account parameter - Store selected account in localStorage for persistence
This commit is contained in:
58
index.html
58
index.html
@@ -16,6 +16,12 @@
|
|||||||
<div id="apikeyContainer" class="mb-3"></div>
|
<div id="apikeyContainer" class="mb-3"></div>
|
||||||
|
|
||||||
<div id="eventFilters" style="display: none;">
|
<div id="eventFilters" style="display: none;">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="account" class="form-label">Sélectionner un compte</label>
|
||||||
|
<select id="account" class="form-select">
|
||||||
|
<option value="default">Compte par défaut</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="agegroup" class="form-label">Filtrer par groupe d'âge</label>
|
<label for="agegroup" class="form-label">Filtrer par groupe d'âge</label>
|
||||||
<select id="agegroup" class="form-select">
|
<select id="agegroup" class="form-select">
|
||||||
@@ -46,6 +52,7 @@
|
|||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
const apikeyContainer = document.getElementById("apikeyContainer");
|
const apikeyContainer = document.getElementById("apikeyContainer");
|
||||||
const eventFilters = document.getElementById("eventFilters");
|
const eventFilters = document.getElementById("eventFilters");
|
||||||
|
const accountSelect = document.getElementById("account");
|
||||||
const agegroupSelect = document.getElementById("agegroup");
|
const agegroupSelect = document.getElementById("agegroup");
|
||||||
const eventList = document.getElementById("eventList");
|
const eventList = document.getElementById("eventList");
|
||||||
const fetchButton = document.getElementById("fetchEvents");
|
const fetchButton = document.getElementById("fetchEvents");
|
||||||
@@ -54,16 +61,20 @@
|
|||||||
|
|
||||||
let storedApiKey = localStorage.getItem("apikey");
|
let storedApiKey = localStorage.getItem("apikey");
|
||||||
let lastFetchedEvents = [];
|
let lastFetchedEvents = [];
|
||||||
|
let storedAccount = localStorage.getItem("account") || "default";
|
||||||
|
|
||||||
function renderApiKeyInput() {
|
function renderApiKeyInput() {
|
||||||
if (storedApiKey) {
|
if (storedApiKey) {
|
||||||
apikeyContainer.innerHTML = `<button id="disconnect" class="btn btn-danger">Déconnecter</button>`;
|
apikeyContainer.innerHTML = `<button id="disconnect" class="btn btn-danger">Déconnecter</button>`;
|
||||||
document.getElementById("disconnect").addEventListener("click", () => {
|
document.getElementById("disconnect").addEventListener("click", () => {
|
||||||
localStorage.removeItem("apikey");
|
localStorage.removeItem("apikey");
|
||||||
|
localStorage.removeItem("account");
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
eventFilters.style.display = "block";
|
eventFilters.style.display = "block";
|
||||||
fetchEvents(storedApiKey);
|
// Load available accounts from server or use predefined ones
|
||||||
|
updateAccountOptions();
|
||||||
|
fetchEvents(storedApiKey, storedAccount);
|
||||||
} else {
|
} else {
|
||||||
apikeyContainer.innerHTML = `
|
apikeyContainer.innerHTML = `
|
||||||
<label for="apikey" class="form-label">API Key</label>
|
<label for="apikey" class="form-label">API Key</label>
|
||||||
@@ -90,22 +101,58 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateAccountOptions() {
|
||||||
|
// Fetch available accounts from the server
|
||||||
|
fetch(`${apiBaseUrl}/accounts`, {
|
||||||
|
headers: { "Authorization": `Bearer ${storedApiKey}` }
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(accounts => {
|
||||||
|
accountSelect.innerHTML = '';
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error("Erreur lors du chargement des comptes:", error);
|
||||||
|
// Fallback to default options
|
||||||
|
accountSelect.innerHTML = `
|
||||||
|
<option value="default" ${storedAccount === "default" ? "selected" : ""}>Compte par défaut</option>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
renderApiKeyInput();
|
renderApiKeyInput();
|
||||||
|
|
||||||
|
accountSelect.addEventListener("change", () => {
|
||||||
|
const selectedAccount = accountSelect.value;
|
||||||
|
localStorage.setItem("account", selectedAccount);
|
||||||
|
if (storedApiKey) {
|
||||||
|
fetchEvents(storedApiKey, selectedAccount);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
fetchButton.addEventListener("click", () => {
|
fetchButton.addEventListener("click", () => {
|
||||||
if (!storedApiKey) {
|
if (!storedApiKey) {
|
||||||
alert("Veuillez entrer une clé API");
|
alert("Veuillez entrer une clé API");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fetchEvents(storedApiKey);
|
const selectedAccount = accountSelect.value;
|
||||||
|
fetchEvents(storedApiKey, selectedAccount);
|
||||||
});
|
});
|
||||||
|
|
||||||
agegroupSelect.addEventListener("change", () => {
|
agegroupSelect.addEventListener("change", () => {
|
||||||
displayEvents(lastFetchedEvents);
|
displayEvents(lastFetchedEvents);
|
||||||
});
|
});
|
||||||
|
|
||||||
function fetchEvents(apiKey) {
|
function fetchEvents(apiKey, account) {
|
||||||
fetch(`${apiBaseUrl}/schedule`, {
|
fetch(`${apiBaseUrl}/schedule?account=${account}`, {
|
||||||
headers: { "Authorization": `Bearer ${apiKey}` }
|
headers: { "Authorization": `Bearer ${apiKey}` }
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
@@ -156,7 +203,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fetchEventDetails(eventId) {
|
function fetchEventDetails(eventId) {
|
||||||
fetch(`${apiBaseUrl}/game/${eventId}`, {
|
const selectedAccount = accountSelect.value;
|
||||||
|
fetch(`${apiBaseUrl}/game/${eventId}?account=${selectedAccount}`, {
|
||||||
headers: { "Authorization": `Bearer ${storedApiKey}` }
|
headers: { "Authorization": `Bearer ${storedApiKey}` }
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
|
|||||||
@@ -74,35 +74,86 @@ async def favico():
|
|||||||
@app.get("/schedule")
|
@app.get("/schedule")
|
||||||
async def schedule(
|
async def schedule(
|
||||||
headers: Annotated[AuthHeaders, Header()],
|
headers: Annotated[AuthHeaders, Header()],
|
||||||
|
account: str = "default",
|
||||||
):
|
):
|
||||||
if not headers.authorized():
|
if not headers.authorized():
|
||||||
raise HTTPException(401, detail="get out")
|
raise HTTPException(401, detail="get out")
|
||||||
username, password, userid, existing_token, club_id = myice.get_login()
|
username, password, userid, existing_token, club_id = myice.get_login(
|
||||||
|
config_section=account
|
||||||
|
)
|
||||||
if existing_token:
|
if existing_token:
|
||||||
myice.userdata = {
|
myice.userdata = {
|
||||||
"id": userid,
|
"id": userid,
|
||||||
"id_club": 186,
|
"id_club": club_id or 186,
|
||||||
"token": existing_token,
|
"token": existing_token,
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
myice.userdata = myice.mobile_login()
|
myice.userdata = myice.mobile_login(config_section=account)
|
||||||
return myice.refresh_data()["club_games"]
|
return myice.refresh_data()["club_games"]
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/accounts")
|
||||||
|
async def accounts(
|
||||||
|
headers: Annotated[AuthHeaders, Header()],
|
||||||
|
):
|
||||||
|
if not headers.authorized():
|
||||||
|
raise HTTPException(401, detail="get out")
|
||||||
|
|
||||||
|
# Import configparser to read the available sections
|
||||||
|
import configparser
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
config_files = [
|
||||||
|
Path("~/.config/myice.ini").expanduser(),
|
||||||
|
Path("myice.ini"),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Read all config files
|
||||||
|
for config_file in config_files:
|
||||||
|
if config_file.exists():
|
||||||
|
try:
|
||||||
|
config.read(config_file, encoding="utf-8")
|
||||||
|
except Exception:
|
||||||
|
# Try without specifying encoding
|
||||||
|
config.read(config_file)
|
||||||
|
|
||||||
|
# Get all sections (accounts) from the config
|
||||||
|
accounts = []
|
||||||
|
for section in config.sections():
|
||||||
|
if section != "DEFAULT": # Skip DEFAULT section
|
||||||
|
# Capitalize first letter for display
|
||||||
|
label = (
|
||||||
|
section[0].upper() + section[1:]
|
||||||
|
if len(section) > 1
|
||||||
|
else section.upper()
|
||||||
|
)
|
||||||
|
accounts.append({"name": section, "label": label})
|
||||||
|
|
||||||
|
# If no accounts found, return default
|
||||||
|
if not accounts:
|
||||||
|
accounts = [{"name": "default", "label": "Default"}]
|
||||||
|
|
||||||
|
return accounts
|
||||||
|
|
||||||
|
|
||||||
@app.get("/game/{game_id}")
|
@app.get("/game/{game_id}")
|
||||||
async def game(
|
async def game(
|
||||||
headers: Annotated[AuthHeaders, Header()],
|
headers: Annotated[AuthHeaders, Header()],
|
||||||
game_id: int,
|
game_id: int,
|
||||||
|
account: str = "default",
|
||||||
):
|
):
|
||||||
username, password, userid, existing_token, club_id = myice.get_login()
|
username, password, userid, existing_token, club_id = myice.get_login(
|
||||||
|
config_section=account
|
||||||
|
)
|
||||||
if existing_token:
|
if existing_token:
|
||||||
myice.userdata = {
|
myice.userdata = {
|
||||||
"id": userid,
|
"id": userid,
|
||||||
"id_club": 186,
|
"id_club": club_id or 186,
|
||||||
"token": existing_token,
|
"token": existing_token,
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
myice.userdata = myice.mobile_login()
|
myice.userdata = myice.mobile_login(config_section=account)
|
||||||
|
|
||||||
# data = refresh_data()
|
# data = refresh_data()
|
||||||
with requests.post(
|
with requests.post(
|
||||||
|
|||||||
Reference in New Issue
Block a user