Chapter-Daten auf separaten data-Branch ausgelagert
chapters/ lag bisher im main-Branch, aus dem sich jede lokale Installation bedient (z.B. per ZIP-Download) — dadurch bekam jedes Chapter beim Einrichten die Mitgliederdaten aller anderen Chapter mit, obwohl die App diese Daten ohnehin nie lokal liest, sondern immer live über die Gitea-API holt. Alle Lese-/Schreibzugriffe auf chapters/* laufen jetzt gegen den neuen data-Branch (giteaDataUrl / giteaAuthUrl(..., 'data') inkl. branch: 'data' in den Schreib-Bodies). App-Code (index.html, admin.html, version.json) bleibt weiterhin auf main. chapters/ ist aus main entfernt (lokal weiterhin vorhanden, per .gitignore ausgeschlossen) und liegt vollständig auf dem neuen data-Branch.
This commit is contained in:
57
admin.html
57
admin.html
@@ -380,7 +380,8 @@ const GITEA_RAW = 'http://72.60.134.73:3000/api/v1/repos/cheubaum/BNI-Vorstellun
|
||||
const GITEA_API = 'http://72.60.134.73:3000/api/v1/repos/cheubaum/BNI-Vorstellungsrunde';
|
||||
const CHAPTER_CONFIG_KEY = 'bni-active-chapter';
|
||||
function giteaUrl(path) { return `${GITEA_RAW}/${path}?ref=main`; }
|
||||
function giteaAuthUrl(path, token) { return `${GITEA_API}/contents/${path}?token=${encodeURIComponent(token)}`; }
|
||||
function giteaDataUrl(path) { return `${GITEA_RAW}/${path}?ref=data`; }
|
||||
function giteaAuthUrl(path, token, ref) { return `${GITEA_API}/contents/${path}?token=${encodeURIComponent(token)}${ref ? '&ref=' + ref : ''}`; }
|
||||
|
||||
// ============================================================
|
||||
// CHAPTER CONFIG
|
||||
@@ -577,7 +578,7 @@ async function openImportFromChapter() {
|
||||
const listEl = document.getElementById('import-chapter-select-list');
|
||||
listEl.innerHTML = '<div style="color:var(--muted);font-size:0.85rem;">Lade Chapter…</div>';
|
||||
try {
|
||||
const res = await fetch(`${GITEA_API}/contents/chapters?ref=main`);
|
||||
const res = await fetch(`${GITEA_API}/contents/chapters?ref=data`);
|
||||
const items = await res.json();
|
||||
const chapters = Array.isArray(items) ? items.filter(i => i.type === 'dir') : [];
|
||||
if (!chapters.length) { listEl.innerHTML = '<div style="color:var(--muted);">Keine anderen Chapter gefunden.</div>'; return; }
|
||||
@@ -585,7 +586,7 @@ async function openImportFromChapter() {
|
||||
for (const ch of chapters) {
|
||||
if (activeChapter && ch.name === activeChapter.code) continue;
|
||||
try {
|
||||
const cfgRes = await fetch(giteaUrl(`chapters/${ch.name}/config.json`), { cache: 'no-store' });
|
||||
const cfgRes = await fetch(giteaDataUrl(`chapters/${ch.name}/config.json`), { cache: 'no-store' });
|
||||
const cfg = cfgRes.ok ? await cfgRes.json() : {};
|
||||
const btn = document.createElement('div');
|
||||
btn.className = 'chapter-item';
|
||||
@@ -611,7 +612,7 @@ async function loadChapterMembersForImport(code, chapterName) {
|
||||
const listEl = document.getElementById('import-member-list');
|
||||
listEl.innerHTML = '<div style="padding:12px;color:var(--muted);">Lade Mitglieder…</div>';
|
||||
try {
|
||||
const res = await fetch(giteaUrl(`chapters/${code}/members.json`));
|
||||
const res = await fetch(giteaDataUrl(`chapters/${code}/members.json`));
|
||||
if (!res.ok) { listEl.innerHTML = '<div style="padding:12px;color:#dc2626;">Keine Mitglieder gefunden.</div>'; return; }
|
||||
const data = await res.json();
|
||||
const members = data.members || [];
|
||||
@@ -669,11 +670,11 @@ async function uploadSvToGitea() {
|
||||
const path = `chapters/${activeChapter.code}/stammvertreter.json`;
|
||||
try {
|
||||
let sha = null;
|
||||
const shaRes = await fetch(giteaAuthUrl(path, token));
|
||||
const shaRes = await fetch(giteaAuthUrl(path, token, 'data'));
|
||||
if (shaRes.ok) sha = (await shaRes.json()).sha;
|
||||
const body = { message: 'Stammvertreter aktualisiert', content };
|
||||
const body = { message: 'Stammvertreter aktualisiert', content, branch: 'data' };
|
||||
if (sha) body.sha = sha;
|
||||
const res = await fetch(giteaAuthUrl(path, token), { method: sha?'PUT':'POST', headers: { 'Content-Type':'application/json' }, body: JSON.stringify(body) });
|
||||
const res = await fetch(giteaAuthUrl(path, token, 'data'), { method: sha?'PUT':'POST', headers: { 'Content-Type':'application/json' }, body: JSON.stringify(body) });
|
||||
if (res.ok) { statusEl.textContent = `✓ ${list.length} Stammvertreter gesichert`; statusEl.style.color = 'var(--success)'; }
|
||||
else { statusEl.textContent = 'Fehler beim Upload.'; statusEl.style.color = '#dc2626'; }
|
||||
} catch(e) { statusEl.textContent = 'Verbindungsfehler.'; statusEl.style.color = '#dc2626'; }
|
||||
@@ -683,7 +684,7 @@ async function downloadSvFromGitea() {
|
||||
const statusEl = document.getElementById('sv-sync-status');
|
||||
statusEl.textContent = 'Lade…'; statusEl.style.color = 'var(--muted)';
|
||||
try {
|
||||
const res = await fetch(giteaUrl(`chapters/${activeChapter.code}/stammvertreter.json`), { cache: 'no-store' });
|
||||
const res = await fetch(giteaDataUrl(`chapters/${activeChapter.code}/stammvertreter.json`), { cache: 'no-store' });
|
||||
if (!res.ok) { statusEl.textContent = 'Keine Daten auf Server.'; statusEl.style.color = 'var(--muted)'; return; }
|
||||
const data = await res.json();
|
||||
if (data.substitutes) { saveStammvertreter(data.substitutes); renderSvList(); statusEl.textContent = `✓ ${data.substitutes.length} Stammvertreter geladen`; statusEl.style.color = 'var(--success)'; }
|
||||
@@ -780,7 +781,7 @@ async function fetchMembersAdmin() {
|
||||
const statusEl = document.getElementById('members-status');
|
||||
statusEl.textContent = 'Lade vom Server…'; statusEl.style.color = 'var(--muted)';
|
||||
try {
|
||||
const res = await fetch(giteaUrl(`chapters/${activeChapter.code}/members.json`), { cache: 'no-store' });
|
||||
const res = await fetch(giteaDataUrl(`chapters/${activeChapter.code}/members.json`), { cache: 'no-store' });
|
||||
if (!res.ok) { statusEl.textContent = 'Keine Mitglieder auf Server.'; return; }
|
||||
const data = await res.json();
|
||||
if (!data.members || !data.members.length) { statusEl.textContent = 'Liste ist leer.'; return; }
|
||||
@@ -817,14 +818,14 @@ async function uploadMembersAdmin() {
|
||||
const data = { lastUpdated: new Date().toISOString().slice(0,10), members };
|
||||
const content = btoa(unescape(encodeURIComponent(JSON.stringify(data, null, 2))));
|
||||
const path = `chapters/${activeChapter.code}/members.json`;
|
||||
const url = giteaAuthUrl(path, token);
|
||||
const url = giteaAuthUrl(path, token, 'data');
|
||||
console.log('[Upload] URL:', url);
|
||||
statusEl.textContent = 'Prüfe SHA…';
|
||||
let sha = null;
|
||||
const shaRes = await fetch(url);
|
||||
console.log('[Upload] SHA-Status:', shaRes.status);
|
||||
if (shaRes.ok) sha = (await shaRes.json()).sha;
|
||||
const body = { message:`Mitglieder aktualisiert ${new Date().toLocaleDateString('de')}`, content };
|
||||
const body = { message:`Mitglieder aktualisiert ${new Date().toLocaleDateString('de')}`, content, branch: 'data' };
|
||||
if (sha) body.sha = sha;
|
||||
statusEl.textContent = sha ? 'Aktualisiere…' : 'Erstelle…';
|
||||
const res = await fetch(url, { method:sha?'PUT':'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify(body) });
|
||||
@@ -919,7 +920,7 @@ function editAgendaItem(id) {
|
||||
};
|
||||
thumb.onload = () => { if (thumbHint) thumbHint.style.display = 'none'; };
|
||||
if (thumbHint) thumbHint.style.display = 'none';
|
||||
thumb.src = it.imagePath.startsWith('http') ? it.imagePath : giteaUrl(`chapters/${activeChapter.code}/${it.imagePath}`);
|
||||
thumb.src = it.imagePath.startsWith('http') ? it.imagePath : giteaDataUrl(`chapters/${activeChapter.code}/${it.imagePath}`);
|
||||
thumb.style.display = 'block';
|
||||
} else {
|
||||
thumb.style.display = 'none';
|
||||
@@ -963,11 +964,11 @@ function handleAgendaImageFile(input) {
|
||||
|
||||
async function uploadAgendaImage(path, dataUrl, token) {
|
||||
const content = dataUrl.split(',')[1];
|
||||
const url = giteaAuthUrl(path, token);
|
||||
const url = giteaAuthUrl(path, token, 'data');
|
||||
let sha = null;
|
||||
const shaRes = await fetch(url);
|
||||
if (shaRes.ok) sha = (await shaRes.json()).sha;
|
||||
const body = { message: `Agenda-Bild aktualisiert ${new Date().toLocaleDateString('de')}`, content };
|
||||
const body = { message: `Agenda-Bild aktualisiert ${new Date().toLocaleDateString('de')}`, content, branch: 'data' };
|
||||
if (sha) body.sha = sha;
|
||||
const res = await fetch(url, { method: sha ? 'PUT' : 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });
|
||||
if (!res.ok) { const t = await res.text(); throw new Error(`${res.status}: ${t.slice(0, 80)}`); }
|
||||
@@ -1047,7 +1048,7 @@ async function fetchAgendaAdmin() {
|
||||
const statusEl = document.getElementById('agenda-status');
|
||||
statusEl.textContent = 'Lade vom Server…'; statusEl.style.color = 'var(--muted)';
|
||||
try {
|
||||
const res = await fetch(giteaUrl(`chapters/${activeChapter.code}/agenda.json`), { cache: 'no-store' });
|
||||
const res = await fetch(giteaDataUrl(`chapters/${activeChapter.code}/agenda.json`), { cache: 'no-store' });
|
||||
if (!res.ok) { statusEl.textContent = 'Noch keine Agenda auf dem Server.'; return; }
|
||||
const data = await res.json();
|
||||
const state = loadState();
|
||||
@@ -1068,11 +1069,11 @@ async function uploadAgendaAdmin() {
|
||||
const data = { items: state.agendaCatalog || [] };
|
||||
const content = btoa(unescape(encodeURIComponent(JSON.stringify(data, null, 2))));
|
||||
const path = `chapters/${activeChapter.code}/agenda.json`;
|
||||
const url = giteaAuthUrl(path, token);
|
||||
const url = giteaAuthUrl(path, token, 'data');
|
||||
let sha = null;
|
||||
const shaRes = await fetch(url);
|
||||
if (shaRes.ok) sha = (await shaRes.json()).sha;
|
||||
const body = { message: `Agenda aktualisiert ${new Date().toLocaleDateString('de')}`, content };
|
||||
const body = { message: `Agenda aktualisiert ${new Date().toLocaleDateString('de')}`, content, branch: 'data' };
|
||||
if (sha) body.sha = sha;
|
||||
const res = await fetch(url, { method: sha ? 'PUT' : 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });
|
||||
if (res.ok) { statusEl.textContent = `✓ ${data.items.length} Agenda-Punkte hochgeladen`; statusEl.style.color = 'var(--success)'; }
|
||||
@@ -1089,16 +1090,16 @@ async function loadAllChapters() {
|
||||
const container = document.getElementById('all-chapters-list');
|
||||
container.innerHTML = '<div style="color:var(--muted);font-size:0.85rem;">Lade…</div>';
|
||||
try {
|
||||
const res = await fetch(`${GITEA_API}/contents/chapters?ref=main`);
|
||||
const res = await fetch(`${GITEA_API}/contents/chapters?ref=data`);
|
||||
const items = await res.json();
|
||||
const chapters = Array.isArray(items) ? items.filter(i => i.type === 'dir') : [];
|
||||
_allChaptersData = [];
|
||||
container.innerHTML = '';
|
||||
for (const ch of chapters) {
|
||||
try {
|
||||
const cfgRes = await fetch(giteaUrl(`chapters/${ch.name}/config.json`), { cache: 'no-store' });
|
||||
const cfgRes = await fetch(giteaDataUrl(`chapters/${ch.name}/config.json`), { cache: 'no-store' });
|
||||
const cfg = cfgRes.ok ? await cfgRes.json() : {};
|
||||
const membersRes = await fetch(giteaUrl(`chapters/${ch.name}/members.json`));
|
||||
const membersRes = await fetch(giteaDataUrl(`chapters/${ch.name}/members.json`));
|
||||
const membersData = membersRes.ok ? await membersRes.json() : {};
|
||||
_allChaptersData.push({ code: ch.name, cfg });
|
||||
const isEnabled = !!cfg.memberCoordinatorReport;
|
||||
@@ -1227,18 +1228,18 @@ async function toggleCoordinatorReport(code, currentEnabled) {
|
||||
const token = getAdminToken();
|
||||
if (!token) { alert('Bitte Admin-Token in den Einstellungen eintragen.'); return; }
|
||||
try {
|
||||
const cfgRes = await fetch(giteaUrl(`chapters/${code}/config.json`), { cache: 'no-store' });
|
||||
const cfgRes = await fetch(giteaDataUrl(`chapters/${code}/config.json`), { cache: 'no-store' });
|
||||
if (!cfgRes.ok) { alert('Config nicht gefunden.'); return; }
|
||||
const cfg = await cfgRes.json();
|
||||
const shaRes = await fetch(giteaAuthUrl(`chapters/${code}/config.json`, token));
|
||||
const shaRes = await fetch(giteaAuthUrl(`chapters/${code}/config.json`, token, 'data'));
|
||||
if (!shaRes.ok) { alert('SHA-Fetch fehlgeschlagen.'); return; }
|
||||
const sha = (await shaRes.json()).sha;
|
||||
cfg.memberCoordinatorReport = !currentEnabled;
|
||||
const content = btoa(unescape(encodeURIComponent(JSON.stringify(cfg, null, 2))));
|
||||
const res = await fetch(giteaAuthUrl(`chapters/${code}/config.json`, token), {
|
||||
const res = await fetch(giteaAuthUrl(`chapters/${code}/config.json`, token, 'data'), {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ message: `Koordinatoren-Bericht ${cfg.memberCoordinatorReport ? 'aktiviert' : 'deaktiviert'} für ${code}`, content, sha })
|
||||
body: JSON.stringify({ message: `Koordinatoren-Bericht ${cfg.memberCoordinatorReport ? 'aktiviert' : 'deaktiviert'} für ${code}`, content, sha, branch: 'data' })
|
||||
});
|
||||
if (res.ok) { loadAllChapters(); }
|
||||
else { alert('Fehler beim Speichern der Konfiguration.'); }
|
||||
@@ -1253,7 +1254,7 @@ async function loadCoordinatorReportData() {
|
||||
form.style.display = 'block';
|
||||
_coordReportData = null;
|
||||
try {
|
||||
const res = await fetch(giteaUrl(`chapters/${code}/coordinator-report-${year}.json`), { cache: 'no-store' });
|
||||
const res = await fetch(giteaDataUrl(`chapters/${code}/coordinator-report-${year}.json`), { cache: 'no-store' });
|
||||
if (res.ok) _coordReportData = await res.json();
|
||||
} catch(e) {}
|
||||
if (!_coordReportData) {
|
||||
@@ -1429,14 +1430,14 @@ async function _saveCoordinatorReportToGitea(code, data) {
|
||||
_coordStatus('Speichere…');
|
||||
let sha = null;
|
||||
try {
|
||||
const shaRes = await fetch(giteaAuthUrl(path, token));
|
||||
const shaRes = await fetch(giteaAuthUrl(path, token, 'data'));
|
||||
if (shaRes.ok) sha = (await shaRes.json()).sha;
|
||||
} catch(e) {}
|
||||
const content = btoa(unescape(encodeURIComponent(JSON.stringify(data, null, 2))));
|
||||
const body = { message: `Update Koordinatoren-Bericht ${year} für ${code}`, content };
|
||||
const body = { message: `Update Koordinatoren-Bericht ${year} für ${code}`, content, branch: 'data' };
|
||||
if (sha) body.sha = sha;
|
||||
try {
|
||||
const res = await fetch(giteaAuthUrl(path, token), {
|
||||
const res = await fetch(giteaAuthUrl(path, token, 'data'), {
|
||||
method: sha ? 'PUT' : 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body)
|
||||
|
||||
Reference in New Issue
Block a user