Update MyTischtennis model to use LONGTEXT for encrypted fields and enhance TeamManagementView with season change handling and async loading
This commit is contained in:
62
backend/migrations/check_seasons_and_teams.sql
Normal file
62
backend/migrations/check_seasons_and_teams.sql
Normal file
@@ -0,0 +1,62 @@
|
||||
-- Diagnose-Skript: Prüfe Seasons und Teams auf dem Server
|
||||
-- Führe diese Queries auf dem Server aus, um das Problem zu identifizieren
|
||||
|
||||
-- 1. Prüfe, ob die season-Tabelle existiert und Daten enthält
|
||||
SELECT '=== SEASONS ===' as info;
|
||||
SELECT * FROM `season` ORDER BY `id` DESC;
|
||||
|
||||
-- 2. Prüfe, ob die club_team-Tabelle existiert und welche season_id verwendet wird
|
||||
SELECT '=== CLUB_TEAMS ===' as info;
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
club_id,
|
||||
season_id,
|
||||
league_id,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM `club_team`
|
||||
ORDER BY `id`;
|
||||
|
||||
-- 3. Prüfe, ob es Teams gibt, die auf nicht-existierende Seasons verweisen
|
||||
SELECT '=== TEAMS MIT FEHLENDEN SEASONS ===' as info;
|
||||
SELECT
|
||||
ct.id,
|
||||
ct.name,
|
||||
ct.season_id,
|
||||
s.season
|
||||
FROM `club_team` ct
|
||||
LEFT JOIN `season` s ON ct.season_id = s.id
|
||||
WHERE s.id IS NULL;
|
||||
|
||||
-- 4. Prüfe, ob es Teams gibt, die keine season_id haben
|
||||
SELECT '=== TEAMS OHNE SEASON_ID ===' as info;
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
club_id,
|
||||
season_id
|
||||
FROM `club_team`
|
||||
WHERE season_id IS NULL;
|
||||
|
||||
-- 5. Prüfe die Struktur der club_team-Tabelle
|
||||
SELECT '=== CLUB_TEAM TABELLENSTRUKTUR ===' as info;
|
||||
DESCRIBE `club_team`;
|
||||
|
||||
-- 6. Prüfe die Struktur der season-Tabelle
|
||||
SELECT '=== SEASON TABELLENSTRUKTUR ===' as info;
|
||||
DESCRIBE `season`;
|
||||
|
||||
-- 7. Prüfe Foreign Key Constraints
|
||||
SELECT '=== FOREIGN KEYS ===' as info;
|
||||
SELECT
|
||||
CONSTRAINT_NAME,
|
||||
TABLE_NAME,
|
||||
COLUMN_NAME,
|
||||
REFERENCED_TABLE_NAME,
|
||||
REFERENCED_COLUMN_NAME
|
||||
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND (TABLE_NAME = 'club_team' OR TABLE_NAME = 'season')
|
||||
AND REFERENCED_TABLE_NAME IS NOT NULL;
|
||||
|
||||
30
backend/migrations/check_seasons_and_teams_simple.sql
Normal file
30
backend/migrations/check_seasons_and_teams_simple.sql
Normal file
@@ -0,0 +1,30 @@
|
||||
-- Vereinfachtes Diagnose-Skript: Prüfe nur die wichtigsten Punkte
|
||||
|
||||
-- 1. Gibt es Seasons in der Datenbank?
|
||||
SELECT 'SEASONS:' as check_type, COUNT(*) as count FROM `season`;
|
||||
SELECT * FROM `season` ORDER BY `id` DESC;
|
||||
|
||||
-- 2. Gibt es Teams in der Datenbank?
|
||||
SELECT 'CLUB_TEAMS:' as check_type, COUNT(*) as count FROM `club_team`;
|
||||
SELECT id, name, club_id, season_id, league_id FROM `club_team` ORDER BY `id`;
|
||||
|
||||
-- 3. Haben alle Teams eine season_id?
|
||||
SELECT 'TEAMS OHNE SEASON_ID:' as check_type, COUNT(*) as count
|
||||
FROM `club_team` WHERE season_id IS NULL;
|
||||
|
||||
-- 4. Verweisen alle Teams auf existierende Seasons?
|
||||
SELECT 'TEAMS MIT FEHLENDEN SEASONS:' as check_type, COUNT(*) as count
|
||||
FROM `club_team` ct
|
||||
LEFT JOIN `season` s ON ct.season_id = s.id
|
||||
WHERE s.id IS NULL;
|
||||
|
||||
-- 5. Welche season_id verwenden die Teams?
|
||||
SELECT 'SEASON_ID VERWENDUNG:' as check_type, season_id, COUNT(*) as team_count
|
||||
FROM `club_team`
|
||||
GROUP BY season_id;
|
||||
|
||||
-- 6. Welche Seasons existieren?
|
||||
SELECT 'EXISTIERENDE SEASONS:' as check_type, id, season
|
||||
FROM `season`
|
||||
ORDER BY id;
|
||||
|
||||
92
backend/migrations/fix_seasons_and_teams.sql
Normal file
92
backend/migrations/fix_seasons_and_teams.sql
Normal file
@@ -0,0 +1,92 @@
|
||||
-- Fix-Skript: Behebt häufige Probleme mit Seasons und Teams
|
||||
-- Führe dieses Skript auf dem Server aus, wenn die Diagnose Probleme zeigt
|
||||
|
||||
-- 1. Stelle sicher, dass die season-Tabelle existiert und die richtige Struktur hat
|
||||
-- (Falls die Tabelle nicht existiert, wird sie erstellt)
|
||||
CREATE TABLE IF NOT EXISTS `season` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`season` VARCHAR(255) NOT NULL UNIQUE,
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- 2. Stelle sicher, dass die club_team-Tabelle die season_id-Spalte hat
|
||||
-- (Falls die Spalte nicht existiert, wird sie hinzugefügt)
|
||||
ALTER TABLE `club_team`
|
||||
ADD COLUMN IF NOT EXISTS `season_id` INT NULL;
|
||||
|
||||
-- 3. Erstelle die Seasons, falls sie fehlen
|
||||
INSERT IGNORE INTO `season` (`season`) VALUES ('2024/2025');
|
||||
INSERT IGNORE INTO `season` (`season`) VALUES ('2025/2026');
|
||||
|
||||
-- 4. Aktualisiere Teams ohne season_id auf die aktuelle Saison
|
||||
-- (Verwendet die neueste Saison basierend auf dem aktuellen Datum)
|
||||
UPDATE `club_team`
|
||||
SET `season_id` = (
|
||||
SELECT `id` FROM `season`
|
||||
WHERE `season` = (
|
||||
CASE
|
||||
WHEN MONTH(CURDATE()) >= 7 THEN CONCAT(YEAR(CURDATE()), '/', YEAR(CURDATE()) + 1)
|
||||
ELSE CONCAT(YEAR(CURDATE()) - 1, '/', YEAR(CURDATE()))
|
||||
END
|
||||
)
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE `season_id` IS NULL;
|
||||
|
||||
-- 5. Falls keine aktuelle Saison existiert, erstelle sie
|
||||
INSERT IGNORE INTO `season` (`season`) VALUES (
|
||||
CASE
|
||||
WHEN MONTH(CURDATE()) >= 7 THEN CONCAT(YEAR(CURDATE()), '/', YEAR(CURDATE()) + 1)
|
||||
ELSE CONCAT(YEAR(CURDATE()) - 1, '/', YEAR(CURDATE()))
|
||||
END
|
||||
);
|
||||
|
||||
-- 6. Aktualisiere Teams mit ungültigen season_id auf die aktuelle Saison
|
||||
UPDATE `club_team` ct
|
||||
LEFT JOIN `season` s ON ct.season_id = s.id
|
||||
SET ct.season_id = (
|
||||
SELECT `id` FROM `season`
|
||||
WHERE `season` = (
|
||||
CASE
|
||||
WHEN MONTH(CURDATE()) >= 7 THEN CONCAT(YEAR(CURDATE()), '/', YEAR(CURDATE()) + 1)
|
||||
ELSE CONCAT(YEAR(CURDATE()) - 1, '/', YEAR(CURDATE()))
|
||||
END
|
||||
)
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE s.id IS NULL;
|
||||
|
||||
-- 7. Füge Foreign Key Constraint hinzu, falls er fehlt
|
||||
-- (Hinweis: MySQL/MariaDB unterstützt "IF NOT EXISTS" nicht für Constraints,
|
||||
-- daher müssen wir prüfen, ob der Constraint bereits existiert)
|
||||
SET @constraint_exists = (
|
||||
SELECT COUNT(*)
|
||||
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'club_team'
|
||||
AND CONSTRAINT_NAME = 'club_team_season_id_foreign_idx'
|
||||
AND REFERENCED_TABLE_NAME = 'season'
|
||||
);
|
||||
|
||||
SET @sql = IF(@constraint_exists = 0,
|
||||
'ALTER TABLE `club_team` ADD CONSTRAINT `club_team_season_id_foreign_idx` FOREIGN KEY (`season_id`) REFERENCES `season` (`id`) ON DELETE CASCADE ON UPDATE CASCADE',
|
||||
'SELECT "Foreign key constraint already exists" as message'
|
||||
);
|
||||
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 8. Zeige die Ergebnisse
|
||||
SELECT '=== ERGEBNIS ===' as info;
|
||||
SELECT
|
||||
ct.id,
|
||||
ct.name,
|
||||
ct.season_id,
|
||||
s.season
|
||||
FROM `club_team` ct
|
||||
LEFT JOIN `season` s ON ct.season_id = s.id
|
||||
ORDER BY ct.id;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
-- Migration: Update my_tischtennis table TEXT fields to LONGTEXT for encrypted data
|
||||
-- Date: 2025-11-21
|
||||
-- For MariaDB/MySQL
|
||||
--
|
||||
-- Problem: Encrypted data can be very long, and TEXT fields (max 65KB) are too small
|
||||
-- Solution: Change to LONGTEXT (max 4GB) for all encrypted fields
|
||||
|
||||
-- Update user_data to LONGTEXT
|
||||
ALTER TABLE `my_tischtennis`
|
||||
MODIFY COLUMN `user_data` LONGTEXT NULL;
|
||||
|
||||
-- Update access_token to LONGTEXT
|
||||
ALTER TABLE `my_tischtennis`
|
||||
MODIFY COLUMN `access_token` LONGTEXT NULL;
|
||||
|
||||
-- Update refresh_token to LONGTEXT
|
||||
ALTER TABLE `my_tischtennis`
|
||||
MODIFY COLUMN `refresh_token` LONGTEXT NULL;
|
||||
|
||||
-- Update cookie to LONGTEXT
|
||||
ALTER TABLE `my_tischtennis`
|
||||
MODIFY COLUMN `cookie` LONGTEXT NULL;
|
||||
|
||||
-- Update encrypted_password to LONGTEXT
|
||||
ALTER TABLE `my_tischtennis`
|
||||
MODIFY COLUMN `encrypted_password` LONGTEXT NULL;
|
||||
|
||||
-- Update club_id to LONGTEXT (was VARCHAR, but encrypted data can be longer)
|
||||
ALTER TABLE `my_tischtennis`
|
||||
MODIFY COLUMN `club_id` LONGTEXT NULL;
|
||||
|
||||
-- Update club_name to LONGTEXT (was VARCHAR, but encrypted data can be longer)
|
||||
ALTER TABLE `my_tischtennis`
|
||||
MODIFY COLUMN `club_name` LONGTEXT NULL;
|
||||
|
||||
-- Update fed_nickname to LONGTEXT (was VARCHAR, but encrypted data can be longer)
|
||||
ALTER TABLE `my_tischtennis`
|
||||
MODIFY COLUMN `fed_nickname` LONGTEXT NULL;
|
||||
|
||||
@@ -32,7 +32,7 @@ const MyTischtennis = sequelize.define('MyTischtennis', {
|
||||
}
|
||||
},
|
||||
encryptedPassword: {
|
||||
type: DataTypes.TEXT,
|
||||
type: DataTypes.TEXT('long'), // Use LONGTEXT for encrypted data
|
||||
allowNull: true,
|
||||
field: 'encrypted_password'
|
||||
},
|
||||
@@ -49,7 +49,7 @@ const MyTischtennis = sequelize.define('MyTischtennis', {
|
||||
field: 'auto_update_ratings'
|
||||
},
|
||||
accessToken: {
|
||||
type: DataTypes.TEXT,
|
||||
type: DataTypes.TEXT('long'), // Use LONGTEXT for encrypted data
|
||||
allowNull: true,
|
||||
field: 'access_token',
|
||||
set(value) {
|
||||
@@ -67,7 +67,7 @@ const MyTischtennis = sequelize.define('MyTischtennis', {
|
||||
}
|
||||
},
|
||||
refreshToken: {
|
||||
type: DataTypes.TEXT,
|
||||
type: DataTypes.TEXT('long'), // Use LONGTEXT for encrypted data
|
||||
allowNull: true,
|
||||
field: 'refresh_token',
|
||||
set(value) {
|
||||
@@ -90,7 +90,7 @@ const MyTischtennis = sequelize.define('MyTischtennis', {
|
||||
field: 'expires_at'
|
||||
},
|
||||
cookie: {
|
||||
type: DataTypes.TEXT,
|
||||
type: DataTypes.TEXT('long'), // Use LONGTEXT for encrypted data
|
||||
allowNull: true,
|
||||
set(value) {
|
||||
if (value === null || value === undefined) {
|
||||
@@ -107,7 +107,7 @@ const MyTischtennis = sequelize.define('MyTischtennis', {
|
||||
}
|
||||
},
|
||||
userData: {
|
||||
type: DataTypes.TEXT, // Changed from JSON to TEXT to store encrypted JSON string
|
||||
type: DataTypes.TEXT('long'), // Use LONGTEXT to support very long encrypted strings
|
||||
allowNull: true,
|
||||
field: 'user_data',
|
||||
set(value) {
|
||||
@@ -132,7 +132,7 @@ const MyTischtennis = sequelize.define('MyTischtennis', {
|
||||
}
|
||||
},
|
||||
clubId: {
|
||||
type: DataTypes.STRING,
|
||||
type: DataTypes.TEXT('long'), // Use LONGTEXT for encrypted data (can be longer than VARCHAR)
|
||||
allowNull: true,
|
||||
field: 'club_id',
|
||||
set(value) {
|
||||
@@ -150,7 +150,7 @@ const MyTischtennis = sequelize.define('MyTischtennis', {
|
||||
}
|
||||
},
|
||||
clubName: {
|
||||
type: DataTypes.STRING,
|
||||
type: DataTypes.TEXT('long'), // Use LONGTEXT for encrypted data (can be longer than VARCHAR)
|
||||
allowNull: true,
|
||||
field: 'club_name',
|
||||
set(value) {
|
||||
@@ -168,7 +168,7 @@ const MyTischtennis = sequelize.define('MyTischtennis', {
|
||||
}
|
||||
},
|
||||
fedNickname: {
|
||||
type: DataTypes.STRING,
|
||||
type: DataTypes.TEXT('long'), // Use LONGTEXT for encrypted data (can be longer than VARCHAR)
|
||||
allowNull: true,
|
||||
field: 'fed_nickname',
|
||||
set(value) {
|
||||
|
||||
@@ -801,9 +801,12 @@ export default {
|
||||
};
|
||||
|
||||
const onSeasonChange = (season) => {
|
||||
currentSeason.value = season;
|
||||
loadTeams();
|
||||
loadLeagues();
|
||||
if (season) {
|
||||
currentSeason.value = season;
|
||||
selectedSeasonId.value = season.id;
|
||||
loadTeams();
|
||||
loadLeagues();
|
||||
}
|
||||
};
|
||||
|
||||
// Load scheduler jobs info
|
||||
@@ -849,11 +852,19 @@ export default {
|
||||
};
|
||||
|
||||
// Lifecycle
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
// Lade Ligen beim ersten Laden der Seite (ohne Saison-Filter)
|
||||
loadLeagues();
|
||||
await loadLeagues();
|
||||
// Lade Job-Informationen
|
||||
loadSchedulerJobsInfo();
|
||||
await loadSchedulerJobsInfo();
|
||||
|
||||
// Warte kurz, damit SeasonSelector die Saison setzen kann
|
||||
// Dann lade Teams, falls eine Saison ausgewählt wurde
|
||||
setTimeout(() => {
|
||||
if (selectedSeasonId.value && selectedClub.value) {
|
||||
loadTeams();
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
|
||||
// PDF-Dialog Funktionen
|
||||
@@ -1222,6 +1233,14 @@ export default {
|
||||
}
|
||||
});
|
||||
|
||||
// Watch selectedSeasonId to load teams when season changes
|
||||
watch(selectedSeasonId, (newSeasonId) => {
|
||||
if (newSeasonId && selectedClub.value) {
|
||||
loadTeams();
|
||||
loadLeagues();
|
||||
}
|
||||
});
|
||||
|
||||
const validateTeamDocumentFile = async (file, label) => {
|
||||
if (!file) {
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user