Fix Avatar-Anzeige: Auth-Header bei Avatar-Requests mitsenden
Avatar-Bilder wurden per <img src="..."> geladen, was keinen Authorization-Header mitsendet. Der Endpoint erfordert aber Auth, daher kam immer 401 zurück. Jetzt werden alle Avatar-Requests per fetch() mit Bearer-Token geladen und als Blob-URL gesetzt.
This commit is contained in:
@@ -162,17 +162,27 @@ function bindLoginForm() {
|
|||||||
|
|
||||||
// ── Avatar Helper ────────────────────────────────────────
|
// ── Avatar Helper ────────────────────────────────────────
|
||||||
function loadAvatarImage(avatarEl, username) {
|
function loadAvatarImage(avatarEl, username) {
|
||||||
|
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();
|
const img = new Image();
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
avatarEl.innerHTML = '';
|
avatarEl.innerHTML = '';
|
||||||
img.style.cssText = 'width:100%;height:100%;object-fit:cover;position:absolute;inset:0';
|
img.style.cssText = 'width:100%;height:100%;object-fit:cover;position:absolute;inset:0';
|
||||||
avatarEl.appendChild(img);
|
avatarEl.appendChild(img);
|
||||||
};
|
};
|
||||||
img.onerror = () => {
|
img.src = URL.createObjectURL(blob);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
avatarEl.innerHTML = '';
|
avatarEl.innerHTML = '';
|
||||||
avatarEl.textContent = (username || '?')[0].toUpperCase();
|
avatarEl.textContent = (username || '?')[0].toUpperCase();
|
||||||
};
|
});
|
||||||
img.src = `/api/profile/avatar?t=${Date.now()}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Start ─────────────────────────────────────────────────
|
// ── Start ─────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -4,6 +4,17 @@ import { renderMonth } from './views/month.js';
|
|||||||
import { renderWeek } from './views/week.js';
|
import { renderWeek } from './views/week.js';
|
||||||
import { renderAgenda } from './views/agenda.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)
|
// week start day global (loaded from settings)
|
||||||
let weekStartDay = 'monday';
|
let weekStartDay = 'monday';
|
||||||
|
|
||||||
@@ -751,9 +762,15 @@ export function openProfileModal() {
|
|||||||
const img = document.getElementById('profile-avatar-img');
|
const img = document.getElementById('profile-avatar-img');
|
||||||
const removeBtn = document.getElementById('profile-avatar-remove');
|
const removeBtn = document.getElementById('profile-avatar-remove');
|
||||||
if (profile.has_avatar) {
|
if (profile.has_avatar) {
|
||||||
img.src = `/api/profile/avatar?t=${Date.now()}`;
|
fetchAvatarBlob().then(blobUrl => {
|
||||||
|
img.src = blobUrl;
|
||||||
img.classList.remove('hidden');
|
img.classList.remove('hidden');
|
||||||
letter.classList.add('hidden');
|
letter.classList.add('hidden');
|
||||||
|
}).catch(() => {
|
||||||
|
img.classList.add('hidden');
|
||||||
|
letter.classList.remove('hidden');
|
||||||
|
letter.textContent = (user.username || '?')[0].toUpperCase();
|
||||||
|
});
|
||||||
removeBtn.classList.remove('hidden');
|
removeBtn.classList.remove('hidden');
|
||||||
} else {
|
} else {
|
||||||
img.classList.add('hidden');
|
img.classList.add('hidden');
|
||||||
@@ -899,18 +916,19 @@ function bindProfileModal() {
|
|||||||
function updateTopbarAvatar(hasAvatar) {
|
function updateTopbarAvatar(hasAvatar) {
|
||||||
const avatar = document.getElementById('user-avatar');
|
const avatar = document.getElementById('user-avatar');
|
||||||
if (hasAvatar) {
|
if (hasAvatar) {
|
||||||
|
fetchAvatarBlob().then(blobUrl => {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
avatar.innerHTML = '';
|
avatar.innerHTML = '';
|
||||||
img.style.cssText = 'width:100%;height:100%;object-fit:cover;position:absolute;inset:0';
|
img.style.cssText = 'width:100%;height:100%;object-fit:cover;position:absolute;inset:0';
|
||||||
avatar.appendChild(img);
|
avatar.appendChild(img);
|
||||||
};
|
};
|
||||||
img.onerror = () => {
|
img.src = blobUrl;
|
||||||
|
}).catch(() => {
|
||||||
avatar.innerHTML = '';
|
avatar.innerHTML = '';
|
||||||
const u = JSON.parse(localStorage.getItem('user')||'{}');
|
const u = JSON.parse(localStorage.getItem('user')||'{}');
|
||||||
avatar.textContent = (u.username||'?')[0].toUpperCase();
|
avatar.textContent = (u.username||'?')[0].toUpperCase();
|
||||||
};
|
});
|
||||||
img.src = `/api/profile/avatar?t=${Date.now()}`;
|
|
||||||
// Update localStorage so avatar persists across reloads
|
// Update localStorage so avatar persists across reloads
|
||||||
const u = JSON.parse(localStorage.getItem('user')||'{}');
|
const u = JSON.parse(localStorage.getItem('user')||'{}');
|
||||||
u.has_avatar = true;
|
u.has_avatar = true;
|
||||||
@@ -1047,9 +1065,11 @@ document.getElementById('crop-save').onclick = async () => {
|
|||||||
showToast('Profilbild hochgeladen');
|
showToast('Profilbild hochgeladen');
|
||||||
// Update profile modal avatar
|
// Update profile modal avatar
|
||||||
const img = document.getElementById('profile-avatar-img');
|
const img = document.getElementById('profile-avatar-img');
|
||||||
img.src = `/api/profile/avatar?t=${Date.now()}`;
|
fetchAvatarBlob().then(blobUrl => {
|
||||||
|
img.src = blobUrl;
|
||||||
img.classList.remove('hidden');
|
img.classList.remove('hidden');
|
||||||
document.getElementById('profile-avatar-letter').classList.add('hidden');
|
document.getElementById('profile-avatar-letter').classList.add('hidden');
|
||||||
|
});
|
||||||
document.getElementById('profile-avatar-remove').classList.remove('hidden');
|
document.getElementById('profile-avatar-remove').classList.remove('hidden');
|
||||||
// Update topbar avatar
|
// Update topbar avatar
|
||||||
updateTopbarAvatar(true);
|
updateTopbarAvatar(true);
|
||||||
|
|||||||
Reference in New Issue
Block a user