Implement OAuth authentication and admin panel
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
- Introduced OAuth-based login flow with session management and CSRF protection. - Added admin panel for managing events and gallery content with real-time editing functionality. - Integrated Gitea API for saving files and updating repository content. - Updated `.env.example` to include OAuth and Gitea-related configurations. - Added example event and gallery JSON files for demonstration.
This commit is contained in:
94
src/pages/admin/index.astro
Normal file
94
src/pages/admin/index.astro
Normal file
@ -0,0 +1,94 @@
|
||||
---
|
||||
import Layout from "../../components/Layout.astro";
|
||||
import eventsData from "../../content/events.json";
|
||||
import imagesData from "../../content/gallery.json";
|
||||
import { getSessionFromRequest } from "../../utils/session";
|
||||
|
||||
const session = getSessionFromRequest(Astro.request);
|
||||
if (!session?.user) {
|
||||
// Not logged in: redirect to OAuth login
|
||||
return Astro.redirect("/api/auth/login");
|
||||
}
|
||||
const csrf = session.csrf;
|
||||
const events = eventsData;
|
||||
const images = imagesData;
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<section>
|
||||
<h1>Admin</h1>
|
||||
<p>Eingeloggt als {session.user.login}</p>
|
||||
<form id="editor">
|
||||
<h2>Events (JSON)</h2>
|
||||
<textarea id="events" name="events" rows="16" style="width:100%;font-family:monospace;">{JSON.stringify(events, null, 2)}</textarea>
|
||||
|
||||
<h2>Galerie (JSON)</h2>
|
||||
<textarea id="images" name="images" rows="10" style="width:100%;font-family:monospace;">{JSON.stringify(images, null, 2)}</textarea>
|
||||
|
||||
<h2>Bilder hochladen</h2>
|
||||
<input type="file" id="fileInput" multiple accept="image/*" />
|
||||
|
||||
<div style="margin-top:1rem;display:flex;gap:.5rem;">
|
||||
<button id="saveBtn" type="button">Speichern</button>
|
||||
<button id="logoutBtn" type="button">Logout</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<meta name="csrf" content={csrf} />
|
||||
<script type="module">
|
||||
const csrf = document.querySelector('meta[name="csrf"]').content;
|
||||
|
||||
async function uploadFiles(files){
|
||||
const uploads = [];
|
||||
for (const file of files){
|
||||
const arrayBuffer = await file.arrayBuffer();
|
||||
const base64 = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
|
||||
uploads.push({ path: `public/images/${file.name}`, content: base64 });
|
||||
}
|
||||
return uploads;
|
||||
}
|
||||
|
||||
async function save(){
|
||||
let events, images;
|
||||
try{
|
||||
events = JSON.parse(document.getElementById('events').value);
|
||||
images = JSON.parse(document.getElementById('images').value);
|
||||
}catch(e){
|
||||
alert('JSON fehlerhaft: ' + e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
const files = [
|
||||
{ path: 'src/content/events.json', content: JSON.stringify(events, null, 2) },
|
||||
{ path: 'src/content/gallery.json', content: JSON.stringify(images, null, 2) },
|
||||
];
|
||||
|
||||
const input = document.getElementById('fileInput');
|
||||
if (input.files && input.files.length){
|
||||
const imageFiles = await uploadFiles(input.files);
|
||||
files.push(...imageFiles);
|
||||
}
|
||||
|
||||
const res = await fetch('/api/save', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF': csrf },
|
||||
body: JSON.stringify({ files, message: 'Admin-Inhalte aktualisiert' })
|
||||
});
|
||||
if (!res.ok){
|
||||
const t = await res.text();
|
||||
alert('Fehler beim Speichern: ' + t);
|
||||
return;
|
||||
}
|
||||
alert('Gespeichert! Build wird gestartet.');
|
||||
// optional: Seite neu laden
|
||||
location.reload();
|
||||
}
|
||||
|
||||
document.getElementById('saveBtn').addEventListener('click', save);
|
||||
document.getElementById('logoutBtn').addEventListener('click', async () => {
|
||||
await fetch('/api/auth/logout', { method: 'POST' });
|
||||
location.href = '/';
|
||||
});
|
||||
</script>
|
||||
</Layout>
|
||||
Reference in New Issue
Block a user