Add linking of RFID with camera

This commit is contained in:
2025-09-03 16:42:18 +02:00
parent 33f3f613e6
commit e4f6218066
6 changed files with 1597 additions and 5 deletions

View File

@@ -998,4 +998,313 @@ router.post('/users/find', requireApiKey, async (req, res) => {
// ============================================================================
// RFID LINKING & USER MANAGEMENT ENDPOINTS (No API Key required for dashboard)
// ============================================================================
// Get all players for RFID linking (no auth required for dashboard)
router.get('/players', async (req, res) => {
try {
const result = await pool.query(
`SELECT id, firstname, lastname, birthdate, rfiduid, created_at
FROM players
ORDER BY created_at DESC`
);
res.json(result.rows);
} catch (error) {
console.error('Fehler beim Abrufen der Spieler:', error);
res.status(500).json({
success: false,
message: 'Fehler beim Abrufen der Spieler'
});
}
});
// Create new player with optional Supabase user linking (no auth required for dashboard)
router.post('/players', async (req, res) => {
const { firstname, lastname, birthdate, rfiduid, supabase_user_id } = req.body;
// Validierung
if (!firstname || !lastname || !birthdate) {
return res.status(400).json({
success: false,
message: 'Firstname, Lastname und Birthdate sind erforderlich'
});
}
try {
// Prüfen ob RFID UID bereits existiert (falls angegeben)
if (rfiduid) {
const existingRfid = await pool.query(
'SELECT id FROM players WHERE rfiduid = $1',
[rfiduid]
);
if (existingRfid.rows.length > 0) {
return res.status(409).json({
success: false,
message: 'RFID UID existiert bereits'
});
}
}
// Prüfen ob Supabase User bereits verknüpft ist
if (supabase_user_id) {
const existingUser = await pool.query(
'SELECT id FROM players WHERE supabase_user_id = $1',
[supabase_user_id]
);
if (existingUser.rows.length > 0) {
return res.status(409).json({
success: false,
message: 'Dieser Benutzer ist bereits mit einem Spieler verknüpft'
});
}
}
// Spieler in Datenbank einfügen
const result = await pool.query(
`INSERT INTO players (firstname, lastname, birthdate, rfiduid, supabase_user_id, created_at)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id, created_at`,
[firstname, lastname, birthdate, rfiduid, supabase_user_id, new Date()]
);
res.json({
success: true,
message: 'Spieler erfolgreich erstellt',
data: {
id: result.rows[0].id,
firstname: firstname,
lastname: lastname,
birthdate: birthdate,
rfiduid: rfiduid,
supabase_user_id: supabase_user_id,
created_at: result.rows[0].created_at
}
});
} catch (error) {
console.error('Fehler beim Erstellen des Spielers:', error);
res.status(500).json({
success: false,
message: 'Interner Serverfehler beim Erstellen des Spielers'
});
}
});
// Link existing player to Supabase user (no auth required for dashboard)
router.post('/link-player', async (req, res) => {
const { player_id, supabase_user_id } = req.body;
// Validierung
if (!player_id || !supabase_user_id) {
return res.status(400).json({
success: false,
message: 'Player ID und Supabase User ID sind erforderlich'
});
}
try {
// Prüfen ob Spieler existiert
const playerExists = await pool.query(
'SELECT id, firstname, lastname FROM players WHERE id = $1',
[player_id]
);
if (playerExists.rows.length === 0) {
return res.status(404).json({
success: false,
message: 'Spieler nicht gefunden'
});
}
// Prüfen ob Supabase User bereits verknüpft ist
const existingLink = await pool.query(
'SELECT id FROM players WHERE supabase_user_id = $1',
[supabase_user_id]
);
if (existingLink.rows.length > 0) {
return res.status(409).json({
success: false,
message: 'Dieser Benutzer ist bereits mit einem Spieler verknüpft'
});
}
// Verknüpfung erstellen
const result = await pool.query(
'UPDATE players SET supabase_user_id = $1 WHERE id = $2 RETURNING id, firstname, lastname, rfiduid',
[supabase_user_id, player_id]
);
res.json({
success: true,
message: 'Spieler erfolgreich verknüpft',
data: result.rows[0]
});
} catch (error) {
console.error('Fehler beim Verknüpfen des Spielers:', error);
res.status(500).json({
success: false,
message: 'Interner Serverfehler beim Verknüpfen des Spielers'
});
}
});
// Get user times by Supabase user ID (no auth required for dashboard)
router.get('/user-times/:supabase_user_id', async (req, res) => {
const { supabase_user_id } = req.params;
try {
// Finde verknüpften Spieler
const playerResult = await pool.query(
'SELECT id FROM players WHERE supabase_user_id = $1',
[supabase_user_id]
);
if (playerResult.rows.length === 0) {
return res.json([]); // Noch keine Verknüpfung
}
const player_id = playerResult.rows[0].id;
// Hole alle Zeiten für diesen Spieler mit Location-Namen
const timesResult = await pool.query(`
SELECT
t.id,
t.recorded_time,
t.created_at,
l.name as location_name,
l.latitude,
l.longitude
FROM times t
JOIN locations l ON t.location_id = l.id
WHERE t.player_id = $1
ORDER BY t.created_at DESC
`, [player_id]);
res.json(timesResult.rows);
} catch (error) {
console.error('Fehler beim Abrufen der Benutzerzeiten:', error);
res.status(500).json({
success: false,
message: 'Fehler beim Abrufen der Benutzerzeiten'
});
}
});
// Get player info by Supabase user ID (no auth required for dashboard)
router.get('/user-player/:supabase_user_id', async (req, res) => {
const { supabase_user_id } = req.params;
try {
const result = await pool.query(
'SELECT id, firstname, lastname, birthdate, rfiduid FROM players WHERE supabase_user_id = $1',
[supabase_user_id]
);
if (result.rows.length === 0) {
return res.status(404).json({
success: false,
message: 'Kein verknüpfter Spieler gefunden'
});
}
res.json({
success: true,
data: result.rows[0]
});
} catch (error) {
console.error('Fehler beim Abrufen der Spielerdaten:', error);
res.status(500).json({
success: false,
message: 'Fehler beim Abrufen der Spielerdaten'
});
}
});
// Link user by RFID UID (scanned from QR code)
router.post('/link-by-rfid', async (req, res) => {
const { rfiduid, supabase_user_id } = req.body;
// Validierung
if (!rfiduid || !supabase_user_id) {
return res.status(400).json({
success: false,
message: 'RFID UID und Supabase User ID sind erforderlich'
});
}
try {
// Prüfen ob Spieler mit dieser RFID UID existiert
const playerResult = await pool.query(
'SELECT id, firstname, lastname, rfiduid, supabase_user_id FROM players WHERE rfiduid = $1',
[rfiduid]
);
if (playerResult.rows.length === 0) {
return res.status(404).json({
success: false,
message: `Kein Spieler mit RFID UID '${rfiduid}' gefunden. Bitte erstelle zuerst einen Spieler mit dieser RFID UID.`
});
}
const player = playerResult.rows[0];
// Prüfen ob dieser Spieler bereits mit einem anderen Benutzer verknüpft ist
if (player.supabase_user_id && player.supabase_user_id !== supabase_user_id) {
return res.status(409).json({
success: false,
message: 'Dieser Spieler ist bereits mit einem anderen Benutzer verknüpft'
});
}
// Prüfen ob dieser Benutzer bereits mit einem anderen Spieler verknüpft ist
const existingLink = await pool.query(
'SELECT id, firstname, lastname FROM players WHERE supabase_user_id = $1 AND id != $2',
[supabase_user_id, player.id]
);
if (existingLink.rows.length > 0) {
return res.status(409).json({
success: false,
message: `Du bist bereits mit dem Spieler '${existingLink.rows[0].firstname} ${existingLink.rows[0].lastname}' verknüpft. Ein Benutzer kann nur mit einem Spieler verknüpft sein.`
});
}
// Verknüpfung erstellen (falls noch nicht vorhanden)
if (!player.supabase_user_id) {
await pool.query(
'UPDATE players SET supabase_user_id = $1 WHERE id = $2',
[supabase_user_id, player.id]
);
}
res.json({
success: true,
message: 'RFID erfolgreich verknüpft',
data: {
id: player.id,
firstname: player.firstname,
lastname: player.lastname,
rfiduid: player.rfiduid
}
});
} catch (error) {
console.error('Fehler beim Verknüpfen per RFID UID:', error);
res.status(500).json({
success: false,
message: 'Interner Serverfehler beim Verknüpfen per RFID UID'
});
}
});
module.exports = { router, requireApiKey };