From ac727c6c5ba0e4f4501b1242ca9b45c65ec6280e Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Fri, 3 Oct 2025 19:49:19 +0200 Subject: [PATCH] =?UTF-8?q?F=C3=BCgt=20die=20Funktionalit=C3=A4t=20zur=20A?= =?UTF-8?q?ktualisierung=20der=20Vereinseinstellungen=20hinzu.=20Implement?= =?UTF-8?q?iert=20die=20Methode=20`updateClubSettings`=20im=20`clubsContro?= =?UTF-8?q?ller`,=20um=20Begr=C3=BC=C3=9Fungstexte=20und=20Mitgliedsnummer?= =?UTF-8?q?n=20zu=20aktualisieren.=20Aktualisiert=20das=20`Club`-Modell,?= =?UTF-8?q?=20um=20neue=20Felder=20f=C3=BCr=20`greetingText`=20und=20`asso?= =?UTF-8?q?ciationMemberNumber`=20zu=20unterst=C3=BCtzen.=20Erg=C3=A4nzt?= =?UTF-8?q?=20die=20Routen=20in=20`clubRoutes`,=20um=20die=20neuen=20Einst?= =?UTF-8?q?ellungen=20zu=20verarbeiten.=20F=C3=BCgt=20eine=20neue=20Ansich?= =?UTF-8?q?t=20f=C3=BCr=20die=20Vereins-Einstellungen=20im=20Frontend=20hi?= =?UTF-8?q?nzu=20und=20aktualisiert=20die=20Navigation=20entsprechend.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/controllers/clubsController.js | 19 + .../add_greeting_and_association_to_clubs.sql | 5 + backend/models/Club.js | 10 + backend/routes/clubRoutes.js | 3 +- backend/routes/nuscoreApiRoutes.js | 8 - backend/services/clubService.js | 9 + backend/services/nuscoreProxyService.js | 9 - frontend/src/App.vue | 4 + frontend/src/components/DialogManager.vue | 2 - .../src/components/MatchReportApiDialog.vue | 1014 ++++++++++++++++- frontend/src/router.js | 2 + frontend/src/views/ClubSettings.vue | 107 ++ 12 files changed, 1144 insertions(+), 48 deletions(-) create mode 100644 backend/migrations/add_greeting_and_association_to_clubs.sql create mode 100644 frontend/src/views/ClubSettings.vue diff --git a/backend/controllers/clubsController.js b/backend/controllers/clubsController.js index 848e288..900d0a0 100644 --- a/backend/controllers/clubsController.js +++ b/backend/controllers/clubsController.js @@ -56,6 +56,25 @@ export const getClub = async (req, res) => { } }; +export const updateClubSettings = async (req, res) => { + try { + const { authcode: token } = req.headers; + const { clubid } = req.params; + const { greetingText, associationMemberNumber } = req.body; + const updated = await ClubService.updateClubSettings(token, clubid, { greetingText, associationMemberNumber }); + res.status(200).json(updated); + } catch (error) { + if (error.message === 'noaccess') { + res.status(403).json({ error: 'noaccess' }); + } else if (error.message === 'clubnotfound') { + res.status(404).json({ error: 'clubnotfound' }); + } else { + console.error('[updateClubSettings] - error:', error); + res.status(500).json({ error: 'internalerror' }); + } + } +}; + export const requestClubAccess = async (req, res) => { const { authcode: token } = req.headers; const { clubid: clubId } = req.params; diff --git a/backend/migrations/add_greeting_and_association_to_clubs.sql b/backend/migrations/add_greeting_and_association_to_clubs.sql new file mode 100644 index 0000000..95263a6 --- /dev/null +++ b/backend/migrations/add_greeting_and_association_to_clubs.sql @@ -0,0 +1,5 @@ +ALTER TABLE clubs + ADD COLUMN IF NOT EXISTS greeting_text TEXT NULL, + ADD COLUMN IF NOT EXISTS association_member_number VARCHAR(255) NULL; + + diff --git a/backend/models/Club.js b/backend/models/Club.js index 303125c..dba014b 100644 --- a/backend/models/Club.js +++ b/backend/models/Club.js @@ -7,6 +7,16 @@ const Club = sequelize.define('Club', { allowNull: false, unique: true, }, + greetingText: { + type: DataTypes.TEXT, + allowNull: true, + field: 'greeting_text' + }, + associationMemberNumber: { + type: DataTypes.STRING, + allowNull: true, + field: 'association_member_number' + }, }, { tableName: 'clubs', underscored: true, diff --git a/backend/routes/clubRoutes.js b/backend/routes/clubRoutes.js index 024104a..d719526 100644 --- a/backend/routes/clubRoutes.js +++ b/backend/routes/clubRoutes.js @@ -1,11 +1,12 @@ import express from 'express'; import { authenticate } from '../middleware/authMiddleware.js'; -import { getClubs, addClub, getClub, requestClubAccess, getPendingApprovals, approveClubAccess, rejectClubAccess } from '../controllers/clubsController.js'; +import { getClubs, addClub, getClub, requestClubAccess, getPendingApprovals, approveClubAccess, rejectClubAccess, updateClubSettings } from '../controllers/clubsController.js'; const router = express.Router(); router.get('/', authenticate, getClubs); router.post('/', authenticate, addClub); +router.put('/:clubid/settings', authenticate, updateClubSettings); router.get('/:clubid', authenticate, getClub); router.get('/request/:clubid', authenticate, requestClubAccess); router.get('/pending/:clubid', authenticate, getPendingApprovals); diff --git a/backend/routes/nuscoreApiRoutes.js b/backend/routes/nuscoreApiRoutes.js index 1020c04..ca2be52 100644 --- a/backend/routes/nuscoreApiRoutes.js +++ b/backend/routes/nuscoreApiRoutes.js @@ -31,7 +31,6 @@ function formatCookies(cookies) { // Meeting-Info API-Endpunkt router.get('/meetinginfo/:code', async (req, res) => { const { code } = req.params; - console.log(`📊 Meeting-Info API fĂŒr Code: ${code}`); try { // Hole Cookies fĂŒr diesen Code (falls vorhanden) @@ -65,7 +64,6 @@ router.get('/meetinginfo/:code', async (req, res) => { const newCookies = extractCookies(response.headers.raw()['set-cookie']); if (Object.keys(newCookies).length > 0) { cookieStore.set(code, { ...cookies, ...newCookies }); - console.log(`đŸȘ Cookies fĂŒr Code ${code} gespeichert:`, Object.keys(newCookies)); } // CORS-Header setzen @@ -78,7 +76,6 @@ router.get('/meetinginfo/:code', async (req, res) => { }); res.json(data); - console.log(`✅ Meeting-Info fĂŒr Code ${code} erfolgreich abgerufen`); } catch (error) { console.error(`❌ Fehler beim Abrufen der Meeting-Info fĂŒr Code ${code}:`, error); @@ -92,7 +89,6 @@ router.get('/meetinginfo/:code', async (req, res) => { // Cookie-Initialisierung (fĂŒr den ersten Request) router.post('/init-cookies/:code', async (req, res) => { const { code } = req.params; - console.log(`đŸȘ Cookie-Initialisierung fĂŒr Code: ${code}`); try { // Erster Request an die nuscore-Seite um Cookies zu erhalten @@ -111,7 +107,6 @@ router.post('/init-cookies/:code', async (req, res) => { const cookies = extractCookies(response.headers.raw()['set-cookie']); if (Object.keys(cookies).length > 0) { cookieStore.set(code, cookies); - console.log(`đŸȘ Cookies fĂŒr Code ${code} initialisiert:`, Object.keys(cookies)); } res.json({ @@ -132,7 +127,6 @@ router.post('/init-cookies/:code', async (req, res) => { // Detaillierte Meeting-Daten API-Endpunkt router.get('/meetingdetails/:uuid', async (req, res) => { const { uuid } = req.params; - console.log(`📊 Meeting-Details API fĂŒr UUID: ${uuid}`); try { // Hole Cookies fĂŒr diesen Code (falls vorhanden) @@ -166,7 +160,6 @@ router.get('/meetingdetails/:uuid', async (req, res) => { const newCookies = extractCookies(response.headers.raw()['set-cookie']); if (Object.keys(newCookies).length > 0) { cookieStore.set(uuid, { ...cookies, ...newCookies }); - console.log(`đŸȘ Cookies fĂŒr UUID ${uuid} gespeichert:`, Object.keys(newCookies)); } // CORS-Header setzen @@ -179,7 +172,6 @@ router.get('/meetingdetails/:uuid', async (req, res) => { }); res.json(data); - console.log(`✅ Meeting-Details fĂŒr UUID ${uuid} erfolgreich abgerufen`); } catch (error) { console.error(`❌ Fehler beim Abrufen der Meeting-Details fĂŒr UUID ${uuid}:`, error); diff --git a/backend/services/clubService.js b/backend/services/clubService.js index 0b1ee26..1c71cc1 100644 --- a/backend/services/clubService.js +++ b/backend/services/clubService.js @@ -55,6 +55,15 @@ class ClubService { }); } + async updateClubSettings(userToken, clubId, { greetingText, associationMemberNumber }) { + await checkAccess(userToken, clubId); + const club = await Club.findByPk(clubId); + if (!club) { + throw new Error('clubnotfound'); + } + return await club.update({ greetingText, associationMemberNumber }); + } + async approveUserClubAccess(userToken, clubId, toApproveUserId) { await checkAccess(userToken, clubId); const toApproveUserClub = await UserClub.findOne({ diff --git a/backend/services/nuscoreProxyService.js b/backend/services/nuscoreProxyService.js index f1b62a7..46a2f1e 100644 --- a/backend/services/nuscoreProxyService.js +++ b/backend/services/nuscoreProxyService.js @@ -8,7 +8,6 @@ class NuscoreProxyService { async initialize() { if (!this.browser) { - console.log('🚀 Initialisiere Playwright Browser...'); this.browser = await chromium.launch({ headless: true, args: [ @@ -26,7 +25,6 @@ class NuscoreProxyService { ignoreHTTPSErrors: true }); - console.log('✅ Playwright Browser initialisiert'); } } @@ -34,7 +32,6 @@ class NuscoreProxyService { try { await this.initialize(); - console.log(`🔍 Lade nuscore-Seite fĂŒr Code: ${code}`); const page = await this.context.newPage(); @@ -45,17 +42,14 @@ class NuscoreProxyService { timeout: 30000 }); - console.log('📄 Seite geladen'); // Optional: PIN automatisch einfĂŒgen falls vorhanden if (pin) { - console.log(`🔑 Versuche PIN ${pin} einzufĂŒgen...`); try { // Suche nach PIN-Eingabefeld const pinInput = await page.locator('input[type="password"][placeholder*="PIN"], input[placeholder*="Pin"], input[placeholder*="pin"]').first(); if (await pinInput.isVisible()) { await pinInput.fill(pin); - console.log('✅ PIN eingefĂŒgt'); // Optional: Submit-Button klicken falls vorhanden const submitBtn = await page.locator('button[type="submit"], input[type="submit"], button:has-text("Einloggen"), button:has-text("Anmelden")').first(); @@ -65,7 +59,6 @@ class NuscoreProxyService { } } } catch (error) { - console.log('⚠ PIN-EinfĂŒgung fehlgeschlagen:', error.message); } } @@ -77,7 +70,6 @@ class NuscoreProxyService { await page.close(); - console.log('✅ nuscore-Seite erfolgreich proxiert'); return modifiedHtml; } catch (error) { @@ -138,7 +130,6 @@ class NuscoreProxyService { await this.browser.close(); this.browser = null; } - console.log('đŸ§č Playwright Browser bereinigt'); } } diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 09dc577..8184733 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -75,6 +75,10 @@