From a1001bad68da6ebe9711ee6b817a9172acf620ac Mon Sep 17 00:00:00 2001 From: Scarriffle Date: Thu, 26 Mar 2026 19:23:58 +0100 Subject: [PATCH] =?UTF-8?q?Fix=20Avatar-Anzeige:=20Auth-Header=20bei=20Ava?= =?UTF-8?q?tar-Requests=20mitsenden=20Avatar-Bilder=20wurden=20per=20=20geladen,=20was=20keinen=20Authorization-Heade?= =?UTF-8?q?r=20mitsendet.=20Der=20Endpoint=20erfordert=20aber=20Auth,=20da?= =?UTF-8?q?her=20kam=20immer=20401=20zur=C3=BCck.=20Jetzt=20werden=20alle?= =?UTF-8?q?=20Avatar-Requests=20per=20fetch()=20mit=20Bearer-Token=20gelad?= =?UTF-8?q?en=20und=20als=20Blob-URL=20gesetzt.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/js/app.js | 32 +++++++++++++++++--------- frontend/js/calendar.js | 50 ++++++++++++++++++++++++++++------------- 2 files changed, 56 insertions(+), 26 deletions(-) diff --git a/frontend/js/app.js b/frontend/js/app.js index 718a0ca..c77d7e6 100644 --- a/frontend/js/app.js +++ b/frontend/js/app.js @@ -162,17 +162,27 @@ function bindLoginForm() { // ── Avatar Helper ──────────────────────────────────────── function loadAvatarImage(avatarEl, username) { - const img = new Image(); - img.onload = () => { - avatarEl.innerHTML = ''; - img.style.cssText = 'width:100%;height:100%;object-fit:cover;position:absolute;inset:0'; - avatarEl.appendChild(img); - }; - img.onerror = () => { - avatarEl.innerHTML = ''; - avatarEl.textContent = (username || '?')[0].toUpperCase(); - }; - img.src = `/api/profile/avatar?t=${Date.now()}`; + const token = localStorage.getItem('token'); + fetch(`/api/profile/avatar?t=${Date.now()}`, { + headers: token ? { 'Authorization': `Bearer ${token}` } : {} + }) + .then(res => { + if (!res.ok) throw new Error('No avatar'); + return res.blob(); + }) + .then(blob => { + const img = new Image(); + img.onload = () => { + avatarEl.innerHTML = ''; + img.style.cssText = 'width:100%;height:100%;object-fit:cover;position:absolute;inset:0'; + avatarEl.appendChild(img); + }; + img.src = URL.createObjectURL(blob); + }) + .catch(() => { + avatarEl.innerHTML = ''; + avatarEl.textContent = (username || '?')[0].toUpperCase(); + }); } // ── Start ───────────────────────────────────────────────── diff --git a/frontend/js/calendar.js b/frontend/js/calendar.js index 159b1bb..99e3c9c 100644 --- a/frontend/js/calendar.js +++ b/frontend/js/calendar.js @@ -4,6 +4,17 @@ import { renderMonth } from './views/month.js'; import { renderWeek } from './views/week.js'; import { renderAgenda } from './views/agenda.js'; +// Fetch avatar image as blob URL (with auth header) +function fetchAvatarBlob() { + const token = localStorage.getItem('token'); + return fetch(`/api/profile/avatar?t=${Date.now()}`, { + headers: token ? { 'Authorization': `Bearer ${token}` } : {} + }).then(res => { + if (!res.ok) throw new Error('No avatar'); + return res.blob(); + }).then(blob => URL.createObjectURL(blob)); +} + // week start day global (loaded from settings) let weekStartDay = 'monday'; @@ -751,9 +762,15 @@ export function openProfileModal() { const img = document.getElementById('profile-avatar-img'); const removeBtn = document.getElementById('profile-avatar-remove'); if (profile.has_avatar) { - img.src = `/api/profile/avatar?t=${Date.now()}`; - img.classList.remove('hidden'); - letter.classList.add('hidden'); + fetchAvatarBlob().then(blobUrl => { + img.src = blobUrl; + img.classList.remove('hidden'); + letter.classList.add('hidden'); + }).catch(() => { + img.classList.add('hidden'); + letter.classList.remove('hidden'); + letter.textContent = (user.username || '?')[0].toUpperCase(); + }); removeBtn.classList.remove('hidden'); } else { img.classList.add('hidden'); @@ -899,18 +916,19 @@ function bindProfileModal() { function updateTopbarAvatar(hasAvatar) { const avatar = document.getElementById('user-avatar'); if (hasAvatar) { - const img = new Image(); - img.onload = () => { - avatar.innerHTML = ''; - img.style.cssText = 'width:100%;height:100%;object-fit:cover;position:absolute;inset:0'; - avatar.appendChild(img); - }; - img.onerror = () => { + fetchAvatarBlob().then(blobUrl => { + const img = new Image(); + img.onload = () => { + avatar.innerHTML = ''; + img.style.cssText = 'width:100%;height:100%;object-fit:cover;position:absolute;inset:0'; + avatar.appendChild(img); + }; + img.src = blobUrl; + }).catch(() => { avatar.innerHTML = ''; const u = JSON.parse(localStorage.getItem('user')||'{}'); avatar.textContent = (u.username||'?')[0].toUpperCase(); - }; - img.src = `/api/profile/avatar?t=${Date.now()}`; + }); // Update localStorage so avatar persists across reloads const u = JSON.parse(localStorage.getItem('user')||'{}'); u.has_avatar = true; @@ -1047,9 +1065,11 @@ document.getElementById('crop-save').onclick = async () => { showToast('Profilbild hochgeladen'); // Update profile modal avatar const img = document.getElementById('profile-avatar-img'); - img.src = `/api/profile/avatar?t=${Date.now()}`; - img.classList.remove('hidden'); - document.getElementById('profile-avatar-letter').classList.add('hidden'); + fetchAvatarBlob().then(blobUrl => { + img.src = blobUrl; + img.classList.remove('hidden'); + document.getElementById('profile-avatar-letter').classList.add('hidden'); + }); document.getElementById('profile-avatar-remove').classList.remove('hidden'); // Update topbar avatar updateTopbarAvatar(true);