mirror of
https://github.com/Deutscher-Tischfussballbund/com_sportsmanager.git
synced 2026-06-10 14:37:52 +00:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6b68d8a5ed | |||
| 5843fda2d6 | |||
| 511c17468c | |||
| 6f33599fd9 | |||
| aac4c1458f | |||
| f39ade0e9d | |||
| 2a307b0987 | |||
| e8e6f7046d | |||
| 20ab5a44a9 | |||
| a5357e4a51 | |||
| 68e16a3adb | |||
| cfc821f8ff | |||
| 582829331c | |||
| d8ccd08843 | |||
| 57e92da771 | |||
| 7f85888a26 | |||
| 13ad52f221 | |||
| a44564a40e | |||
| ee4e817ad4 | |||
| 8a7ff6c234 | |||
| 8fb4ed1cdd | |||
| a2243d9ccf | |||
| 308fbae4e5 | |||
| d6d2a04ceb | |||
| d7d6751b70 | |||
| b112b4dc31 | |||
| ac416c1822 | |||
| c92774b27d | |||
| b33a7e6a25 | |||
| f86815dae5 | |||
| 43a03bbb09 |
@@ -0,0 +1,22 @@
|
|||||||
|
name: Nightly DTFB Player Sync
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 2 * * *' # Every night at 2:00 AM UTC
|
||||||
|
workflow_dispatch: # Allow manual trigger from GitHub
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sync:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Trigger DTFB Sync
|
||||||
|
run: |
|
||||||
|
response=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||||
|
-X POST \
|
||||||
|
-H "Authorization: Bearer ${{ secrets.DTFB_SYNC_KEY }}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
"${{ secrets.DTFB_SYNC_TRIGGER_URL }}")
|
||||||
|
if [ "$response" != "200" ]; then
|
||||||
|
echo "Sync failed with HTTP $response"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Sync triggered successfully"
|
||||||
@@ -817,6 +817,7 @@ function adminEinstellungen(): void
|
|||||||
$spielerimport_persoenliche_daten_vorauswahl = $jInput->get('spielerimport_persoenliche_daten_vorauswahl', 0, 'INT');
|
$spielerimport_persoenliche_daten_vorauswahl = $jInput->get('spielerimport_persoenliche_daten_vorauswahl', 0, 'INT');
|
||||||
|
|
||||||
$api_push_key = $jInput->get('api_push_key', '', 'RAW');
|
$api_push_key = $jInput->get('api_push_key', '', 'RAW');
|
||||||
|
$dtfb_sync_url = $db->escape(trim($jInput->get('dtfb_sync_url', '', 'RAW')));
|
||||||
|
|
||||||
$query = "REPLACE #__sportsmanager_einstellungen"
|
$query = "REPLACE #__sportsmanager_einstellungen"
|
||||||
. "\n SET name = 'verbands_kuerzel'"
|
. "\n SET name = 'verbands_kuerzel'"
|
||||||
@@ -950,6 +951,12 @@ function adminEinstellungen(): void
|
|||||||
die($db->stderr(true));
|
die($db->stderr(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$query = "REPLACE #__sportsmanager_einstellungen SET name = 'dtfb_sync_url', wert = '$dtfb_sync_url'";
|
||||||
|
$db->setQuery($query);
|
||||||
|
if (!$db->execute()) {
|
||||||
|
die($db->stderr(true));
|
||||||
|
}
|
||||||
|
|
||||||
redirectSportsManagerURL('&task=admin_uebersicht');
|
redirectSportsManagerURL('&task=admin_uebersicht');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3419,6 +3426,50 @@ function adminExportSpielerForm(): void
|
|||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[NoReturn] function adminSyncSpielerToDtfb(): void
|
||||||
|
{
|
||||||
|
$jInput = Factory::getContainer()->get(SiteApplication::class)->input;
|
||||||
|
|
||||||
|
if (!benutzerZugriff("spieler_aendern")) {
|
||||||
|
keinZugriff();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($jInput->get('cancel', false, 'BOOL')) {
|
||||||
|
redirectSportsManagerURL('&task=admin_spieler');
|
||||||
|
}
|
||||||
|
|
||||||
|
$csvData = syncExportSpielerCSV();
|
||||||
|
if (empty($csvData)) {
|
||||||
|
redirectSportsManagerURL('&task=admin_spieler', 'Keine Spieler zum Synchronisieren gefunden.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$res = syncPushToDtfb($csvData);
|
||||||
|
|
||||||
|
// Log the sync
|
||||||
|
syncLogEntry(
|
||||||
|
'push',
|
||||||
|
'manual',
|
||||||
|
$res['success'] ? 'success' : 'error',
|
||||||
|
$res['spieler_count'] ?? 0,
|
||||||
|
$res['spieler_updated'] ?? 0,
|
||||||
|
$res['spieler_added'] ?? 0,
|
||||||
|
$res['message'] ?? '',
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($res['success']) {
|
||||||
|
$msg = sprintf(
|
||||||
|
'Erfolgreich mit DTFB synchronisiert! Spieler gesamt: %d, aktualisiert: %d, neu hinzugefügt: %d.',
|
||||||
|
$res['spieler_count'] ?? 0,
|
||||||
|
$res['spieler_updated'] ?? 0,
|
||||||
|
$res['spieler_added'] ?? 0
|
||||||
|
);
|
||||||
|
redirectSportsManagerURL('&task=admin_spieler', $msg);
|
||||||
|
} else {
|
||||||
|
redirectSportsManagerURL('&task=admin_spieler', 'Sync-Fehler: ' . $res['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[NoReturn] function adminExportSpielerSport(): void
|
#[NoReturn] function adminExportSpielerSport(): void
|
||||||
{
|
{
|
||||||
$db = getDatabase();
|
$db = getDatabase();
|
||||||
@@ -3474,6 +3525,8 @@ function adminVereine(): void
|
|||||||
if (!benutzerZugriff("vereine_aendern"))
|
if (!benutzerZugriff("vereine_aendern"))
|
||||||
keinZugriff(true);
|
keinZugriff(true);
|
||||||
|
|
||||||
|
$ansprechpartner = [];
|
||||||
|
|
||||||
$query = "SELECT COUNT(DISTINCT veranstalter_id) FROM #__sportsmanager_verein WHERE NOT ausgetreten";
|
$query = "SELECT COUNT(DISTINCT veranstalter_id) FROM #__sportsmanager_verein WHERE NOT ausgetreten";
|
||||||
$organisationAnzeigen = loadResult($db, $query) > 1;
|
$organisationAnzeigen = loadResult($db, $query) > 1;
|
||||||
|
|
||||||
@@ -3483,7 +3536,21 @@ function adminVereine(): void
|
|||||||
. "\n LEFT JOIN #__sportsmanager_veranstalter USING (veranstalter_id)"
|
. "\n LEFT JOIN #__sportsmanager_veranstalter USING (veranstalter_id)"
|
||||||
. "\n ORDER BY IF(ISNULL(#__sportsmanager_veranstalter.veranstalter_id), 1, 0), veranstalterbezeichnung, ausgetreten, vereinsname";
|
. "\n ORDER BY IF(ISNULL(#__sportsmanager_veranstalter.veranstalter_id), 1, 0), veranstalterbezeichnung, ausgetreten, vereinsname";
|
||||||
$vereine = loadObjectList($db, $query);
|
$vereine = loadObjectList($db, $query);
|
||||||
HTML_sportsmanager_admin::adminVereine($vereine, $organisationAnzeigen);
|
|
||||||
|
$query = "SELECT #__sportsmanager_verein.verein_id, email FROM #__sportsmanager_vereinsansprechpartner"
|
||||||
|
. "\n LEFT join #__sportsmanager_verein ON #__sportsmanager_vereinsansprechpartner.verein_id = #__sportsmanager_verein.verein_id"
|
||||||
|
. "\n WHERE #__sportsmanager_verein.ausgetreten = 0"
|
||||||
|
. "\n AND email IS NOT NULL AND email <> '';";
|
||||||
|
$ergebnisse = loadObjectList($db, $query);
|
||||||
|
|
||||||
|
if (!empty($ergebnisse)){
|
||||||
|
foreach($ergebnisse as $value){
|
||||||
|
if (empty($ansprechpartner[$value->verein_id]) OR !in_array($value->email, $ansprechpartner[$value->verein_id]))
|
||||||
|
$ansprechpartner[$value->verein_id][] = $value->email;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HTML_sportsmanager_admin::adminVereine($vereine, $organisationAnzeigen, $ansprechpartner);
|
||||||
}
|
}
|
||||||
|
|
||||||
function adminEditVerein(): void
|
function adminEditVerein(): void
|
||||||
@@ -4525,6 +4592,7 @@ function adminEditTeamspielmodus(): void
|
|||||||
$punkte_sieg_doppel_separat = $jInput->get('punkte_sieg_doppel_separat', 0, 'INT');
|
$punkte_sieg_doppel_separat = $jInput->get('punkte_sieg_doppel_separat', 0, 'INT');
|
||||||
$punkte_sieg_doppel = $punkte_sieg_doppel_separat ? $jInput->get('punkte_sieg_doppel', 0, 'INT') : $punkte_sieg_einzel;
|
$punkte_sieg_doppel = $punkte_sieg_doppel_separat ? $jInput->get('punkte_sieg_doppel', 0, 'INT') : $punkte_sieg_einzel;
|
||||||
$heimtausch = $jInput->get('heimtausch', 0, 'INT');
|
$heimtausch = $jInput->get('heimtausch', 0, 'INT');
|
||||||
|
$spiele_in_spielerstatistik = $jInput->get('spiele_in_spielerstatistik', 0, 'INT');
|
||||||
$status = $jInput->get('status', 0, 'INT');
|
$status = $jInput->get('status', 0, 'INT');
|
||||||
$spielpunkte_wertung_einzel = $jInput->get('spielpunkte_wertung_einzel', 0, 'INT');
|
$spielpunkte_wertung_einzel = $jInput->get('spielpunkte_wertung_einzel', 0, 'INT');
|
||||||
$spielpunkte_wertung_doppel_separat = $jInput->get('spielpunkte_wertung_doppel_separat', 0, 'INT');
|
$spielpunkte_wertung_doppel_separat = $jInput->get('spielpunkte_wertung_doppel_separat', 0, 'INT');
|
||||||
@@ -4572,7 +4640,11 @@ function adminEditTeamspielmodus(): void
|
|||||||
$modus = $db->escape($modus);
|
$modus = $db->escape($modus);
|
||||||
|
|
||||||
if ($id == 0) {
|
if ($id == 0) {
|
||||||
$query = "INSERT INTO #__sportsmanager_teamspiel_modus (bezeichnung, punktetyp, punkte_sieg_einzel, punkte_sieg_doppel, spielpunkte_wertung_einzel, spielpunkte_wertung_doppel, spielpunkte_bedingung, spielernamen, heimtausch, modus, status) VALUES ('$bezeichnung', '$punktetyp', '$punkte_sieg_einzel', '$punkte_sieg_doppel', '$spielpunkte_wertung_einzel', '$spielpunkte_wertung_doppel', '$spielpunkte_bedingung', '$spielernamen', '$heimtausch', '$modus', '$status');";
|
$query = "INSERT INTO #__sportsmanager_teamspiel_modus"
|
||||||
|
. "\n (bezeichnung, punktetyp, punkte_sieg_einzel, punkte_sieg_doppel, spielpunkte_wertung_einzel, spielpunkte_wertung_doppel,"
|
||||||
|
. "\n spielpunkte_bedingung, spielernamen, heimtausch, modus, spiele_in_spielerstatistik, status)"
|
||||||
|
. "\n VALUES ('$bezeichnung', '$punktetyp', '$punkte_sieg_einzel', '$punkte_sieg_doppel', '$spielpunkte_wertung_einzel',"
|
||||||
|
. "\n '$spielpunkte_wertung_doppel', '$spielpunkte_bedingung', '$spielernamen', '$heimtausch', '$modus', '$spiele_in_spielerstatistik', '$status');";
|
||||||
$db->setQuery($query);
|
$db->setQuery($query);
|
||||||
if (!$db->execute()) {
|
if (!$db->execute()) {
|
||||||
die($db->stderr(true));
|
die($db->stderr(true));
|
||||||
@@ -4590,6 +4662,7 @@ function adminEditTeamspielmodus(): void
|
|||||||
. "\n spielernamen = '$spielernamen',"
|
. "\n spielernamen = '$spielernamen',"
|
||||||
. "\n heimtausch = '$heimtausch',"
|
. "\n heimtausch = '$heimtausch',"
|
||||||
. "\n modus = '$modus',"
|
. "\n modus = '$modus',"
|
||||||
|
. "\n spiele_in_spielerstatistik = '$spiele_in_spielerstatistik',"
|
||||||
. "\n status = '$status'"
|
. "\n status = '$status'"
|
||||||
. "\n WHERE teamspiel_modus_id = $id";
|
. "\n WHERE teamspiel_modus_id = $id";
|
||||||
$db->setQuery($query);
|
$db->setQuery($query);
|
||||||
@@ -7788,6 +7861,7 @@ function adminHalloffameMitglieder(): void
|
|||||||
if ($halloffame->spielform == 1){
|
if ($halloffame->spielform == 1){
|
||||||
foreach ($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
$index_vereinid = "verein_id_" . $row->platz;
|
$index_vereinid = "verein_id_" . $row->platz;
|
||||||
|
$index_teamid = "team_id_" . $row->platz;
|
||||||
$index_team = "teamname_" . $row->platz;
|
$index_team = "teamname_" . $row->platz;
|
||||||
if (!isset($mitglieder[$row->jahr])) {
|
if (!isset($mitglieder[$row->jahr])) {
|
||||||
$mitglieder[$row->jahr] = new stdClass();
|
$mitglieder[$row->jahr] = new stdClass();
|
||||||
@@ -7799,6 +7873,14 @@ function adminHalloffameMitglieder(): void
|
|||||||
$halloffame->platz2_zeigen = 1;
|
$halloffame->platz2_zeigen = 1;
|
||||||
if ($row->platz == 3 && !empty($row->teamname))
|
if ($row->platz == 3 && !empty($row->teamname))
|
||||||
$halloffame->platz3_zeigen = 1;
|
$halloffame->platz3_zeigen = 1;
|
||||||
|
|
||||||
|
//Suche team_id wenn keine verein_id vorhanden
|
||||||
|
if (empty($row->verein_id)){
|
||||||
|
$query = "SELECT team_id FROM #__sportsmanager_team WHERE teamname LIKE '$row->teamname%' ORDER BY team_id DESC LIMIT 1;";
|
||||||
|
$mitglieder[$row->jahr]->$index_teamid = loadResult($db, $query);
|
||||||
|
} else {
|
||||||
|
$mitglieder[$row->jahr]->$index_teamid = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($halloffame->spielform == 2 || $halloffame->spielform == 3){
|
if ($halloffame->spielform == 2 || $halloffame->spielform == 3){
|
||||||
@@ -8559,6 +8641,8 @@ function adminMannschaften(): void
|
|||||||
if (!benutzerZugriff("mannschaftswettbewerb_aendern") && !benutzerVeranstaltungModerator($veranstaltungId))
|
if (!benutzerZugriff("mannschaftswettbewerb_aendern") && !benutzerVeranstaltungModerator($veranstaltungId))
|
||||||
keinZugriff(true);
|
keinZugriff(true);
|
||||||
|
|
||||||
|
$ansprechpartner = [];
|
||||||
|
|
||||||
$query = "SELECT * FROM #__sportsmanager_veranstaltung WHERE veranstaltung_id = $veranstaltungId";
|
$query = "SELECT * FROM #__sportsmanager_veranstaltung WHERE veranstaltung_id = $veranstaltungId";
|
||||||
$rows = loadObjectList($db, $query);
|
$rows = loadObjectList($db, $query);
|
||||||
if (count($rows) < 1) die("Wrong id!");
|
if (count($rows) < 1) die("Wrong id!");
|
||||||
@@ -8583,7 +8667,36 @@ function adminMannschaften(): void
|
|||||||
. "\n WHERE #__sportsmanager_team.veranstaltung_id = $veranstaltungId"
|
. "\n WHERE #__sportsmanager_team.veranstaltung_id = $veranstaltungId"
|
||||||
. "\n ORDER BY teamname";
|
. "\n ORDER BY teamname";
|
||||||
$rows = loadObjectList($db, $query);
|
$rows = loadObjectList($db, $query);
|
||||||
HTML_sportsmanager_admin::adminMannschaften($veranstaltung, $rows);
|
|
||||||
|
//Ansprechpartner Teams
|
||||||
|
$query = "SELECT #__sportsmanager_team.team_id, email FROM #__sportsmanager_teamansprechpartner"
|
||||||
|
. "\n LEFT JOIN #__sportsmanager_team ON #__sportsmanager_teamansprechpartner.team_id = #__sportsmanager_team.team_id"
|
||||||
|
. "\n WHERE #__sportsmanager_team.veranstaltung_id = $veranstaltungId"
|
||||||
|
. "\n AND email IS NOT NULL AND email <> '';";
|
||||||
|
$ergebnisse = loadObjectList($db, $query);
|
||||||
|
if (!empty($ergebnisse)){
|
||||||
|
foreach($ergebnisse as $value){
|
||||||
|
if (empty($ansprechpartner[$value->team_id]) OR !in_array($value->email, $ansprechpartner[$value->team_id]))
|
||||||
|
$ansprechpartner[$value->team_id][] = $value->email;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Ansprechpartner Vereine
|
||||||
|
$query = "SELECT #__sportsmanager_team.team_id, #__sportsmanager_vereinsansprechpartner.email"
|
||||||
|
. "\n FROM #__sportsmanager_team"
|
||||||
|
. "\n LEFT JOIN #__sportsmanager_verein ON #__sportsmanager_team.verein_id = #__sportsmanager_verein.verein_id"
|
||||||
|
. "\n LEFT JOIN #__sportsmanager_vereinsansprechpartner ON #__sportsmanager_verein.verein_id = #__sportsmanager_vereinsansprechpartner.verein_id"
|
||||||
|
. "\n WHERE #__sportsmanager_team.veranstaltung_id = $veranstaltungId"
|
||||||
|
. "\n AND #__sportsmanager_vereinsansprechpartner.email IS NOT NULL AND #__sportsmanager_vereinsansprechpartner.email <> '';";
|
||||||
|
$ergebnisse = loadObjectList($db, $query);
|
||||||
|
if (!empty($ergebnisse)){
|
||||||
|
foreach($ergebnisse as $value){
|
||||||
|
if (empty($ansprechpartner[$value->team_id]) OR !in_array($value->email, $ansprechpartner[$value->team_id]))
|
||||||
|
$ansprechpartner[$value->team_id][] = $value->email;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HTML_sportsmanager_admin::adminMannschaften($veranstaltung, $rows, $ansprechpartner);
|
||||||
}
|
}
|
||||||
|
|
||||||
function adminEditMannschaft(): void
|
function adminEditMannschaft(): void
|
||||||
|
|||||||
@@ -5708,6 +5708,73 @@ function updateDatabase(): void
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($datenbank_version < 120) {
|
||||||
|
$columns = $db->getTableColumns('#__sportsmanager_teamspiel_modus');
|
||||||
|
if (!array_key_exists('spiele_in_spielerstatistik', $columns)){
|
||||||
|
$query = "ALTER TABLE `#__sportsmanager_teamspiel_modus`"
|
||||||
|
. "\n ADD `spiele_in_spielerstatistik` INT(4) NOT NULL DEFAULT '0' AFTER `heimtausch`;";
|
||||||
|
$db->setQuery($query);
|
||||||
|
if (!$db->execute()) {
|
||||||
|
die($db->stderr(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$columns = $db->getTableColumns('#__sportsmanager_bestenliste_punkte');
|
||||||
|
if (!array_key_exists('team_id', $columns)){
|
||||||
|
$query = "ALTER TABLE `#__sportsmanager_bestenliste_punkte`"
|
||||||
|
. "\n ADD `team_id` INT(11) NULL DEFAULT NULL AFTER `spieler_2_id`;";
|
||||||
|
$db->setQuery($query);
|
||||||
|
if (!$db->execute()) {
|
||||||
|
die($db->stderr(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$spielerstatistik_aktualisieren = true;
|
||||||
|
|
||||||
|
$query = "UPDATE #__sportsmanager_einstellungen"
|
||||||
|
. "\n SET wert = '120'"
|
||||||
|
. "\n WHERE name = 'datenbank_version'";
|
||||||
|
$db->setQuery($query);
|
||||||
|
if (!$db->execute()) {
|
||||||
|
die($db->stderr(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($datenbank_version < 121) {
|
||||||
|
$query = "CREATE TABLE IF NOT EXISTS `#__sportsmanager_sync_log` ("
|
||||||
|
. "\n `sync_id` INT(11) NOT NULL AUTO_INCREMENT,"
|
||||||
|
. "\n `sync_timestamp` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,"
|
||||||
|
. "\n `sync_direction` ENUM('push', 'receive') NOT NULL,"
|
||||||
|
. "\n `sync_trigger` ENUM('manual', 'cron', 'api') NOT NULL,"
|
||||||
|
. "\n `sync_status` ENUM('success', 'error') NOT NULL,"
|
||||||
|
. "\n `spieler_count` INT(11) DEFAULT 0,"
|
||||||
|
. "\n `spieler_updated` INT(11) DEFAULT 0,"
|
||||||
|
. "\n `spieler_added` INT(11) DEFAULT 0,"
|
||||||
|
. "\n `message` TEXT,"
|
||||||
|
. "\n `details` TEXT,"
|
||||||
|
. "\n PRIMARY KEY (`sync_id`),"
|
||||||
|
. "\n INDEX `idx_timestamp` (`sync_timestamp`)"
|
||||||
|
. "\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||||
|
$db->setQuery($query);
|
||||||
|
if (!$db->execute()) {
|
||||||
|
die($db->stderr(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = "INSERT IGNORE #__sportsmanager_einstellungen SET name = 'dtfb_sync_url', wert = '';";
|
||||||
|
$db->setQuery($query);
|
||||||
|
if (!$db->execute()) {
|
||||||
|
die($db->stderr(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = "UPDATE #__sportsmanager_einstellungen"
|
||||||
|
. "\n SET wert = '121'"
|
||||||
|
. "\n WHERE name = 'datenbank_version'";
|
||||||
|
$db->setQuery($query);
|
||||||
|
if (!$db->execute()) {
|
||||||
|
die($db->stderr(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($termin_aktionen_email_setzen) {
|
if ($termin_aktionen_email_setzen) {
|
||||||
$query = "SELECT aktion_user_id, termin_aktion_id"
|
$query = "SELECT aktion_user_id, termin_aktion_id"
|
||||||
. "\n FROM #__sportsmanager_termin_aktion";
|
. "\n FROM #__sportsmanager_termin_aktion";
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ require_once JPATH_SITE . '/components/com_sportsmanager/views/sportsmanager/vie
|
|||||||
require_once JPATH_SITE . '/components/com_sportsmanager/util/image.php';
|
require_once JPATH_SITE . '/components/com_sportsmanager/util/image.php';
|
||||||
require_once JPATH_SITE . '/components/com_sportsmanager/util/email.php';
|
require_once JPATH_SITE . '/components/com_sportsmanager/util/email.php';
|
||||||
require_once JPATH_SITE . '/components/com_sportsmanager/database/update.php'; // will also include init.php and util.php
|
require_once JPATH_SITE . '/components/com_sportsmanager/database/update.php'; // will also include init.php and util.php
|
||||||
|
require_once JPATH_SITE . '/components/com_sportsmanager/sync.php';
|
||||||
|
|
||||||
initDatabase();
|
initDatabase();
|
||||||
updateDatabase();
|
updateDatabase();
|
||||||
@@ -74,6 +75,10 @@ if ($task == "spielerbild") {
|
|||||||
terminDokument();
|
terminDokument();
|
||||||
} else if ($task == "spieler_details") {
|
} else if ($task == "spieler_details") {
|
||||||
spielerDetails();
|
spielerDetails();
|
||||||
|
} else if ($task === 'api_sync_spieler_receive') {
|
||||||
|
apiSyncSpielerReceive();
|
||||||
|
} else if ($task === 'api_sync_spieler_trigger') {
|
||||||
|
apiSyncSpielerTrigger();
|
||||||
} else if ($task !== null && str_starts_with($task, "admin_")) {
|
} else if ($task !== null && str_starts_with($task, "admin_")) {
|
||||||
// in some cases there are no breaks needed due to no return from method
|
// in some cases there are no breaks needed due to no return from method
|
||||||
switch ($task) {
|
switch ($task) {
|
||||||
@@ -134,6 +139,9 @@ if ($task == "spielerbild") {
|
|||||||
case 'admin_spieler_export_sport':
|
case 'admin_spieler_export_sport':
|
||||||
adminExportSpielerSport();
|
adminExportSpielerSport();
|
||||||
break;
|
break;
|
||||||
|
case 'admin_spieler_sync_dtfb':
|
||||||
|
adminSyncSpielerToDtfb();
|
||||||
|
break;
|
||||||
case 'admin_spieler_remove_inaktive_form':
|
case 'admin_spieler_remove_inaktive_form':
|
||||||
adminRemoveInaktiveSpielerForm();
|
adminRemoveInaktiveSpielerForm();
|
||||||
break;
|
break;
|
||||||
@@ -1805,7 +1813,7 @@ function tabelle($veranstaltung, $spieltag, $alleine_angezeigt, $praesentation =
|
|||||||
$teams = getTabelleAktuellerSpieltag($veranstaltung);
|
$teams = getTabelleAktuellerSpieltag($veranstaltung);
|
||||||
} else {
|
} else {
|
||||||
$teams = getTabelleSpieltag($veranstaltung,$spieltag);
|
$teams = getTabelleSpieltag($veranstaltung,$spieltag);
|
||||||
if ($veranstaltung->direktervergleich && $spieltag >= $anzahl_spieltage_komplett/2 && $anzahl_spieltage_komplett >= 3){
|
if ($veranstaltung->direktervergleich > 0 && $spieltag >= $anzahl_spieltage_komplett/2 && $anzahl_spieltage_komplett >= 3){
|
||||||
$teams = getTabelleDirekterVergleich($teams,$veranstaltung,$spieltag);
|
$teams = getTabelleDirekterVergleich($teams,$veranstaltung,$spieltag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1833,17 +1841,40 @@ function tabelle($veranstaltung, $spieltag, $alleine_angezeigt, $praesentation =
|
|||||||
function getTabelleDirekterVergleich($teams,$veranstaltung,$spieltag)
|
function getTabelleDirekterVergleich($teams,$veranstaltung,$spieltag)
|
||||||
{
|
{
|
||||||
$gesamtpunkte = 1000;
|
$gesamtpunkte = 1000;
|
||||||
$anzahlSpiele = 1000;
|
$anzahl_spiele = 1000;
|
||||||
|
$punkte_differenz = 1000;
|
||||||
|
$punkte_quotient = 1000.0000;
|
||||||
|
$spielpunkte_differenz = 1000;
|
||||||
|
$spielpunkte_quotient = 1000.0000;
|
||||||
$platz = 0;
|
$platz = 0;
|
||||||
|
|
||||||
$punktgleicheMannschaften = [];
|
$punktgleicheMannschaften = [];
|
||||||
$korrekturen = [];
|
$korrekturen = [];
|
||||||
$bufferplatz = [];
|
$bufferplatz = [];
|
||||||
|
|
||||||
foreach($teams AS $team){
|
foreach($teams AS $team){
|
||||||
$bufferplatz[$team->team_id]['platz'] = $team->platz;
|
$bufferplatz[$team->team_id]['platz'] = $team->platz;
|
||||||
if (($gesamtpunkte != $team->gesamtpunkte) OR ($anzahlSpiele != $team->anzahl_spiele)){
|
$unterschied = false;
|
||||||
|
|
||||||
|
if (($gesamtpunkte != $team->gesamtpunkte) || ($anzahl_spiele != $team->anzahl_spiele))
|
||||||
|
$unterschied = true;
|
||||||
|
if ($veranstaltung->direktervergleich >= 2 && in_array($veranstaltung->tabellenwertung, [1,4,7,10]) && $spielpunkte_differenz != $team->spielpunkte_differenz)
|
||||||
|
$unterschied = true;
|
||||||
|
if ($veranstaltung->direktervergleich >= 2 && in_array($veranstaltung->tabellenwertung, [2,5,8,11]) && $spielpunkte_quotient != $team->spielpunkte_quotient)
|
||||||
|
$unterschied = true;
|
||||||
|
if ($veranstaltung->direktervergleich == 3 && in_array($veranstaltung->tabellenwertung, [1,4,7,10]) && $punkte_differenz != $team->punkte_differenz)
|
||||||
|
$unterschied = true;
|
||||||
|
if ($veranstaltung->direktervergleich == 3 && in_array($veranstaltung->tabellenwertung, [2,5,8,11]) && $punkte_quotient != $team->punkte_quotient)
|
||||||
|
$unterschied = true;
|
||||||
|
|
||||||
|
if ($unterschied)
|
||||||
|
{
|
||||||
$gesamtpunkte = $team->gesamtpunkte;
|
$gesamtpunkte = $team->gesamtpunkte;
|
||||||
$anzahlSpiele = $team->anzahl_spiele;
|
$anzahl_spiele = $team->anzahl_spiele;
|
||||||
|
$punkte_differenz = $team->punkte_differenz;
|
||||||
|
$punkte_quotient = $team->punkte_quotient;
|
||||||
|
$spielpunkte_differenz = $team->spielpunkte_differenz;
|
||||||
|
$spielpunkte_quotient = $team->spielpunkte_quotient;
|
||||||
$platz = $team->platz;
|
$platz = $team->platz;
|
||||||
$punktgleicheMannschaften[$platz] = $team->team_id;
|
$punktgleicheMannschaften[$platz] = $team->team_id;
|
||||||
}
|
}
|
||||||
@@ -4484,6 +4515,7 @@ function halloffameDetails($uebergabe_id = 0): void
|
|||||||
if ($halloffame->spielform == 1){
|
if ($halloffame->spielform == 1){
|
||||||
foreach ($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
$index_vereinid = "verein_id_" . $row->platz;
|
$index_vereinid = "verein_id_" . $row->platz;
|
||||||
|
$index_teamid = "team_id_" . $row->platz;
|
||||||
$index_team = "teamname_" . $row->platz;
|
$index_team = "teamname_" . $row->platz;
|
||||||
if (!isset($mitglieder[$row->jahr])) {
|
if (!isset($mitglieder[$row->jahr])) {
|
||||||
$mitglieder[$row->jahr] = new stdClass();
|
$mitglieder[$row->jahr] = new stdClass();
|
||||||
@@ -4495,6 +4527,14 @@ function halloffameDetails($uebergabe_id = 0): void
|
|||||||
$halloffame->platz2_zeigen = 1;
|
$halloffame->platz2_zeigen = 1;
|
||||||
if ($row->platz == 3 && !empty($row->teamname))
|
if ($row->platz == 3 && !empty($row->teamname))
|
||||||
$halloffame->platz3_zeigen = 1;
|
$halloffame->platz3_zeigen = 1;
|
||||||
|
|
||||||
|
//Suche team_id wenn keine verein_id vorhanden
|
||||||
|
if (empty($row->verein_id)){
|
||||||
|
$query = "SELECT team_id FROM #__sportsmanager_team WHERE teamname LIKE '$row->teamname%' ORDER BY team_id DESC LIMIT 1;";
|
||||||
|
$mitglieder[$row->jahr]->$index_teamid = loadResult($db, $query);
|
||||||
|
} else {
|
||||||
|
$mitglieder[$row->jahr]->$index_teamid = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($halloffame->spielform == 2 || $halloffame->spielform == 3){
|
if ($halloffame->spielform == 2 || $halloffame->spielform == 3){
|
||||||
@@ -5270,7 +5310,7 @@ function teamstatistikAktualisieren($geaenderte_veranstaltung_id = 0, $geaendert
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Direkter Vergleich, wenn mindestens die Hälfte der Spieltage gespielt sind.
|
// Direkter Vergleich, wenn mindestens die Hälfte der Spieltage gespielt sind.
|
||||||
if ($veranstaltung->direktervergleich && $anzahl_spieltage_gespielt >= $anzahl_spieltage_komplett/2 && $anzahl_spieltage_komplett >= 3){
|
if ($veranstaltung->direktervergleich > 0 && $anzahl_spieltage_gespielt >= $anzahl_spieltage_komplett/2 && $anzahl_spieltage_komplett >= 3){
|
||||||
$teams = getTabelleDirekterVergleich($teams,$veranstaltung,$aktueller_spieltag);
|
$teams = getTabelleDirekterVergleich($teams,$veranstaltung,$aktueller_spieltag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5284,7 +5324,10 @@ function teamstatistikAktualisieren($geaenderte_veranstaltung_id = 0, $geaendert
|
|||||||
$buchholz1_wert = 0;
|
$buchholz1_wert = 0;
|
||||||
$buchholz2_wert = 0;
|
$buchholz2_wert = 0;
|
||||||
foreach ($teams as $team) {
|
foreach ($teams as $team) {
|
||||||
if ($platz == 1 || (($veranstaltung->tabellenwertung <= 9 || $veranstaltung->tabellenwertung >= 21) && $gesamtpunkte != $team->gesamtpunkte) || (($veranstaltung->tabellenwertung == 1 || $veranstaltung->tabellenwertung == 4 || $veranstaltung->tabellenwertung == 7 || $veranstaltung->tabellenwertung == 10 || $veranstaltung->tabellenwertung == 21 || $veranstaltung->tabellenwertung == 24 || $veranstaltung->tabellenwertung == 27) && ($spielpunkte_differenz != $team->spielpunkte_differenz || $punkte_differenz != $team->punkte_differenz)) || (($veranstaltung->tabellenwertung == 2 || $veranstaltung->tabellenwertung == 5 || $veranstaltung->tabellenwertung == 8 || $veranstaltung->tabellenwertung == 11 || $veranstaltung->tabellenwertung == 22 || $veranstaltung->tabellenwertung == 25 || $veranstaltung->tabellenwertung == 28) && ($spielpunkte_quotient != $team->spielpunkte_quotient || $punkte_quotient != $team->punkte_quotient)) || (($veranstaltung->tabellenwertung >= 21) && ($team->buchholz1 != $buchholz1_wert || $team->buchholz2 != $buchholz2_wert)))
|
if ($platz == 1 || (($veranstaltung->tabellenwertung <= 9 || $veranstaltung->tabellenwertung >= 21) && $gesamtpunkte != $team->gesamtpunkte)
|
||||||
|
|| (($veranstaltung->tabellenwertung == 1 || $veranstaltung->tabellenwertung == 4 || $veranstaltung->tabellenwertung == 7 || $veranstaltung->tabellenwertung == 10 || $veranstaltung->tabellenwertung == 21 || $veranstaltung->tabellenwertung == 24 || $veranstaltung->tabellenwertung == 27) && ($spielpunkte_differenz != $team->spielpunkte_differenz || $punkte_differenz != $team->punkte_differenz))
|
||||||
|
|| (($veranstaltung->tabellenwertung == 2 || $veranstaltung->tabellenwertung == 5 || $veranstaltung->tabellenwertung == 8 || $veranstaltung->tabellenwertung == 11 || $veranstaltung->tabellenwertung == 22 || $veranstaltung->tabellenwertung == 25 || $veranstaltung->tabellenwertung == 28) && ($spielpunkte_quotient != $team->spielpunkte_quotient || $punkte_quotient != $team->punkte_quotient))
|
||||||
|
|| (($veranstaltung->tabellenwertung >= 21) && ($team->buchholz1 != $buchholz1_wert || $team->buchholz2 != $buchholz2_wert)))
|
||||||
$tatsaechlicher_platz = $platz;
|
$tatsaechlicher_platz = $platz;
|
||||||
$query = "UPDATE #__sportsmanager_team"
|
$query = "UPDATE #__sportsmanager_team"
|
||||||
. "\n SET platz = $tatsaechlicher_platz";
|
. "\n SET platz = $tatsaechlicher_platz";
|
||||||
@@ -5825,16 +5868,22 @@ function spielerstatistikAktualisieren($geaenderte_spielerstatistik_id = 0, $gea
|
|||||||
$punkte = array();
|
$punkte = array();
|
||||||
|
|
||||||
foreach ($veranstaltungen as $veranstaltung) {
|
foreach ($veranstaltungen as $veranstaltung) {
|
||||||
$query = "SELECT heim_spieler_1_id, heim_spieler_2_id, gast_spieler_1_id, gast_spieler_2_id, teamspiel_heim_punkte, teamspiel_gast_punkte, teamspiel_heim_spielpunkte, teamspiel_gast_spielpunkte"
|
$query = "SELECT heim_spieler_1_id, heim_spieler_2_id, gast_spieler_1_id, gast_spieler_2_id, heim_team_id, gast_team_id,"
|
||||||
|
. "\n teamspiel_heim_punkte, teamspiel_gast_punkte, teamspiel_heim_spielpunkte, teamspiel_gast_spielpunkte"
|
||||||
. "\n FROM #__sportsmanager_begegnung"
|
. "\n FROM #__sportsmanager_begegnung"
|
||||||
. "\n LEFT JOIN #__sportsmanager_team ON heim_team_id = #__sportsmanager_team.team_id"
|
. "\n LEFT JOIN #__sportsmanager_team ON heim_team_id = #__sportsmanager_team.team_id"
|
||||||
. "\n LEFT JOIN #__sportsmanager_teamspiel ON #__sportsmanager_begegnung.begegnung_id = #__sportsmanager_teamspiel.begegnung_id"
|
. "\n LEFT JOIN #__sportsmanager_teamspiel ON #__sportsmanager_begegnung.begegnung_id = #__sportsmanager_teamspiel.begegnung_id"
|
||||||
. "\n LEFT JOIN #__sportsmanager_unbestaetigtes_ergebnis ON #__sportsmanager_begegnung.begegnung_id = #__sportsmanager_unbestaetigtes_ergebnis.begegnung_id"
|
. "\n LEFT JOIN #__sportsmanager_unbestaetigtes_ergebnis ON #__sportsmanager_begegnung.begegnung_id = #__sportsmanager_unbestaetigtes_ergebnis.begegnung_id"
|
||||||
. "\n WHERE ISNULL(unbestaetigtes_ergebnis_id) AND veranstaltung_id = $veranstaltung->veranstaltung_id";
|
. "\n LEFT JOIN #__sportsmanager_veranstaltung ON #__sportsmanager_team.veranstaltung_id = #__sportsmanager_veranstaltung.veranstaltung_id"
|
||||||
|
. "\n LEFT JOIN #__sportsmanager_teamspiel_modus ON #__sportsmanager_veranstaltung.modus_id = #__sportsmanager_teamspiel_modus.teamspiel_modus_id"
|
||||||
|
. "\n WHERE ISNULL(unbestaetigtes_ergebnis_id) AND #__sportsmanager_veranstaltung.veranstaltung_id = $veranstaltung->veranstaltung_id"
|
||||||
|
. "\n AND (#__sportsmanager_teamspiel_modus.spiele_in_spielerstatistik <= 0"
|
||||||
|
. "\n OR teamspiel_nummer <= #__sportsmanager_teamspiel_modus.spiele_in_spielerstatistik)";
|
||||||
if ($spielerstatistik->typ == 1)
|
if ($spielerstatistik->typ == 1)
|
||||||
$query .= "\n AND ISNULL(heim_spieler_2_id) AND ISNULL(gast_spieler_2_id)";
|
$query .= "\n AND ISNULL(heim_spieler_2_id) AND ISNULL(gast_spieler_2_id)";
|
||||||
else if ($spielerstatistik->typ == 2 || $spielerstatistik->typ == 3)
|
else if ($spielerstatistik->typ == 2 || $spielerstatistik->typ == 3)
|
||||||
$query .= "\n AND NOT (ISNULL(heim_spieler_2_id) AND ISNULL(gast_spieler_2_id))";
|
$query .= "\n AND NOT (ISNULL(heim_spieler_2_id) AND ISNULL(gast_spieler_2_id))";
|
||||||
|
$query .= "\n ORDER BY #__sportsmanager_begegnung.zeitpunkt ASC;";
|
||||||
$begegnungen = loadObjectList($db, $query);
|
$begegnungen = loadObjectList($db, $query);
|
||||||
|
|
||||||
foreach ($begegnungen as $begegnung) {
|
foreach ($begegnungen as $begegnung) {
|
||||||
@@ -5868,6 +5917,8 @@ function spielerstatistikAktualisieren($geaenderte_spielerstatistik_id = 0, $gea
|
|||||||
$gast_punkte = $begegnung->teamspiel_gast_punkte;
|
$gast_punkte = $begegnung->teamspiel_gast_punkte;
|
||||||
$heim_spielpunkte = $begegnung->teamspiel_heim_spielpunkte;
|
$heim_spielpunkte = $begegnung->teamspiel_heim_spielpunkte;
|
||||||
$gast_spielpunkte = $begegnung->teamspiel_gast_spielpunkte;
|
$gast_spielpunkte = $begegnung->teamspiel_gast_spielpunkte;
|
||||||
|
$heim_team_id = $begegnung->heim_team_id;
|
||||||
|
$gast_team_id = $begegnung->gast_team_id;
|
||||||
$ergebnis = $heim_punkte > $gast_punkte ? 1 : ($heim_punkte < $gast_punkte ? 2 : 0);
|
$ergebnis = $heim_punkte > $gast_punkte ? 1 : ($heim_punkte < $gast_punkte ? 2 : 0);
|
||||||
$heim_saetze = $ergebnis == 1 ? 1 : 0;
|
$heim_saetze = $ergebnis == 1 ? 1 : 0;
|
||||||
$unentschieden_saetze = $ergebnis == 0 ? 1 : 0;
|
$unentschieden_saetze = $ergebnis == 0 ? 1 : 0;
|
||||||
@@ -5888,6 +5939,10 @@ function spielerstatistikAktualisieren($geaenderte_spielerstatistik_id = 0, $gea
|
|||||||
$punkte[$spieler_id]["sv"] = 0;
|
$punkte[$spieler_id]["sv"] = 0;
|
||||||
$punkte[$spieler_id]["pg"] = 0;
|
$punkte[$spieler_id]["pg"] = 0;
|
||||||
$punkte[$spieler_id]["pv"] = 0;
|
$punkte[$spieler_id]["pv"] = 0;
|
||||||
|
if ($typ == "H")
|
||||||
|
$punkte[$spieler_id]["team_id"] = $heim_team_id;
|
||||||
|
else
|
||||||
|
$punkte[$spieler_id]["team_id"] = $gast_team_id;
|
||||||
}
|
}
|
||||||
if (($ergebnis == 1 && $typ == "H") || ($ergebnis == 2 && $typ != "H"))
|
if (($ergebnis == 1 && $typ == "H") || ($ergebnis == 2 && $typ != "H"))
|
||||||
$punkte[$spieler_id]["s"] += 1;
|
$punkte[$spieler_id]["s"] += 1;
|
||||||
@@ -6014,6 +6069,11 @@ function spielerstatistikAktualisieren($geaenderte_spielerstatistik_id = 0, $gea
|
|||||||
$spieler_punkte_saetze_verloren = $spieler_punkte["sv"];
|
$spieler_punkte_saetze_verloren = $spieler_punkte["sv"];
|
||||||
$spieler_punkte_punkte_gewonnen = $spieler_punkte["pg"];
|
$spieler_punkte_punkte_gewonnen = $spieler_punkte["pg"];
|
||||||
$spieler_punkte_punkte_verloren = $spieler_punkte["pv"];
|
$spieler_punkte_punkte_verloren = $spieler_punkte["pv"];
|
||||||
|
if (!empty($spieler_punkte["team_id"]))
|
||||||
|
$spieler_team_id = $spieler_punkte["team_id"];
|
||||||
|
else
|
||||||
|
$spieler_team_id = "NULL";
|
||||||
|
|
||||||
$query = "UPDATE #__sportsmanager_bestenliste_punkte"
|
$query = "UPDATE #__sportsmanager_bestenliste_punkte"
|
||||||
. "\n SET siege = $spieler_punkte_siege,"
|
. "\n SET siege = $spieler_punkte_siege,"
|
||||||
. "\n unentschieden = $spieler_punkte_unentschieden,"
|
. "\n unentschieden = $spieler_punkte_unentschieden,"
|
||||||
@@ -6024,7 +6084,8 @@ function spielerstatistikAktualisieren($geaenderte_spielerstatistik_id = 0, $gea
|
|||||||
. "\n saetze_unentschieden = $spieler_punkte_saetze_unentschieden,"
|
. "\n saetze_unentschieden = $spieler_punkte_saetze_unentschieden,"
|
||||||
. "\n saetze_verloren = $spieler_punkte_saetze_verloren,"
|
. "\n saetze_verloren = $spieler_punkte_saetze_verloren,"
|
||||||
. "\n punkte_gewonnen = $spieler_punkte_punkte_gewonnen,"
|
. "\n punkte_gewonnen = $spieler_punkte_punkte_gewonnen,"
|
||||||
. "\n punkte_verloren = $spieler_punkte_punkte_verloren"
|
. "\n punkte_verloren = $spieler_punkte_punkte_verloren,"
|
||||||
|
. "\n team_id = $spieler_team_id"
|
||||||
. "\n WHERE bestenliste_punkte_id = $row->bestenliste_punkte_id;";
|
. "\n WHERE bestenliste_punkte_id = $row->bestenliste_punkte_id;";
|
||||||
$db->setQuery($query);
|
$db->setQuery($query);
|
||||||
if (!$db->execute()) {
|
if (!$db->execute()) {
|
||||||
@@ -6051,6 +6112,10 @@ function spielerstatistikAktualisieren($geaenderte_spielerstatistik_id = 0, $gea
|
|||||||
$spieler_punkte_saetze_verloren = $spieler_punkte["sv"];
|
$spieler_punkte_saetze_verloren = $spieler_punkte["sv"];
|
||||||
$spieler_punkte_punkte_gewonnen = $spieler_punkte["pg"];
|
$spieler_punkte_punkte_gewonnen = $spieler_punkte["pg"];
|
||||||
$spieler_punkte_punkte_verloren = $spieler_punkte["pv"];
|
$spieler_punkte_punkte_verloren = $spieler_punkte["pv"];
|
||||||
|
if (!empty($spieler_punkte["team_id"]))
|
||||||
|
$spieler_team_id = $spieler_punkte["team_id"];
|
||||||
|
else
|
||||||
|
$spieler_team_id = "NULL";
|
||||||
$query = "INSERT #__sportsmanager_bestenliste_punkte"
|
$query = "INSERT #__sportsmanager_bestenliste_punkte"
|
||||||
. "\n SET siege = $spieler_punkte_siege,"
|
. "\n SET siege = $spieler_punkte_siege,"
|
||||||
. "\n unentschieden = $spieler_punkte_unentschieden,"
|
. "\n unentschieden = $spieler_punkte_unentschieden,"
|
||||||
@@ -6064,6 +6129,7 @@ function spielerstatistikAktualisieren($geaenderte_spielerstatistik_id = 0, $gea
|
|||||||
. "\n punkte_verloren = $spieler_punkte_punkte_verloren,"
|
. "\n punkte_verloren = $spieler_punkte_punkte_verloren,"
|
||||||
. "\n spieler_id = $spieler_1_id,"
|
. "\n spieler_id = $spieler_1_id,"
|
||||||
. "\n spieler_2_id = " . ($spieler_2_id != NULL ? "$spieler_2_id" : "NULL") . ","
|
. "\n spieler_2_id = " . ($spieler_2_id != NULL ? "$spieler_2_id" : "NULL") . ","
|
||||||
|
. "\n team_id = $spieler_team_id,"
|
||||||
. "\n bestenliste_id = $spielerstatistik->bestenliste_id;";
|
. "\n bestenliste_id = $spielerstatistik->bestenliste_id;";
|
||||||
$db->setQuery($query);
|
$db->setQuery($query);
|
||||||
if (!$db->execute()) {
|
if (!$db->execute()) {
|
||||||
@@ -7312,6 +7378,7 @@ function spielerstatistiken(): void
|
|||||||
|
|
||||||
$details_anzeigen = currentUserHasAccessToDetails();
|
$details_anzeigen = currentUserHasAccessToDetails();
|
||||||
$filter_saison_id = $jInput->get('filter_saison_id', 0, 'INT');
|
$filter_saison_id = $jInput->get('filter_saison_id', 0, 'INT');
|
||||||
|
|
||||||
if ($filter_saison_id == 0)
|
if ($filter_saison_id == 0)
|
||||||
$filter_saison_id = $jInput->cookie->get('sportsmanager_filter_saison_id', 0, 'INT');
|
$filter_saison_id = $jInput->cookie->get('sportsmanager_filter_saison_id', 0, 'INT');
|
||||||
|
|
||||||
@@ -7341,25 +7408,53 @@ function spielerstatistiken(): void
|
|||||||
. "\n ORDER BY reihenfolge, bezeichnung, kategorie";
|
. "\n ORDER BY reihenfolge, bezeichnung, kategorie";
|
||||||
$spielerstatistiken = loadObjectList($db, $query);
|
$spielerstatistiken = loadObjectList($db, $query);
|
||||||
|
|
||||||
HTML_sportsmanager::spielerstatistikenHeader($params->get('titel'), $params->get('beschreibung'), $saisons, $filter_saison_id);
|
HTML_sportsmanager::spielerstatistikenHeader($params->get('titel'), $params->get('beschreibung'), $saisons, $filter_saison_id, "", null, null, null, null);
|
||||||
|
|
||||||
foreach ($spielerstatistiken as $spielerstatistik) {
|
foreach ($spielerstatistiken as $spielerstatistik) {
|
||||||
$query = "SELECT #__sportsmanager_bestenliste_punkte.*, #__sportsmanager_spieler.nachname, #__sportsmanager_spieler.vorname, #__sportsmanager_spieler.geschlecht, #__sportsmanager_spieler.aktueller_verein_id, #__sportsmanager_spieler.bild_ausblenden, spieler_2.nachname AS nachname_2, spieler_2.vorname AS vorname_2, spieler_2.geschlecht AS geschlecht_2, spieler_2.aktueller_verein_id AS aktueller_verein_id_2, spieler_2.bild_ausblenden AS bild_ausblenden_2";
|
//Mindestzahl an Spielen
|
||||||
if ($spielerstatistik->tabellenwertung == 1)
|
$spielerstatistik->min_spiele = 0;
|
||||||
|
if (in_array($spielerstatistik->tabellenwertung, [4, 5])) {
|
||||||
|
$query = "SELECT siege + unentschieden + niederlagen AS spiele"
|
||||||
|
. "\n FROM #__sportsmanager_bestenliste_punkte"
|
||||||
|
. "\n WHERE bestenliste_id = $spielerstatistik->bestenliste_id"
|
||||||
|
. "\n ORDER BY spiele DESC;";
|
||||||
|
$max_spiele = loadResult($db, $query);
|
||||||
|
$spielerstatistik->min_spiele = round($max_spiele/2);
|
||||||
|
}
|
||||||
|
$query = "SELECT #__sportsmanager_bestenliste_punkte.*, #__sportsmanager_spieler.nachname, team.teamname,"
|
||||||
|
. "\n siege + unentschieden + niederlagen AS spiele,"
|
||||||
|
. "\n #__sportsmanager_spieler.vorname, #__sportsmanager_spieler.geschlecht,"
|
||||||
|
. "\n #__sportsmanager_spieler.aktueller_verein_id, #__sportsmanager_spieler.bild_ausblenden,"
|
||||||
|
. "\n spieler_2.nachname AS nachname_2, spieler_2.vorname AS vorname_2,"
|
||||||
|
. "\n spieler_2.geschlecht AS geschlecht_2, spieler_2.aktueller_verein_id AS aktueller_verein_id_2,"
|
||||||
|
. "\n spieler_2.bild_ausblenden AS bild_ausblenden_2,"
|
||||||
|
. "\n IF(siege > 0 OR unentschieden > 0, ROUND(((siege * 2 + unentschieden)*100) / ((siege + unentschieden + niederlagen)*2)), 0) AS quotient";
|
||||||
|
if ($spielerstatistik->tabellenwertung == 0){
|
||||||
|
$query .= "\n , 0 AS leistungsindex";
|
||||||
|
} else if ($spielerstatistik->tabellenwertung == 1){
|
||||||
$query .= ", IF(spielpunkte_gewonnen > 0 OR spielpunkte_verloren > 0, spielpunkte_gewonnen * spielpunkte_gewonnen * 100 / (spielpunkte_gewonnen + spielpunkte_verloren), 0) AS leistungsindex";
|
$query .= ", IF(spielpunkte_gewonnen > 0 OR spielpunkte_verloren > 0, spielpunkte_gewonnen * spielpunkte_gewonnen * 100 / (spielpunkte_gewonnen + spielpunkte_verloren), 0) AS leistungsindex";
|
||||||
else if ($spielerstatistik->tabellenwertung == 2)
|
} else if ($spielerstatistik->tabellenwertung == 2){
|
||||||
$query .= ", IF(punkte_gewonnen > 0 OR punkte_verloren > 0, siege * punkte_gewonnen * 10 / (punkte_gewonnen + punkte_verloren), 0) AS leistungsindex";
|
$query .= ", IF(punkte_gewonnen > 0 OR punkte_verloren > 0, ROUND(siege * punkte_gewonnen * 10 / (punkte_gewonnen + punkte_verloren)), 0) AS leistungsindex";
|
||||||
|
} else if ($spielerstatistik->tabellenwertung == 3){
|
||||||
|
$query .= "\n , IF(punkte_gewonnen > 0 OR punkte_verloren > 0, siege * 2 + unentschieden + punkte_gewonnen - punkte_verloren, 0) AS leistungsindex";
|
||||||
|
} else if ($spielerstatistik->tabellenwertung == 4){
|
||||||
|
$query .= "\n , IF(punkte_gewonnen > 0 OR punkte_verloren > 0, ROUND(punkte_gewonnen*100 / (punkte_gewonnen + punkte_verloren),2), 0) AS leistungsindex";
|
||||||
|
} else if ($spielerstatistik->tabellenwertung == 5){
|
||||||
|
$query .= "\n , IF(punkte_gewonnen > 0 OR punkte_verloren > 0, ROUND(spielpunkte_gewonnen / (siege + unentschieden + niederlagen),2), 0) AS leistungsindex";
|
||||||
|
}
|
||||||
$query .= "\n FROM #__sportsmanager_bestenliste_punkte"
|
$query .= "\n FROM #__sportsmanager_bestenliste_punkte"
|
||||||
. "\n LEFT JOIN #__sportsmanager_spieler USING (spieler_id)"
|
. "\n LEFT JOIN #__sportsmanager_spieler USING (spieler_id)"
|
||||||
|
. "\n LEFT JOIN (SELECT team_id, teamname FROM #__sportsmanager_team) AS team ON #__sportsmanager_bestenliste_punkte.team_id = team.team_id"
|
||||||
. "\n LEFT JOIN #__sportsmanager_spieler AS spieler_2 ON spieler_2.spieler_id = spieler_2_id"
|
. "\n LEFT JOIN #__sportsmanager_spieler AS spieler_2 ON spieler_2.spieler_id = spieler_2_id"
|
||||||
. "\n WHERE bestenliste_id = $spielerstatistik->bestenliste_id";
|
. "\n WHERE bestenliste_id = $spielerstatistik->bestenliste_id"
|
||||||
|
. "\n AND siege + unentschieden + niederlagen >= $spielerstatistik->min_spiele";
|
||||||
if ($spielerstatistik->tabellenwertung == 0)
|
if ($spielerstatistik->tabellenwertung == 0)
|
||||||
$query .= "\n ORDER BY spielpunkte_gewonnen DESC, spielpunkte_verloren, punkte_gewonnen - punkte_verloren DESC, nachname, vorname";
|
$query .= "\n ORDER BY spielpunkte_gewonnen DESC, spielpunkte_verloren, punkte_gewonnen - punkte_verloren DESC, nachname, vorname";
|
||||||
else
|
else
|
||||||
$query .= "\n ORDER BY leistungsindex DESC, spielpunkte_gewonnen DESC, spielpunkte_verloren, punkte_gewonnen - punkte_verloren DESC, nachname, vorname";
|
$query .= "\n ORDER BY leistungsindex DESC, quotient DESC, punkte_gewonnen - punkte_verloren DESC, nachname, vorname";
|
||||||
$spielerstatistik_punkte = loadObjectList($db, $query);
|
$spielerstatistik_punkte = loadObjectList($db, $query);
|
||||||
|
|
||||||
HTML_sportsmanager::spielerstatistik($spielerstatistik, $spielerstatistik_punkte, FALSE, 0, 0, $details_anzeigen);
|
HTML_sportsmanager::spielerstatistik($spielerstatistik, $spielerstatistik_punkte, FALSE, 0, 0, 0, $details_anzeigen);
|
||||||
}
|
}
|
||||||
|
|
||||||
administrationFooter();
|
administrationFooter();
|
||||||
@@ -7368,6 +7463,7 @@ function spielerstatistiken(): void
|
|||||||
function spielerstatistik(): void
|
function spielerstatistik(): void
|
||||||
{
|
{
|
||||||
$db = getDatabase();
|
$db = getDatabase();
|
||||||
|
global $params;
|
||||||
$jInput = Factory::getContainer()->get(SiteApplication::class)->input;
|
$jInput = Factory::getContainer()->get(SiteApplication::class)->input;
|
||||||
|
|
||||||
$id = $jInput->get('id', 0, 'INT');
|
$id = $jInput->get('id', 0, 'INT');
|
||||||
@@ -7383,7 +7479,10 @@ function spielerstatistik(): void
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$details_anzeigen = currentUserHasAccessToDetails();
|
$details_anzeigen = currentUserHasAccessToDetails();
|
||||||
|
$filter_min_spiele = $jInput->get('filter_min_spiele', 999, 'INT');
|
||||||
$filter_saison_id = $jInput->get('filter_saison_id', 0, 'INT');
|
$filter_saison_id = $jInput->get('filter_saison_id', 0, 'INT');
|
||||||
|
$filter_teams = $jInput->get('filter_teams', 0, 'INT');
|
||||||
|
|
||||||
if ($filter_saison_id == 0) {
|
if ($filter_saison_id == 0) {
|
||||||
$filter_saison_id = $jInput->cookie->get('sportsmanager_filter_saison_id', 0, 'INT');
|
$filter_saison_id = $jInput->cookie->get('sportsmanager_filter_saison_id', 0, 'INT');
|
||||||
}
|
}
|
||||||
@@ -7419,24 +7518,75 @@ function spielerstatistik(): void
|
|||||||
}
|
}
|
||||||
$spielerstatistik = $rows[0];
|
$spielerstatistik = $rows[0];
|
||||||
|
|
||||||
|
//Mindestzahl an Spielen
|
||||||
|
$spiele = null;
|
||||||
|
$spielerstatistik->min_spiele = 0;
|
||||||
|
if (in_array($spielerstatistik->tabellenwertung, [4, 5])) {
|
||||||
|
$query = "SELECT siege + unentschieden + niederlagen AS spiele"
|
||||||
|
. "\n FROM #__sportsmanager_bestenliste_punkte"
|
||||||
|
. "\n WHERE bestenliste_id = $id"
|
||||||
|
. "\n ORDER BY spiele DESC;";
|
||||||
|
$max_spiele = loadResult($db, $query);
|
||||||
|
if ($max_spiele > 0){
|
||||||
|
$offset = $max_spiele/10;
|
||||||
|
$spiele[0] = "Alle zeigen";
|
||||||
|
for($i = 1; $i <= 10; $i++){
|
||||||
|
$spiele[round($offset*$i)] = $i*10 . "%";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$spielerstatistik->max_spiele = $max_spiele;
|
||||||
|
if ($filter_min_spiele == 999)
|
||||||
|
$spielerstatistik->min_spiele = round($max_spiele/2);
|
||||||
|
else
|
||||||
|
$spielerstatistik->min_spiele = $filter_min_spiele;
|
||||||
|
}
|
||||||
|
|
||||||
// Spielerstatistikpunkte ermitteln
|
// Spielerstatistikpunkte ermitteln
|
||||||
$query = "SELECT #__sportsmanager_bestenliste_punkte.*, #__sportsmanager_spieler.nachname, #__sportsmanager_spieler.vorname, #__sportsmanager_spieler.geschlecht, #__sportsmanager_spieler.aktueller_verein_id, #__sportsmanager_spieler.bild_ausblenden, spieler_2.nachname AS nachname_2, spieler_2.vorname AS vorname_2, spieler_2.geschlecht AS geschlecht_2, spieler_2.aktueller_verein_id AS aktueller_verein_id_2, spieler_2.bild_ausblenden AS bild_ausblenden_2";
|
$query = "SELECT #__sportsmanager_bestenliste_punkte.*, #__sportsmanager_spieler.nachname, #__sportsmanager_spieler.vorname, team.teamname,"
|
||||||
if ($spielerstatistik->tabellenwertung == 1) {
|
. "\n siege + unentschieden + niederlagen AS spiele,"
|
||||||
$query .= ", IF(spielpunkte_gewonnen > 0 OR spielpunkte_verloren > 0, spielpunkte_gewonnen * spielpunkte_gewonnen * 100 / (spielpunkte_gewonnen + spielpunkte_verloren), 0) AS leistungsindex";
|
. "\n #__sportsmanager_spieler.geschlecht, #__sportsmanager_spieler.aktueller_verein_id, #__sportsmanager_spieler.bild_ausblenden,"
|
||||||
} else if ($spielerstatistik->tabellenwertung == 2) {
|
. "\n spieler_2.nachname AS nachname_2, spieler_2.vorname AS vorname_2, spieler_2.geschlecht AS geschlecht_2,"
|
||||||
$query .= ", IF(punkte_gewonnen > 0 OR punkte_verloren > 0, siege * punkte_gewonnen * 10 / (punkte_gewonnen + punkte_verloren), 0) AS leistungsindex";
|
. "\n spieler_2.aktueller_verein_id AS aktueller_verein_id_2, spieler_2.bild_ausblenden AS bild_ausblenden_2,"
|
||||||
|
. "\n IF(siege > 0 OR unentschieden > 0, ROUND(((siege * 2 + unentschieden)*100) / ((siege + unentschieden + niederlagen)*2)), 0) AS quotient";
|
||||||
|
if ($spielerstatistik->tabellenwertung == 0){
|
||||||
|
$query .= "\n , spielpunkte_gewonnen AS leistungsindex";
|
||||||
|
} else if ($spielerstatistik->tabellenwertung == 1){
|
||||||
|
$query .= "\n , IF(spielpunkte_gewonnen > 0 OR spielpunkte_verloren > 0, spielpunkte_gewonnen * spielpunkte_gewonnen * 100 / (spielpunkte_gewonnen + spielpunkte_verloren), 0) AS leistungsindex";
|
||||||
|
} else if ($spielerstatistik->tabellenwertung == 2){
|
||||||
|
$query .= "\n , IF(punkte_gewonnen > 0 OR punkte_verloren > 0, ROUND(siege * punkte_gewonnen * 10 / (punkte_gewonnen + punkte_verloren)), 0) AS leistungsindex";
|
||||||
|
} else if ($spielerstatistik->tabellenwertung == 3){
|
||||||
|
$query .= "\n , IF(punkte_gewonnen > 0 OR punkte_verloren > 0, siege * 2 + unentschieden + punkte_gewonnen - punkte_verloren, 0) AS leistungsindex";
|
||||||
|
} else if ($spielerstatistik->tabellenwertung == 4){
|
||||||
|
$query .= "\n , IF(punkte_gewonnen > 0 OR punkte_verloren > 0, ROUND(punkte_gewonnen*100 / (punkte_gewonnen + punkte_verloren),2), 0) AS leistungsindex";
|
||||||
|
} else if ($spielerstatistik->tabellenwertung == 5){
|
||||||
|
$query .= "\n , IF(punkte_gewonnen > 0 OR punkte_verloren > 0, ROUND(spielpunkte_gewonnen / (siege + unentschieden + niederlagen),2), 0) AS leistungsindex";
|
||||||
}
|
}
|
||||||
$query .= "\n FROM #__sportsmanager_bestenliste_punkte"
|
$query .= "\n FROM #__sportsmanager_bestenliste_punkte"
|
||||||
. "\n LEFT JOIN #__sportsmanager_spieler USING (spieler_id)"
|
. "\n LEFT JOIN #__sportsmanager_spieler USING (spieler_id)"
|
||||||
|
. "\n LEFT JOIN (SELECT team_id, teamname FROM #__sportsmanager_team) AS team ON #__sportsmanager_bestenliste_punkte.team_id = team.team_id"
|
||||||
. "\n LEFT JOIN #__sportsmanager_spieler AS spieler_2 ON spieler_2.spieler_id = spieler_2_id"
|
. "\n LEFT JOIN #__sportsmanager_spieler AS spieler_2 ON spieler_2.spieler_id = spieler_2_id"
|
||||||
. "\n WHERE bestenliste_id = $spielerstatistik->bestenliste_id";
|
. "\n WHERE bestenliste_id = $spielerstatistik->bestenliste_id"
|
||||||
|
. "\n AND siege + unentschieden + niederlagen >= $spielerstatistik->min_spiele";
|
||||||
if ($spielerstatistik->tabellenwertung == 0) {
|
if ($spielerstatistik->tabellenwertung == 0) {
|
||||||
$query .= "\n ORDER BY spielpunkte_gewonnen DESC, spielpunkte_verloren, punkte_gewonnen - punkte_verloren DESC, nachname, vorname";
|
$query .= "\n ORDER BY spielpunkte_gewonnen DESC, spielpunkte_verloren, punkte_gewonnen - punkte_verloren DESC, nachname, vorname";
|
||||||
} else {
|
} else {
|
||||||
$query .= "\n ORDER BY leistungsindex DESC, spielpunkte_gewonnen DESC, spielpunkte_verloren, punkte_gewonnen - punkte_verloren DESC, nachname, vorname";
|
$query .= "\n ORDER BY leistungsindex DESC, quotient DESC, spielpunkte_gewonnen - spielpunkte_verloren DESC, punkte_gewonnen - punkte_verloren DESC, nachname, vorname";
|
||||||
}
|
}
|
||||||
$spielerstatistik_punkte = loadObjectList($db, $query);
|
$spielerstatistik_punkte = loadObjectList($db, $query);
|
||||||
|
|
||||||
|
//Dropdown teams
|
||||||
|
$query = "SELECT 0 AS team_id, '" . Text::_('COM_SPORTSMANAGER_SELECT_ALL') . "' AS teamname, 0 AS sort_order"
|
||||||
|
. "\n UNION"
|
||||||
|
. "\n SELECT team.team_id, team.teamname, 1 AS sort_order"
|
||||||
|
. "\n FROM #__sportsmanager_bestenliste_punkte"
|
||||||
|
. "\n LEFT JOIN (SELECT team_id, teamname FROM #__sportsmanager_team) AS team"
|
||||||
|
. "\n ON #__sportsmanager_bestenliste_punkte.team_id = team.team_id"
|
||||||
|
. "\n WHERE bestenliste_id = $spielerstatistik->bestenliste_id"
|
||||||
|
. "\n GROUP BY team.team_id"
|
||||||
|
. "\n ORDER BY sort_order, teamname;";
|
||||||
|
$db->setQuery($query);
|
||||||
|
$teams = $db->loadObjectList('team_id');
|
||||||
|
|
||||||
// Vorherige und nächste Spielerstatistik ermitteln
|
// Vorherige und nächste Spielerstatistik ermitteln
|
||||||
$query = "SELECT *"
|
$query = "SELECT *"
|
||||||
. "\n FROM #__sportsmanager_bestenliste"
|
. "\n FROM #__sportsmanager_bestenliste"
|
||||||
@@ -7463,7 +7613,8 @@ function spielerstatistik(): void
|
|||||||
if (isJson()) {
|
if (isJson()) {
|
||||||
JSON_sportsmanager::spielerstatistik($spielerstatistik_punkte);
|
JSON_sportsmanager::spielerstatistik($spielerstatistik_punkte);
|
||||||
} else {
|
} else {
|
||||||
HTML_sportsmanager::spielerstatistik($spielerstatistik, $spielerstatistik_punkte, TRUE, $vorherige_spielerstatistik_id, $naechste_spielerstatistik_id, $details_anzeigen);
|
HTML_sportsmanager::spielerstatistikenHeader($params->get('titel'), $params->get('beschreibung'), $saisons, $filter_saison_id, $id, $spiele, $spielerstatistik->min_spiele, $teams, $filter_teams);
|
||||||
|
HTML_sportsmanager::spielerstatistik($spielerstatistik, $spielerstatistik_punkte, TRUE, $filter_teams, $vorherige_spielerstatistik_id, $naechste_spielerstatistik_id, $details_anzeigen);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,899 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Sports Manager Sync Extension
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Joomla\CMS\Application\SiteApplication;
|
||||||
|
use Joomla\CMS\Factory;
|
||||||
|
use Joomla\CMS\Language\Text;
|
||||||
|
|
||||||
|
defined("_JEXEC") or die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Bearer token from the Authorization header.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function syncGetBearerToken(): ?string
|
||||||
|
{
|
||||||
|
$headers = null;
|
||||||
|
if (isset($_SERVER['Authorization'])) {
|
||||||
|
$headers = trim($_SERVER["Authorization"]);
|
||||||
|
} elseif (isset($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||||
|
$headers = trim($_SERVER["HTTP_AUTHORIZATION"]);
|
||||||
|
} elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
|
||||||
|
$headers = trim($_SERVER["REDIRECT_HTTP_AUTHORIZATION"]);
|
||||||
|
} elseif (function_exists('apache_request_headers')) {
|
||||||
|
$requestHeaders = apache_request_headers();
|
||||||
|
$requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
|
||||||
|
if (isset($requestHeaders['Authorization'])) {
|
||||||
|
$headers = trim($requestHeaders['Authorization']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($headers)) {
|
||||||
|
if (preg_match('/Bearer\s(\S+)/i', $headers, $matches)) {
|
||||||
|
return $matches[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a sync event in the database.
|
||||||
|
*
|
||||||
|
* @param string $direction ('push' or 'receive')
|
||||||
|
* @param string $trigger ('manual', 'cron', or 'api')
|
||||||
|
* @param string $status ('success' or 'error')
|
||||||
|
* @param int $spieler_count
|
||||||
|
* @param int $spieler_updated
|
||||||
|
* @param int $spieler_added
|
||||||
|
* @param string $message
|
||||||
|
* @param string $details
|
||||||
|
*/
|
||||||
|
function syncLogEntry(string $direction, string $trigger, string $status, int $spieler_count, int $spieler_updated, int $spieler_added, string $message, string $details = ''): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$db = getDatabase();
|
||||||
|
$query = "INSERT INTO #__sportsmanager_sync_log"
|
||||||
|
. "\n SET sync_timestamp = NOW(),"
|
||||||
|
. "\n sync_direction = '" . $db->escape($direction) . "',"
|
||||||
|
. "\n sync_trigger = '" . $db->escape($trigger) . "',"
|
||||||
|
. "\n sync_status = '" . $db->escape($status) . "',"
|
||||||
|
. "\n spieler_count = " . intval($spieler_count) . ","
|
||||||
|
. "\n spieler_updated = " . intval($spieler_updated) . ","
|
||||||
|
. "\n spieler_added = " . intval($spieler_added) . ","
|
||||||
|
. "\n message = '" . $db->escape($message) . "',"
|
||||||
|
. "\n details = '" . $db->escape($details) . "'";
|
||||||
|
$db->setQuery($query);
|
||||||
|
$db->execute();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Failed to write sync log: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns HTML displaying the status of the last sync operation.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function syncGetLastStatus(): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$db = getDatabase();
|
||||||
|
$query = "SELECT * FROM #__sportsmanager_sync_log ORDER BY sync_id DESC LIMIT 1";
|
||||||
|
$rows = loadObjectList($db, $query);
|
||||||
|
if (count($rows) === 0) {
|
||||||
|
return "Noch nie synchronisiert";
|
||||||
|
}
|
||||||
|
$row = $rows[0];
|
||||||
|
|
||||||
|
$statusClass = $row->sync_status === 'success' ? 'uk-text-success' : 'uk-text-danger';
|
||||||
|
$statusText = $row->sync_status === 'success' ? 'Erfolgreich' : 'Fehlgeschlagen';
|
||||||
|
$directionText = $row->sync_direction === 'push' ? 'Export (Push)' : 'Import (Receive)';
|
||||||
|
$triggerText = $row->sync_trigger === 'manual' ? 'Manuell' : ($row->sync_trigger === 'cron' ? 'Cron' : 'API');
|
||||||
|
|
||||||
|
$stats = "";
|
||||||
|
if ($row->sync_status === 'success') {
|
||||||
|
$stats = sprintf(
|
||||||
|
" (Spieler gesamt: %d, Aktualisiert: %d, Hinzugefügt: %d)",
|
||||||
|
$row->spieler_count,
|
||||||
|
$row->spieler_updated,
|
||||||
|
$row->spieler_added
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$stats = " (Fehler: " . htmlspecialchars($row->message) . ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf(
|
||||||
|
"<span class='%s'><strong>%s</strong></span> am %s via %s / %s%s",
|
||||||
|
$statusClass,
|
||||||
|
$statusText,
|
||||||
|
date('d.m.Y H:i:s', strtotime($row->sync_timestamp)),
|
||||||
|
$directionText,
|
||||||
|
$triggerText,
|
||||||
|
$stats
|
||||||
|
);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return "Noch nie synchronisiert";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports player data to a tab-separated CSV string.
|
||||||
|
* Excludes personal contact details and images.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function syncExportSpielerCSV(): string
|
||||||
|
{
|
||||||
|
$db = getDatabase();
|
||||||
|
$jahr = date("Y");
|
||||||
|
$query = "SELECT nachname, vorname, spielernr, lizenznr, lizenz, geschlecht";
|
||||||
|
$query .= ",\n IF(ISNULL(geburtsjahr), IF(geschlecht = 'M', 'H', 'D'), IF(" . ($jahr - 18) . " <= geburtsjahr, 'J', IF(" . ($jahr - 50) . " > geburtsjahr, 'S', IF(geschlecht = 'M', 'H', 'D')))) AS kategorie";
|
||||||
|
$query .= ",\n vereinsname as verein, vereinssitz, veranstalterbezeichnung as organisation, IF(mitgliedsstatus = 1, 'Aktiv', IF(mitgliedsstatus = 0, 'Ausgetreten', IF(mitgliedsstatus = 2, 'Eingeschränkt', 'Passiv'))) AS mitgliedsstatus";
|
||||||
|
$query .= ",\n geburtsjahr";
|
||||||
|
$query .= "\n FROM #__sportsmanager_spieler";
|
||||||
|
$query .= "\n LEFT JOIN #__sportsmanager_mitglied_von_verein ON #__sportsmanager_spieler.spieler_id = #__sportsmanager_mitglied_von_verein.spieler_id AND #__sportsmanager_mitglied_von_verein.verein_id = #__sportsmanager_spieler.aktueller_verein_id"
|
||||||
|
. "\n LEFT JOIN #__sportsmanager_verein ON #__sportsmanager_verein.verein_id = #__sportsmanager_spieler.aktueller_verein_id"
|
||||||
|
. "\n LEFT JOIN #__sportsmanager_veranstalter ON #__sportsmanager_veranstalter.veranstalter_id = #__sportsmanager_verein.veranstalter_id";
|
||||||
|
$query .= "\n WHERE NOT ISNULL(aktueller_verein_id) AND NOT ISNULL(spielernr) AND spielernr != ''";
|
||||||
|
$query .= "\n ORDER BY nachname, vorname";
|
||||||
|
|
||||||
|
$rows = loadObjectList($db, $query);
|
||||||
|
if (count($rows) === 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
$trennzeichen = "\t";
|
||||||
|
$header = "";
|
||||||
|
foreach ($rows[0] as $field => $value) {
|
||||||
|
$header .= $field . $trennzeichen;
|
||||||
|
}
|
||||||
|
$header = rtrim($header, $trennzeichen);
|
||||||
|
|
||||||
|
$data = "";
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$line = '';
|
||||||
|
foreach ($row as $value) {
|
||||||
|
if ((!isset($value)) or ($value === "")) {
|
||||||
|
$value = $trennzeichen;
|
||||||
|
} else {
|
||||||
|
$value = str_replace('"', '""', $value);
|
||||||
|
$value = str_replace("\t", ' ', $value);
|
||||||
|
$value = str_replace("\r", '', $value);
|
||||||
|
$value = str_replace("\n", ' ', $value);
|
||||||
|
$value = '="' . $value . '"' . $trennzeichen;
|
||||||
|
}
|
||||||
|
$line .= $value;
|
||||||
|
}
|
||||||
|
$data .= rtrim($line, $trennzeichen) . "\n";
|
||||||
|
}
|
||||||
|
$data = str_replace("\r", "", $data);
|
||||||
|
|
||||||
|
return "sep=" . $trennzeichen . "\n" . $header . "\n" . $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushes the exported CSV data to DTFB (dtfb_sync_url) via cURL.
|
||||||
|
*
|
||||||
|
* @param string $csvData
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function syncPushToDtfb(string $csvData): array
|
||||||
|
{
|
||||||
|
$push_key = einstellungswert("api_push_key");
|
||||||
|
$sync_url = einstellungswert("dtfb_sync_url");
|
||||||
|
|
||||||
|
if (empty($sync_url)) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Sync-URL nicht konfiguriert.'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (empty($push_key)) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'API Push Key nicht konfiguriert.'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$ch = curl_init($sync_url);
|
||||||
|
if (!$ch) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Initialisierung von cURL fehlgeschlagen.'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_setopt_array($ch, array(
|
||||||
|
CURLOPT_POST => TRUE,
|
||||||
|
CURLOPT_RETURNTRANSFER => TRUE,
|
||||||
|
CURLOPT_HTTPHEADER => array(
|
||||||
|
'Authorization: Bearer ' . $push_key,
|
||||||
|
'Content-Type: text/csv; charset=utf-8',
|
||||||
|
),
|
||||||
|
CURLOPT_TIMEOUT => 60,
|
||||||
|
CURLOPT_POSTFIELDS => $csvData,
|
||||||
|
));
|
||||||
|
|
||||||
|
$resp = curl_exec($ch);
|
||||||
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
|
||||||
|
if (curl_errno($ch)) {
|
||||||
|
$error_msg = curl_error($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'cURL-Fehler: ' . $error_msg
|
||||||
|
];
|
||||||
|
}
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($http_code !== 200) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'HTTP-Status ' . $http_code . ': ' . $resp
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = json_decode($resp, true);
|
||||||
|
if (json_last_error() === JSON_ERROR_NONE) {
|
||||||
|
if (isset($result['success']) && $result['success']) {
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => $result['message'] ?? 'Erfolgreich synchronisiert.',
|
||||||
|
'spieler_count' => $result['spieler_count'] ?? 0,
|
||||||
|
'spieler_updated' => $result['spieler_updated'] ?? 0,
|
||||||
|
'spieler_added' => $result['spieler_added'] ?? 0
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => $result['error'] ?? $result['message'] ?? 'Import auf Empfängerseite fehlgeschlagen.'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_contains(strtolower($resp), 'success')) {
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Erfolgreich synchronisiert (Klartext-Antwort).'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Unerwartete Antwort vom Server: ' . substr($resp, 0, 200)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes incoming CSV data and imports it into the local database.
|
||||||
|
* Aborts and returns an error if any organization name in the CSV cannot
|
||||||
|
* be matched with an existing local organization.
|
||||||
|
*
|
||||||
|
* @param string $csvData
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function syncReceiveSpielerImport(string $csvData): array
|
||||||
|
{
|
||||||
|
if (!ini_get('safe_mode'))
|
||||||
|
set_time_limit(300);
|
||||||
|
|
||||||
|
$db = getDatabase();
|
||||||
|
|
||||||
|
// Normalise the payload to UTF-8. The automatic/semi-automatic sync path is
|
||||||
|
// UTF-8 end to end, but a legacy/manual export (e.g. from TFVHH) can be
|
||||||
|
// latin1/Windows-1252 encoded. Without this, non-ASCII bytes (e.g. "ß" in an
|
||||||
|
// organisation name) get truncated when staged into the utf8mb4 import table,
|
||||||
|
// causing the organisation match to fail and every row to be skipped silently.
|
||||||
|
if (!mb_check_encoding($csvData, 'UTF-8')) {
|
||||||
|
$csvData = mb_convert_encoding($csvData, 'UTF-8', 'Windows-1252');
|
||||||
|
}
|
||||||
|
|
||||||
|
$lines = explode("\n", str_replace("\r", "", $csvData));
|
||||||
|
if (count($lines) < 2) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Keine Daten in der CSV-Datei gefunden.'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$lineIdx = 0;
|
||||||
|
$titelzeile = trim($lines[$lineIdx]);
|
||||||
|
|
||||||
|
if (str_starts_with($titelzeile, "sep=")) {
|
||||||
|
$trennzeichen = substr($titelzeile, 4);
|
||||||
|
if ($trennzeichen === "") {
|
||||||
|
$trennzeichen = "\t";
|
||||||
|
}
|
||||||
|
$lineIdx++;
|
||||||
|
if (isset($lines[$lineIdx])) {
|
||||||
|
$titelzeile = trim($lines[$lineIdx]);
|
||||||
|
} else {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'CSV-Datei enthält nach sep= keine Titelzeile.'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$trennzeichen = "\t";
|
||||||
|
}
|
||||||
|
|
||||||
|
$titel = explode($trennzeichen, strtolower($titelzeile));
|
||||||
|
$spalte = array();
|
||||||
|
foreach ($titel as $index => $bezeichnung) {
|
||||||
|
$bezeichnung = trim($bezeichnung);
|
||||||
|
$len = strlen($bezeichnung);
|
||||||
|
if ($len >= 2 && $bezeichnung[0] === '"' && $bezeichnung[$len - 1] === '"') {
|
||||||
|
$bezeichnung = trim(str_replace('""', '"', substr($bezeichnung, 1, $len - 2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($bezeichnung === "name" || $bezeichnung === "nachname") {
|
||||||
|
$spalte["nachname"] = $index;
|
||||||
|
} else if ($bezeichnung === "vorname") {
|
||||||
|
$spalte["vorname"] = $index;
|
||||||
|
} else if ($bezeichnung === "name, vorname" || $bezeichnung === "name,vorname") {
|
||||||
|
$spalte["name,vorname"] = $index;
|
||||||
|
} else if ($bezeichnung === "pseudonym") {
|
||||||
|
$spalte["pseudonym"] = $index;
|
||||||
|
} else if ($bezeichnung === "geschlecht" || $bezeichnung === "anrede") {
|
||||||
|
$spalte["geschlecht"] = $index;
|
||||||
|
} else if ($bezeichnung === "spielernr" || $bezeichnung === "spielernr." || $bezeichnung === "spielerpass") {
|
||||||
|
$spalte["spielernr"] = $index;
|
||||||
|
} else if ($bezeichnung === "spielernr alt" || $bezeichnung === "spielernr. alt" || $bezeichnung === "spielernr_alt") {
|
||||||
|
$spalte["spielernr_alt"] = $index;
|
||||||
|
} else if ($bezeichnung === "lizenznr" || $bezeichnung === "lizenznr.") {
|
||||||
|
$spalte["lizenznr"] = $index;
|
||||||
|
} else if ($bezeichnung === "organisation") {
|
||||||
|
$spalte["organisation"] = $index;
|
||||||
|
} else if ($bezeichnung === "vereinssitz") {
|
||||||
|
$spalte["vereinssitz"] = $index;
|
||||||
|
} else if ($bezeichnung === "vereinsname" || $bezeichnung === "verein") {
|
||||||
|
$spalte["vereinsname"] = $index;
|
||||||
|
} else if ($bezeichnung === "geburtsdatum") {
|
||||||
|
$spalte["geburtsdatum"] = $index;
|
||||||
|
} else if ($bezeichnung === "geburtsjahr") {
|
||||||
|
$spalte["geburtsjahr"] = $index;
|
||||||
|
} else if ($bezeichnung === "email" || $bezeichnung === "e-mail") {
|
||||||
|
$spalte["email"] = $index;
|
||||||
|
} else if (str_starts_with($bezeichnung, "stra")) {
|
||||||
|
$spalte["strasse"] = $index;
|
||||||
|
} else if ($bezeichnung === "plz/ort") {
|
||||||
|
$spalte["plz/ort"] = $index;
|
||||||
|
} else if ($bezeichnung === "plz") {
|
||||||
|
$spalte["plz"] = $index;
|
||||||
|
} else if ($bezeichnung === "ort") {
|
||||||
|
$spalte["ort"] = $index;
|
||||||
|
} else if ($bezeichnung === "landeskennung") {
|
||||||
|
$spalte["landeskennung"] = $index;
|
||||||
|
} else if ($bezeichnung === "telefon") {
|
||||||
|
$spalte["telefon"] = $index;
|
||||||
|
} else if ($bezeichnung === "mobil") {
|
||||||
|
$spalte["mobil"] = $index;
|
||||||
|
} else if ($bezeichnung === "austritt" || $bezeichnung === "ausgetreten") {
|
||||||
|
$spalte["ausgetreten"] = $index;
|
||||||
|
} else if ($bezeichnung === "mitgliedsstatus") {
|
||||||
|
$spalte["mitgliedsstatus"] = $index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((!isset($spalte["nachname"]) || !isset($spalte["vorname"])) && !isset($spalte["name,vorname"])) || !isset($spalte["spielernr"])) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Die übergebene Datei ist keine gültige Spielerdatei (erforderliche Spalten fehlen).'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$lineIdx++;
|
||||||
|
// Source the staging session id from the database clock, not PHP's. The
|
||||||
|
// stale-row cleanup below compares session_id against the database NOW(); if
|
||||||
|
// PHP and the database run in different timezones, a PHP-generated timestamp
|
||||||
|
// can fall outside the window and the just-inserted rows get deleted mid-import.
|
||||||
|
$session_id = loadResult($db, "SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s')");
|
||||||
|
if (empty($session_id)) {
|
||||||
|
$session_id = date('Y-m-d H:i:s');
|
||||||
|
}
|
||||||
|
|
||||||
|
$organisations = [];
|
||||||
|
$rows_to_insert = [];
|
||||||
|
|
||||||
|
for ($i = $lineIdx; $i < count($lines); $i++) {
|
||||||
|
$buffer = trim($lines[$i]);
|
||||||
|
if ($buffer === "") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$daten = explode($trennzeichen, $buffer);
|
||||||
|
foreach ($daten as $index => $wert) {
|
||||||
|
$wert = trim($wert);
|
||||||
|
$len = strlen($wert);
|
||||||
|
if ($len < 2 || $wert[$len - 1] !== '"' || !($wert[0] === '"' || ($wert[0] === '=' && $wert[1] === '"'))) {
|
||||||
|
$daten[$index] = $wert;
|
||||||
|
} else if ($wert[0] === '"') {
|
||||||
|
$daten[$index] = trim(str_replace('""', '"', substr($wert, 1, $len - 2)));
|
||||||
|
} else {
|
||||||
|
$daten[$index] = trim(str_replace('""', '"', substr($wert, 2, $len - 3)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($spalte["vorname"]) && isset($spalte["nachname"]) && isset($daten[$spalte["vorname"]]) && isset($daten[$spalte["nachname"]])) {
|
||||||
|
$nachname = $daten[$spalte["nachname"]];
|
||||||
|
$vorname = $daten[$spalte["vorname"]];
|
||||||
|
} else if (isset($spalte["name,vorname"]) && isset($daten[$spalte["name,vorname"]])) {
|
||||||
|
$pos = strpos($daten[$spalte["name,vorname"]], ",");
|
||||||
|
if ($pos === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$nachname = trim(substr($daten[$spalte["name,vorname"]], 0, $pos));
|
||||||
|
$vorname = trim(substr($daten[$spalte["name,vorname"]], $pos + 1));
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($vorname === "" || $nachname === "") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$mitgliedsstatus = 1;
|
||||||
|
if (isset($spalte["mitgliedsstatus"]) && !empty($daten[$spalte["mitgliedsstatus"]])) {
|
||||||
|
$s = strtolower($daten[$spalte["mitgliedsstatus"]]);
|
||||||
|
if ($s === "ausgetreten") {
|
||||||
|
$mitgliedsstatus = 0;
|
||||||
|
} else if ($s === "passiv") {
|
||||||
|
$mitgliedsstatus = 3;
|
||||||
|
} else if (str_starts_with($s, "eingeschr")) {
|
||||||
|
$mitgliedsstatus = 2;
|
||||||
|
}
|
||||||
|
} else if (isset($spalte["ausgetreten"]) && !empty($daten[$spalte["ausgetreten"]])) {
|
||||||
|
if (strtolower($daten[$spalte["ausgetreten"]]) === "ja") {
|
||||||
|
$mitgliedsstatus = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mitgliedsstatus == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$geschlecht = isset($spalte["geschlecht"]) && !empty($daten[$spalte["geschlecht"]]) ? (($daten[$spalte["geschlecht"]][0] === "M" || $daten[$spalte["geschlecht"]][0] === "m" || $daten[$spalte["geschlecht"]][0] === "H" || $daten[$spalte["geschlecht"]][0] === "h") ? "M" : "W") : "M";
|
||||||
|
$spielernr = isset($daten[$spalte["spielernr"]]) ? trim($daten[$spalte["spielernr"]]) : "";
|
||||||
|
// Validate the Passnummer with the same format the manual import enforces
|
||||||
|
// (NN-NNNN[NN]). Invalid values are dropped rather than aborting the whole
|
||||||
|
// automated feed, keeping the player but treating them as having no pass.
|
||||||
|
if (!empty($spielernr) && !preg_match('/^[0-9]{2}-[0-9]{4,6}$/', $spielernr)) {
|
||||||
|
$spielernr = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
$spielernr_alt = isset($spalte["spielernr_alt"]) && isset($daten[$spalte["spielernr_alt"]]) ? trim($daten[$spalte["spielernr_alt"]]) : "";
|
||||||
|
if (!empty($spielernr_alt) && !preg_match('/^[0-9]{2}-[0-9]{4,6}$/', $spielernr_alt)) {
|
||||||
|
$spielernr_alt = "";
|
||||||
|
}
|
||||||
|
$lizenznr = isset($spalte["lizenznr"]) && isset($daten[$spalte["lizenznr"]]) ? $daten[$spalte["lizenznr"]] : "";
|
||||||
|
if (!empty($lizenznr) && !ctype_digit(substr($lizenznr, strlen($lizenznr) - 1, 1))) {
|
||||||
|
$lizenznr = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
$pseudonym = isset($spalte["pseudonym"]) && isset($daten[$spalte["pseudonym"]]) ? $daten[$spalte["pseudonym"]] : "";
|
||||||
|
$organisation = isset($spalte["organisation"]) && isset($daten[$spalte["organisation"]]) ? $daten[$spalte["organisation"]] : "";
|
||||||
|
$vereinssitz = isset($spalte["vereinssitz"]) && isset($daten[$spalte["vereinssitz"]]) ? $daten[$spalte["vereinssitz"]] : "";
|
||||||
|
$vereinsname = isset($spalte["vereinsname"]) && isset($daten[$spalte["vereinsname"]]) ? $daten[$spalte["vereinsname"]] : "";
|
||||||
|
|
||||||
|
$geburtsjahr = isset($spalte["geburtsjahr"]) && isset($daten[$spalte["geburtsjahr"]]) ? $daten[$spalte["geburtsjahr"]] : null;
|
||||||
|
if (empty($geburtsjahr) || !ctype_digit($geburtsjahr) || $geburtsjahr < 1800) {
|
||||||
|
$geburtsjahr = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($organisation)) {
|
||||||
|
$organisations[trim($organisation)] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows_to_insert[] = [
|
||||||
|
'vorname' => $vorname,
|
||||||
|
'nachname' => $nachname,
|
||||||
|
'spielernr' => $spielernr,
|
||||||
|
'spielernr_alt' => $spielernr_alt,
|
||||||
|
'lizenznr' => $lizenznr,
|
||||||
|
'pseudonym' => $pseudonym,
|
||||||
|
'organisation' => $organisation,
|
||||||
|
'vereinssitz' => $vereinssitz,
|
||||||
|
'vereinsname' => $vereinsname,
|
||||||
|
'geburtsjahr' => $geburtsjahr,
|
||||||
|
'mitgliedsstatus' => $mitgliedsstatus,
|
||||||
|
'geschlecht' => $geschlecht
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($rows_to_insert)) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Keine gültigen Spielerzeilen zum Importieren gefunden.'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-match Veranstalter by name. If it does not match, abort.
|
||||||
|
$org_map = [];
|
||||||
|
foreach (array_keys($organisations) as $orgName) {
|
||||||
|
$query = "SELECT veranstalter_id FROM #__sportsmanager_veranstalter WHERE veranstalterbezeichnung = '" . $db->escape($orgName) . "'";
|
||||||
|
$res = loadObjectList($db, $query);
|
||||||
|
if (count($res) === 0) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Veranstalter "' . $orgName . '" existiert nicht auf diesem Empfänger-System. Import abgebrochen.'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$org_map[$orgName] = intval($res[0]->veranstalter_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert into staging table
|
||||||
|
foreach ($rows_to_insert as $row) {
|
||||||
|
$query = "INSERT INTO #__sportsmanager_spieler_import"
|
||||||
|
. "\n SET session_id = '" . $db->escape($session_id) . "',"
|
||||||
|
. "\n vorname = '" . $db->escape($row['vorname']) . "',"
|
||||||
|
. "\n nachname = '" . $db->escape($row['nachname']) . "',"
|
||||||
|
. "\n spielernr = '" . $db->escape($row['spielernr']) . "',"
|
||||||
|
. "\n spielernr_alt = '" . $db->escape($row['spielernr_alt']) . "',"
|
||||||
|
. "\n lizenznr = '" . $db->escape($row['lizenznr']) . "',"
|
||||||
|
. "\n pseudonym = '" . $db->escape($row['pseudonym']) . "',"
|
||||||
|
. "\n geschlecht = '" . $db->escape($row['geschlecht']) . "',"
|
||||||
|
. "\n geburtsjahr = " . ($row['geburtsjahr'] === null ? "NULL" : "'" . $db->escape($row['geburtsjahr']) . "'") . ","
|
||||||
|
. "\n vereinsname = '" . $db->escape($row['vereinsname']) . "',"
|
||||||
|
. "\n vereinssitz = '" . $db->escape($row['vereinssitz']) . "',"
|
||||||
|
. "\n veranstalterbezeichnung = '" . $db->escape($row['organisation']) . "',"
|
||||||
|
. "\n mitgliedsstatus = '" . $row['mitgliedsstatus'] . "'";
|
||||||
|
$db->setQuery($query);
|
||||||
|
if (!$db->execute()) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Fehler beim Schreiben in die Staging-Tabelle: ' . $db->stderr()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up older staging data (older than 5 minutes)
|
||||||
|
$query = "SELECT DISTINCT session_id"
|
||||||
|
. "\n FROM #__sportsmanager_spieler_import"
|
||||||
|
. "\n WHERE session_id < SUBTIME(NOW(), '00:05:00')";
|
||||||
|
$old_sessions = loadObjectList($db, $query);
|
||||||
|
foreach ($old_sessions as $old_session) {
|
||||||
|
$query = "DELETE FROM #__sportsmanager_spieler_import WHERE session_id = '" . $db->escape($old_session->session_id) . "'";
|
||||||
|
$db->setQuery($query);
|
||||||
|
$db->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch staging players with matching ID
|
||||||
|
$query = "SELECT #__sportsmanager_spieler_import.*, #__sportsmanager_spieler.spieler_id"
|
||||||
|
. "\n FROM #__sportsmanager_spieler_import"
|
||||||
|
. "\n LEFT JOIN #__sportsmanager_spieler ON #__sportsmanager_spieler_import.spielernr != '' AND #__sportsmanager_spieler_import.spielernr = #__sportsmanager_spieler.spielernr"
|
||||||
|
. "\n WHERE session_id = '" . $db->escape($session_id) . "'";
|
||||||
|
$spieler_import = loadObjectList($db, $query);
|
||||||
|
|
||||||
|
// Count how many active players the incoming payload provides per organisation.
|
||||||
|
// The mass-deactivation below is only safe when the payload is a *full* roster;
|
||||||
|
// a partial CSV would otherwise silently deactivate every member not listed.
|
||||||
|
$incoming_per_org = [];
|
||||||
|
foreach ($rows_to_insert as $row) {
|
||||||
|
$o = trim($row['organisation']);
|
||||||
|
if ($o !== "") {
|
||||||
|
$incoming_per_org[$o] = ($incoming_per_org[$o] ?? 0) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Minimum fraction of the currently-active roster the payload must contain
|
||||||
|
// before the sweep is allowed to run. Configurable; defaults to 0.5.
|
||||||
|
$deactivation_min_ratio = (float) (einstellungswert("sync_deactivation_min_ratio") ?? 0.5);
|
||||||
|
if ($deactivation_min_ratio <= 0 || $deactivation_min_ratio > 1) {
|
||||||
|
$deactivation_min_ratio = 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
$warnings = [];
|
||||||
|
$deactivated_total = 0;
|
||||||
|
|
||||||
|
// Deactivate all memberships for involved organisations temporarily. The
|
||||||
|
// players present in the payload are reactivated further below; anyone not
|
||||||
|
// listed stays deactivated (i.e. is treated as having left the organisation).
|
||||||
|
foreach ($org_map as $orgName => $veranstalterId) {
|
||||||
|
$aktiv_vorher = (int) loadResult(
|
||||||
|
$db,
|
||||||
|
"SELECT COUNT(*) FROM #__sportsmanager_mitglied_von_verein"
|
||||||
|
. " INNER JOIN #__sportsmanager_verein USING (verein_id)"
|
||||||
|
. " WHERE veranstalter_id = " . $veranstalterId
|
||||||
|
. " AND NOT #__sportsmanager_mitglied_von_verein.ausgetreten"
|
||||||
|
);
|
||||||
|
$eingehend = $incoming_per_org[$orgName] ?? 0;
|
||||||
|
|
||||||
|
// Guard: skip the sweep when the payload looks like a partial roster
|
||||||
|
// (far fewer players than are currently active). This prevents a partial
|
||||||
|
// export from wiping an entire organisation's memberships.
|
||||||
|
if ($aktiv_vorher > 0 && $eingehend < $aktiv_vorher * $deactivation_min_ratio) {
|
||||||
|
$warnings[] = sprintf(
|
||||||
|
'Massen-Deaktivierung für "%s" übersprungen: nur %d von %d aktiven Mitgliedern in den Daten (mögliche Teil-Liste).',
|
||||||
|
$orgName,
|
||||||
|
$eingehend,
|
||||||
|
$aktiv_vorher
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = "UPDATE #__sportsmanager_mitglied_von_verein INNER JOIN #__sportsmanager_verein USING (verein_id)"
|
||||||
|
. "\n SET mitgliedsstatus = 0,"
|
||||||
|
. "\n #__sportsmanager_mitglied_von_verein.ausgetreten = TRUE"
|
||||||
|
. "\n WHERE veranstalter_id = " . $veranstalterId;
|
||||||
|
$db->setQuery($query);
|
||||||
|
if (!$db->execute()) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Fehler beim Deaktivieren der alten Vereinsmitgliedschaften.'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$deactivated_total += $aktiv_vorher;
|
||||||
|
}
|
||||||
|
|
||||||
|
$spieler_updated = 0;
|
||||||
|
$spieler_added = 0;
|
||||||
|
$spielerIdsHinzugefuegt = array();
|
||||||
|
|
||||||
|
foreach ($spieler_import as $t) {
|
||||||
|
$orgName = $t->veranstalterbezeichnung;
|
||||||
|
$veranstalterId = $org_map[$orgName] ?? -1;
|
||||||
|
|
||||||
|
if ($veranstalterId === -1 && !empty($orgName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$spieler_id = $t->spieler_id;
|
||||||
|
$nachname = $t->nachname;
|
||||||
|
$vorname = $t->vorname;
|
||||||
|
$geschlecht = $t->geschlecht;
|
||||||
|
$lizenznr = $t->lizenznr;
|
||||||
|
$pseudonym = $t->pseudonym;
|
||||||
|
$vereinsname = $t->vereinsname;
|
||||||
|
$vereinssitz = $t->vereinssitz;
|
||||||
|
$geburtsjahr = $t->geburtsjahr;
|
||||||
|
$spielernr = $t->spielernr;
|
||||||
|
$mitgliedsstatus = $t->mitgliedsstatus;
|
||||||
|
|
||||||
|
if ($spieler_id === null && !empty($spielernr) && isset($spielerIdsHinzugefuegt[$spielernr])) {
|
||||||
|
$spieler_id = $spielerIdsHinzugefuegt[$spielernr];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($spieler_id === null && empty($spielernr)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($spieler_id === null && empty($vereinsname)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($spieler_id !== null) {
|
||||||
|
$query = "UPDATE #__sportsmanager_spieler"
|
||||||
|
. "\n SET vorname = '" . $db->escape($vorname) . "',"
|
||||||
|
. "\n nachname = '" . $db->escape($nachname) . "',"
|
||||||
|
. "\n geschlecht = '" . $db->escape($geschlecht) . "'"
|
||||||
|
. "\n WHERE spieler_id = " . intval($spieler_id);
|
||||||
|
$db->setQuery($query);
|
||||||
|
if (!$db->execute()) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Fehler beim Aktualisieren des Spielers ID ' . $spieler_id
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$spieler_updated++;
|
||||||
|
} else {
|
||||||
|
$query = "INSERT INTO #__sportsmanager_spieler"
|
||||||
|
. "\n SET vorname = '" . $db->escape($vorname) . "',"
|
||||||
|
. "\n nachname = '" . $db->escape($nachname) . "',"
|
||||||
|
. "\n spielernr = '" . $db->escape($spielernr) . "',"
|
||||||
|
. "\n lizenznr = '" . $db->escape($lizenznr) . "',"
|
||||||
|
. "\n geschlecht = '" . $db->escape($geschlecht) . "',"
|
||||||
|
. "\n geburtsjahr = " . ($geburtsjahr === null ? "NULL" : "'" . $db->escape($geburtsjahr) . "'");
|
||||||
|
if (!empty($pseudonym)) {
|
||||||
|
$query .= ",\n pseudonym = '" . $db->escape($pseudonym) . "'";
|
||||||
|
}
|
||||||
|
$db->setQuery($query);
|
||||||
|
if (!$db->execute()) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Fehler beim Anlegen des neuen Spielers ' . $vorname . ' ' . $nachname
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$spieler_id = $db->insertid();
|
||||||
|
$spielerIdsHinzugefuegt[$spielernr] = $spieler_id;
|
||||||
|
|
||||||
|
$spieler_added++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($vereinsname) && $veranstalterId !== -1) {
|
||||||
|
$query = "SELECT spieler_id FROM #__sportsmanager_mitglied_von_verein"
|
||||||
|
. "\n WHERE spieler_id = $spieler_id AND verein_id = "
|
||||||
|
. " (SELECT verein_id FROM #__sportsmanager_verein WHERE vereinsname = '" . $db->escape($vereinsname) . "' AND veranstalter_id = $veranstalterId LIMIT 1)";
|
||||||
|
$memb_check = loadObjectList($db, $query);
|
||||||
|
|
||||||
|
if (count($memb_check) > 0) {
|
||||||
|
$query = "UPDATE #__sportsmanager_mitglied_von_verein, #__sportsmanager_verein"
|
||||||
|
. "\n SET mitgliedsstatus = '$mitgliedsstatus', #__sportsmanager_mitglied_von_verein.ausgetreten = FALSE"
|
||||||
|
. "\n WHERE spieler_id = $spieler_id AND vereinsname = '" . $db->escape($vereinsname) . "' AND #__sportsmanager_verein.verein_id = #__sportsmanager_mitglied_von_verein.verein_id"
|
||||||
|
. " AND veranstalter_id = $veranstalterId";
|
||||||
|
$db->setQuery($query);
|
||||||
|
$db->execute();
|
||||||
|
} else {
|
||||||
|
$query = "SELECT verein_id FROM #__sportsmanager_verein"
|
||||||
|
. "\n WHERE vereinsname = '" . $db->escape($vereinsname) . "' AND veranstalter_id = $veranstalterId";
|
||||||
|
$club_rows = loadObjectList($db, $query);
|
||||||
|
|
||||||
|
if (count($club_rows) > 0) {
|
||||||
|
$verein_id = intval($club_rows[0]->verein_id);
|
||||||
|
} else {
|
||||||
|
$query = "INSERT INTO #__sportsmanager_verein"
|
||||||
|
. "\n SET vereinsname = '" . $db->escape($vereinsname) . "',"
|
||||||
|
. "\n veranstalter_id = $veranstalterId";
|
||||||
|
if (!empty($vereinssitz)) {
|
||||||
|
$query .= ",\n vereinssitz = '" . $db->escape($vereinssitz) . "'";
|
||||||
|
}
|
||||||
|
$db->setQuery($query);
|
||||||
|
$db->execute();
|
||||||
|
$verein_id = $db->insertid();
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = "INSERT INTO #__sportsmanager_mitglied_von_verein"
|
||||||
|
. "\n SET spieler_id = $spieler_id, verein_id = $verein_id, mitgliedsstatus = '$mitgliedsstatus', ausgetreten = FALSE";
|
||||||
|
$db->setQuery($query);
|
||||||
|
$db->execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($org_map as $orgName => $veranstalterId) {
|
||||||
|
$query = "UPDATE #__sportsmanager_verein"
|
||||||
|
. "\n SET ausgetreten = TRUE"
|
||||||
|
. "\n WHERE NOT EXISTS(SELECT * FROM #__sportsmanager_mitglied_von_verein WHERE #__sportsmanager_verein.verein_id = #__sportsmanager_mitglied_von_verein.verein_id AND NOT #__sportsmanager_mitglied_von_verein.ausgetreten) AND NOT ausgetreten AND veranstalter_id = " . $veranstalterId;
|
||||||
|
$db->setQuery($query);
|
||||||
|
$db->execute();
|
||||||
|
|
||||||
|
$query = "UPDATE #__sportsmanager_verein"
|
||||||
|
. "\n SET ausgetreten = FALSE"
|
||||||
|
. "\n WHERE EXISTS(SELECT * FROM #__sportsmanager_mitglied_von_verein WHERE #__sportsmanager_verein.verein_id = #__sportsmanager_mitglied_von_verein.verein_id AND NOT #__sportsmanager_mitglied_von_verein.ausgetreten) AND ausgetreten AND veranstalter_id = " . $veranstalterId;
|
||||||
|
$db->setQuery($query);
|
||||||
|
$db->execute();
|
||||||
|
|
||||||
|
$query = "SELECT DISTINCT verein_id, #__sportsmanager_spieler_import.vereinsname, #__sportsmanager_spieler_import.vereinssitz"
|
||||||
|
. "\n FROM #__sportsmanager_spieler_import"
|
||||||
|
. "\n INNER JOIN #__sportsmanager_verein ON #__sportsmanager_verein.vereinsname = #__sportsmanager_spieler_import.vereinsname"
|
||||||
|
. "\n WHERE session_id = '" . $db->escape($session_id) . "' AND #__sportsmanager_spieler_import.veranstalterbezeichnung = '" . $db->escape($orgName) . "' AND #__sportsmanager_spieler_import.vereinsname != '' AND #__sportsmanager_spieler_import.vereinssitz != '' AND (ISNULL(#__sportsmanager_verein.vereinssitz) OR #__sportsmanager_verein.vereinssitz != #__sportsmanager_spieler_import.vereinssitz) AND NOT #__sportsmanager_verein.ausgetreten AND veranstalter_id = " . $veranstalterId;
|
||||||
|
$rows_headquarters = loadObjectList($db, $query);
|
||||||
|
foreach ($rows_headquarters as $row) {
|
||||||
|
$query = "UPDATE #__sportsmanager_verein"
|
||||||
|
. "\n SET vereinssitz = '" . $db->escape($row->vereinssitz) . "'"
|
||||||
|
. "\n WHERE verein_id = $row->verein_id";
|
||||||
|
$db->setQuery($query);
|
||||||
|
$db->execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = "DELETE FROM #__sportsmanager_spieler_import WHERE session_id = '" . $db->escape($session_id) . "'";
|
||||||
|
$db->setQuery($query);
|
||||||
|
$db->execute();
|
||||||
|
|
||||||
|
// Fail loudly on a zero-effect import: if valid rows were parsed but nothing
|
||||||
|
// was added or updated, the data almost certainly failed to map (e.g. an
|
||||||
|
// encoding mismatch corrupting organisation names). Reporting success here
|
||||||
|
// would silently hide data loss.
|
||||||
|
if (count($rows_to_insert) > 0 && $spieler_added === 0 && $spieler_updated === 0) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Import ergab keine Änderungen trotz ' . count($rows_to_insert)
|
||||||
|
. ' gültiger Zeilen – mögliche Encoding- oder Zuordnungsfehler.',
|
||||||
|
'spieler_count' => count($rows_to_insert),
|
||||||
|
'spieler_updated' => 0,
|
||||||
|
'spieler_added' => 0,
|
||||||
|
'warnings' => $warnings
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
aktuellerVereinAktualisieren();
|
||||||
|
ranglisteAktualisieren();
|
||||||
|
einstufungAktualisieren();
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'spieler_count' => count($rows_to_insert),
|
||||||
|
'spieler_updated' => $spieler_updated,
|
||||||
|
'spieler_added' => $spieler_added,
|
||||||
|
'deactivated' => $deactivated_total,
|
||||||
|
'warnings' => $warnings
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Endpoint task: triggered by GitHub Actions or other schedule.
|
||||||
|
* Authenticates with local api_push_key, exports player data, pushes to DTFB, and returns JSON.
|
||||||
|
*/
|
||||||
|
function apiSyncSpielerTrigger(): void
|
||||||
|
{
|
||||||
|
$token = syncGetBearerToken();
|
||||||
|
$expected_key = einstellungswert("api_push_key");
|
||||||
|
|
||||||
|
if (empty($expected_key) || $token !== $expected_key) {
|
||||||
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
echo json_encode(['success' => false, 'error' => 'Ungültiges Authentifizierungs-Token.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$csvData = syncExportSpielerCSV();
|
||||||
|
if (empty($csvData)) {
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
echo json_encode(['success' => false, 'error' => 'Keine Spieler zum Synchronisieren gefunden.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$res = syncPushToDtfb($csvData);
|
||||||
|
|
||||||
|
// Log sync status
|
||||||
|
syncLogEntry(
|
||||||
|
'push',
|
||||||
|
'api',
|
||||||
|
$res['success'] ? 'success' : 'error',
|
||||||
|
$res['spieler_count'] ?? 0,
|
||||||
|
$res['spieler_updated'] ?? 0,
|
||||||
|
$res['spieler_added'] ?? 0,
|
||||||
|
$res['message'] ?? '',
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
if ($res['success']) {
|
||||||
|
echo json_encode($res);
|
||||||
|
} else {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
echo json_encode($res);
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Endpoint task: receives CSV data from another Sportsmanager instance, imports it.
|
||||||
|
* Authenticates with local api_push_key.
|
||||||
|
*/
|
||||||
|
function apiSyncSpielerReceive(): void
|
||||||
|
{
|
||||||
|
$token = syncGetBearerToken();
|
||||||
|
$expected_key = einstellungswert("api_push_key");
|
||||||
|
|
||||||
|
if (empty($expected_key) || $token !== $expected_key) {
|
||||||
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
echo json_encode(['success' => false, 'error' => 'Ungültiges Authentifizierungs-Token.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$csvData = file_get_contents('php://input');
|
||||||
|
if (empty($csvData)) {
|
||||||
|
header('HTTP/1.1 400 Bad Request');
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
echo json_encode(['success' => false, 'error' => 'Keine Formulardaten empfangen.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$res = syncReceiveSpielerImport($csvData);
|
||||||
|
|
||||||
|
// Log sync status
|
||||||
|
syncLogEntry(
|
||||||
|
'receive',
|
||||||
|
'api',
|
||||||
|
$res['success'] ? 'success' : 'error',
|
||||||
|
$res['spieler_count'] ?? 0,
|
||||||
|
$res['spieler_updated'] ?? 0,
|
||||||
|
$res['spieler_added'] ?? 0,
|
||||||
|
$res['message'] ?? '',
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
if ($res['success']) {
|
||||||
|
echo json_encode($res);
|
||||||
|
} else {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
echo json_encode($res);
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -982,6 +982,21 @@ class HTML_sportsmanager_admin
|
|||||||
?>"/>
|
?>"/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td nowrap colspan="2">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="font-weight:bold"><label for="dtfb_sync_url">DTFB Sync Einstellungen</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="text-align: right"><label for="dtfb_sync_url">Sync-URL</label></td>
|
||||||
|
<td>
|
||||||
|
<input name="dtfb_sync_url" id="dtfb_sync_url" type="text" size="60"
|
||||||
|
value="<?php echo htmlspecialchars($einstellungen["dtfb_sync_url"] ?? '') ?>"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@@ -1255,6 +1270,18 @@ class HTML_sportsmanager_admin
|
|||||||
href="<?php echo SportsManagerURL('&task=admin_spieler_remove_inaktive_form'); ?>"><?php echo Text::_('COM_SPORTSMANAGER_CLEANUP_INACTIVE_PLAYERS'); ?></a>
|
href="<?php echo SportsManagerURL('&task=admin_spieler_remove_inaktive_form'); ?>"><?php echo Text::_('COM_SPORTSMANAGER_CLEANUP_INACTIVE_PLAYERS'); ?></a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td nowrap style="padding-top: 10px;">
|
||||||
|
<a href="<?php echo SportsManagerURL('&task=admin_spieler_sync_dtfb'); ?>"
|
||||||
|
onclick="return confirm('Spielerdaten jetzt mit DTFB synchronisieren?');"
|
||||||
|
class="uk-button uk-button-primary uk-button-small button" style="padding: 3px 10px; font-weight: bold; background: #007bc3; color: white; border-radius: 4px; border: none; text-decoration: none; display: inline-block;">
|
||||||
|
🔄 Sync zu DTFB
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td nowrap colspan="4" style="padding-top: 10px; vertical-align: middle;">
|
||||||
|
<small style="margin-left: 10px;">Letzter Sync: <?php echo syncGetLastStatus(); ?></small>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -3539,7 +3566,7 @@ class HTML_sportsmanager_admin
|
|||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|
||||||
static function adminVereine($rows, $organisationAnzeigen): void
|
static function adminVereine($rows, $organisationAnzeigen, $ansprechpartner): void
|
||||||
{
|
{
|
||||||
global $params;
|
global $params;
|
||||||
|
|
||||||
@@ -3599,6 +3626,8 @@ class HTML_sportsmanager_admin
|
|||||||
<th nowrap><strong><?php echo Text::_('COM_SPORTSMANAGER_MEMBERS'); ?></strong></th>
|
<th nowrap><strong><?php echo Text::_('COM_SPORTSMANAGER_MEMBERS'); ?></strong></th>
|
||||||
<th nowrap><strong><?php echo Text::_('COM_SPORTSMANAGER_TEAM_SEAT'); ?></strong></th>
|
<th nowrap><strong><?php echo Text::_('COM_SPORTSMANAGER_TEAM_SEAT'); ?></strong></th>
|
||||||
<th nowrap><strong><?php echo Text::_('COM_SPORTSMANAGER_BEATEN'); ?></strong></th>
|
<th nowrap><strong><?php echo Text::_('COM_SPORTSMANAGER_BEATEN'); ?></strong></th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
@@ -3661,6 +3690,14 @@ class HTML_sportsmanager_admin
|
|||||||
</td>
|
</td>
|
||||||
<td nowrap><?php if (!empty($row->vereinssitz)) echo htmlentities_utf8($row->vereinssitz . (!empty($row->vereinssitz_ortsteil) ? ("-" . $row->vereinssitz_ortsteil) : "")); ?></td>
|
<td nowrap><?php if (!empty($row->vereinssitz)) echo htmlentities_utf8($row->vereinssitz . (!empty($row->vereinssitz_ortsteil) ? ("-" . $row->vereinssitz_ortsteil) : "")); ?></td>
|
||||||
<td nowrap><?php echo $row->ausgetreten ? Text::_('COM_SPORTSMANAGER_YES') : Text::_('COM_SPORTSMANAGER_NO'); ?></td>
|
<td nowrap><?php echo $row->ausgetreten ? Text::_('COM_SPORTSMANAGER_YES') : Text::_('COM_SPORTSMANAGER_NO'); ?></td>
|
||||||
|
<td>
|
||||||
|
<?PHP
|
||||||
|
if (!empty($ansprechpartner[$row->verein_id])){
|
||||||
|
$emails = implode(';', $ansprechpartner[$row->verein_id]);
|
||||||
|
echo "<a href='mailto:" . $emails . "?subject=" . $row->vereinsname . "'>E-Mail</a> ";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
<td nowrap><small><a
|
<td nowrap><small><a
|
||||||
href="<?php echo SportsManagerURL('&task=admin_verein_remove&id=' . $row->verein_id); ?>"
|
href="<?php echo SportsManagerURL('&task=admin_verein_remove&id=' . $row->verein_id); ?>"
|
||||||
onclick="return confirm('<?php echo Text::_('COM_SPORTSMANAGER_WANT_REALLY_REMOVE'); ?>');"
|
onclick="return confirm('<?php echo Text::_('COM_SPORTSMANAGER_WANT_REALLY_REMOVE'); ?>');"
|
||||||
@@ -4834,6 +4871,29 @@ class HTML_sportsmanager_admin
|
|||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td nowrap style="width: 20%; text-align: right">
|
||||||
|
<label
|
||||||
|
for="games_in_statistik"><?php echo Text::_('COM_SPORTSMANAGER_GAMES_IN_STATISTIK'); ?>
|
||||||
|
:</label>
|
||||||
|
</td>
|
||||||
|
<td nowrap>
|
||||||
|
<select class="uk-select uk-form-width-medium" name="spiele_in_spielerstatistik"
|
||||||
|
id="games_in_statistik" size="1">
|
||||||
|
<option value="0"><?php echo Text::_('COM_SPORTSMANAGER_GAMES_IN_STATISTIK_ALL'); ?></option>
|
||||||
|
<?php
|
||||||
|
for ($i = 1; $i <= 36; $i++) {
|
||||||
|
echo "<option value=\"" . $i . "\"" . ($row != null ? ($row->spiele_in_spielerstatistik == $i ? " selected" : "") : "") . ">" . $i . "</option>";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td nowrap style="width: 20%; text-align: right">
|
<td nowrap style="width: 20%; text-align: right">
|
||||||
<label for="status"><?php echo Text::_('COM_SPORTSMANAGER_ACTIVE'); ?>
|
<label for="status"><?php echo Text::_('COM_SPORTSMANAGER_ACTIVE'); ?>
|
||||||
@@ -6362,8 +6422,13 @@ class HTML_sportsmanager_admin
|
|||||||
<select class="uk-select uk-form-width-large" name="tabellenwertung"
|
<select class="uk-select uk-form-width-large" name="tabellenwertung"
|
||||||
id="table_evaluation" size="1">
|
id="table_evaluation" size="1">
|
||||||
<?php
|
<?php
|
||||||
$typ = array(Text::_('COM_SPORTSMANAGER_POINTS_WON_LOST_DIFFERENCE'), Text::_('COM_SPORTSMANAGER_PERFORMANCE_INDEX'), Text::_('COM_SPORTSMANAGER_PERFORMANCE_INDEX2'));
|
$typ = array(0 => Text::_('COM_SPORTSMANAGER_PERFORMANCE_INDEX0'),
|
||||||
for ($i = 0; $i <= 2; $i++) {
|
1 => Text::_('COM_SPORTSMANAGER_PERFORMANCE_INDEX1'),
|
||||||
|
2 => Text::_('COM_SPORTSMANAGER_PERFORMANCE_INDEX2'),
|
||||||
|
3 => Text::_('COM_SPORTSMANAGER_PERFORMANCE_INDEX3'),
|
||||||
|
4 => Text::_('COM_SPORTSMANAGER_PERFORMANCE_INDEX4'),
|
||||||
|
5 => Text::_('COM_SPORTSMANAGER_PERFORMANCE_INDEX5'));
|
||||||
|
for ($i = 0; $i <= 5; $i++) {
|
||||||
echo "<option value=\"" . $i . "\"" . ($spielerstatistik != null ? ($spielerstatistik->tabellenwertung == $i ? " selected" : "") : "") . ">" . htmlentities_utf8($typ[$i]) . "</option>";
|
echo "<option value=\"" . $i . "\"" . ($spielerstatistik != null ? ($spielerstatistik->tabellenwertung == $i ? " selected" : "") : "") . ">" . htmlentities_utf8($typ[$i]) . "</option>";
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -8228,9 +8293,13 @@ static function adminVerbandsorganMitglieder($rows,$verbandsorgan): void
|
|||||||
if ($i == 2 && !$halloffame->platz2_zeigen) continue;
|
if ($i == 2 && !$halloffame->platz2_zeigen) continue;
|
||||||
if ($i == 3 && !$halloffame->platz3_zeigen) continue;
|
if ($i == 3 && !$halloffame->platz3_zeigen) continue;
|
||||||
if ($halloffame->spielform == 1) {
|
if ($halloffame->spielform == 1) {
|
||||||
$id = "verein_id_" . $i;
|
|
||||||
$txt = "teamname_" . $i;
|
$txt = "teamname_" . $i;
|
||||||
|
$id = "verein_id_" . $i;
|
||||||
$type = "vereine";
|
$type = "vereine";
|
||||||
|
if ($row->$id == ""){
|
||||||
|
$id = "team_id_" . $i;
|
||||||
|
$type = "mannschaften";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$id = "spieler1_id_" . $i;
|
$id = "spieler1_id_" . $i;
|
||||||
$txt = "spieler1_" . $i;
|
$txt = "spieler1_" . $i;
|
||||||
@@ -9435,12 +9504,16 @@ static function adminVerbandsorganMitglieder($rows,$verbandsorgan): void
|
|||||||
:</label>
|
:</label>
|
||||||
</td>
|
</td>
|
||||||
<td nowrap>
|
<td nowrap>
|
||||||
<select class="uk-select uk-form-width-medium" name="direktervergleich" id="dd_hthr" size="1">
|
<select class="uk-select uk-form-width-large" name="direktervergleich" id="dd_hthr" size="1">
|
||||||
<?php
|
<?php
|
||||||
$direktervergleich = array(Text::_('COM_SPORTSMANAGER_NO'), Text::_('COM_SPORTSMANAGER_YES'));
|
$typ = array(
|
||||||
for ($i = 0; $i <= 1; $i++) {
|
0 => Text::_('COM_SPORTSMANAGER_HEAD_TO_HEAD_OPT_NOT'),
|
||||||
echo "<option value=\"" . $i . "\"" . ($row != null ? ($row->direktervergleich == $i ? " selected" : "") : "") . ">" . htmlentities_utf8($direktervergleich[$i]) . "</option>";
|
1 => Text::_('COM_SPORTSMANAGER_HEAD_TO_HEAD_OPT_POINTS'),
|
||||||
}
|
2 => Text::_('COM_SPORTSMANAGER_HEAD_TO_HEAD_OPT_SETS'),
|
||||||
|
3 => Text::_('COM_SPORTSMANAGER_HEAD_TO_HEAD_OPT_GOALS')
|
||||||
|
);
|
||||||
|
foreach ($typ as $typ_wert => $typ_bezeichnung)
|
||||||
|
echo "<option value=\"" . $typ_wert . "\"" . ($row != null ? ($row->direktervergleich == $typ_wert ? " selected" : "") : "") . ">" . htmlentities_utf8($typ_bezeichnung) . "</option>";
|
||||||
?>
|
?>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
@@ -9662,7 +9735,7 @@ static function adminVerbandsorganMitglieder($rows,$verbandsorgan): void
|
|||||||
|
|
||||||
function pruefeAnzeige() {
|
function pruefeAnzeige() {
|
||||||
const wert = parseInt(dropdown.value);
|
const wert = parseInt(dropdown.value);
|
||||||
if (wert >= 1 && wert <= 9) {
|
if (wert >= 1 && wert <= 11) {
|
||||||
zeile.style.display = "";
|
zeile.style.display = "";
|
||||||
} else {
|
} else {
|
||||||
zeile.style.display = "none";
|
zeile.style.display = "none";
|
||||||
@@ -9676,7 +9749,7 @@ static function adminVerbandsorganMitglieder($rows,$verbandsorgan): void
|
|||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|
||||||
static function adminMannschaften($veranstaltung, $rows): void
|
static function adminMannschaften($veranstaltung, $rows, $ansprechpartner): void
|
||||||
{
|
{
|
||||||
global $params;
|
global $params;
|
||||||
|
|
||||||
@@ -9726,6 +9799,8 @@ static function adminVerbandsorganMitglieder($rows,$verbandsorgan): void
|
|||||||
<th nowrap title="<?php echo Text::_('COM_SPORTSMANAGER_NUM_REQUESTED_SHFITS_TOOLTIP'); ?>">
|
<th nowrap title="<?php echo Text::_('COM_SPORTSMANAGER_NUM_REQUESTED_SHFITS_TOOLTIP'); ?>">
|
||||||
<strong><?php echo Text::_('COM_SPORTSMANAGER_NUM_REQUESTED_SHIFTS'); ?></strong></th>
|
<strong><?php echo Text::_('COM_SPORTSMANAGER_NUM_REQUESTED_SHIFTS'); ?></strong></th>
|
||||||
<th nowrap><strong><?php echo Text::_('COM_SPORTSMANAGER_HOME_VENUE'); ?></strong></th>
|
<th nowrap><strong><?php echo Text::_('COM_SPORTSMANAGER_HOME_VENUE'); ?></strong></th>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
@@ -9768,6 +9843,14 @@ static function adminVerbandsorganMitglieder($rows,$verbandsorgan): void
|
|||||||
</td>
|
</td>
|
||||||
<td nowrap align="center"><?php echo $row->anzahl_verschiebungen; ?></td>
|
<td nowrap align="center"><?php echo $row->anzahl_verschiebungen; ?></td>
|
||||||
<td nowrap><?php if (!empty($row->name)) echo htmlentities_utf8($row->name); ?></td>
|
<td nowrap><?php if (!empty($row->name)) echo htmlentities_utf8($row->name); ?></td>
|
||||||
|
<td>
|
||||||
|
<?PHP
|
||||||
|
if (!empty($ansprechpartner[$row->team_id])){
|
||||||
|
$emails = implode(';', $ansprechpartner[$row->team_id]);
|
||||||
|
echo "<a href='mailto:" . $emails . "?subject=" . $row->teamname . "'>E-Mail</a> ";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
<?php if ($row->begegnungen == 0) { ?>
|
<?php if ($row->begegnungen == 0) { ?>
|
||||||
<td nowrap><small><a
|
<td nowrap><small><a
|
||||||
href="<?php echo SportsManagerURL('&task=admin_team_remove&veranstaltungid=' . $veranstaltung->veranstaltung_id . '&id=' . $row->team_id); ?>"
|
href="<?php echo SportsManagerURL('&task=admin_team_remove&veranstaltungid=' . $veranstaltung->veranstaltung_id . '&id=' . $row->team_id); ?>"
|
||||||
|
|||||||
@@ -411,6 +411,51 @@ class HTML_sportsmanager_ticker
|
|||||||
moreResults(matches, groups, day, page, 0);
|
moreResults(matches, groups, day, page, 0);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
<style>
|
||||||
|
#theme-toggle {
|
||||||
|
float: right;
|
||||||
|
margin-top: 15px;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
.theme-btn {
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 18px;
|
||||||
|
opacity: 0.5;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
.theme-btn:hover, .theme-btn.active {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
function applyTheme(theme) {
|
||||||
|
if (theme === 'dark' || (theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||||||
|
document.body.classList.add('dark-mode');
|
||||||
|
} else {
|
||||||
|
document.body.classList.remove('dark-mode');
|
||||||
|
}
|
||||||
|
if (document.getElementById('theme-' + theme)) {
|
||||||
|
document.querySelectorAll('.theme-btn').forEach(function(btn) { btn.classList.remove('active'); });
|
||||||
|
document.getElementById('theme-' + theme).classList.add('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var savedTheme = localStorage.getItem('livescore-theme') || 'auto';
|
||||||
|
|
||||||
|
function setTheme(theme) {
|
||||||
|
localStorage.setItem('livescore-theme', theme);
|
||||||
|
applyTheme(theme);
|
||||||
|
}
|
||||||
|
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function(e) {
|
||||||
|
if (localStorage.getItem('livescore-theme') === 'auto' || !localStorage.getItem('livescore-theme')) {
|
||||||
|
applyTheme('auto');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
applyTheme(localStorage.getItem('livescore-theme') || 'auto');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body onResize="resizee()">
|
<body onResize="resizee()">
|
||||||
@@ -433,6 +478,11 @@ class HTML_sportsmanager_ticker
|
|||||||
<div id="left_page_header">
|
<div id="left_page_header">
|
||||||
<h1 id="pagetitle_text">LIVE-TICKER</h1>
|
<h1 id="pagetitle_text">LIVE-TICKER</h1>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="theme-toggle">
|
||||||
|
<span id="theme-auto" class="theme-btn" onclick="setTheme('auto')" title="Auto Theme">💻</span>
|
||||||
|
<span id="theme-light" class="theme-btn" onclick="setTheme('light')" title="Light Theme">☀️</span>
|
||||||
|
<span id="theme-dark" class="theme-btn" onclick="setTheme('dark')" title="Dark Theme">🌙</span>
|
||||||
|
</div>
|
||||||
<a href="<?php echo SportsManagerURL(); ?>" id="homeicon">Home</a>
|
<a href="<?php echo SportsManagerURL(); ?>" id="homeicon">Home</a>
|
||||||
<div style="clear:both;"></div>
|
<div style="clear:both;"></div>
|
||||||
<div id="left_menu">
|
<div id="left_menu">
|
||||||
@@ -1838,6 +1888,99 @@ class HTML_sportsmanager_ticker
|
|||||||
height: 39px;
|
height: 39px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body.dark-mode {
|
||||||
|
background: #121212;
|
||||||
|
}
|
||||||
|
body.dark-mode #right_page {
|
||||||
|
background: #1e1e1e;
|
||||||
|
}
|
||||||
|
body.dark-mode h1#pagetitle_text {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
body.dark-mode a#homeicon {
|
||||||
|
color: #cccccc;
|
||||||
|
}
|
||||||
|
body.dark-mode #left_menu ul li a {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
body.dark-mode #tbl th {
|
||||||
|
color: #eeeeee;
|
||||||
|
background-color: #333333;
|
||||||
|
}
|
||||||
|
body.dark-mode #tbl tr td {
|
||||||
|
color: #dddddd;
|
||||||
|
}
|
||||||
|
body.dark-mode #detailedresults #tbl tr.odd td {
|
||||||
|
background-color: #242424;
|
||||||
|
}
|
||||||
|
body.dark-mode #detailedresults #tbl tr.even td {
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
}
|
||||||
|
body.dark-mode #tbl tr.tablehead td {
|
||||||
|
background-color: #333333;
|
||||||
|
}
|
||||||
|
body.dark-mode tr.finished.odd {
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
}
|
||||||
|
body.dark-mode tr.finished.even {
|
||||||
|
background-color: #2e2e2e;
|
||||||
|
}
|
||||||
|
body.dark-mode tr.updated {
|
||||||
|
background-color: #2d2616;
|
||||||
|
}
|
||||||
|
body.dark-mode tr.livenow {
|
||||||
|
background-color: #173824;
|
||||||
|
}
|
||||||
|
body.dark-mode tr.upcoming.odd {
|
||||||
|
background-color: #1a222f;
|
||||||
|
}
|
||||||
|
body.dark-mode tr.upcoming.even {
|
||||||
|
background-color: #1e2a3b;
|
||||||
|
}
|
||||||
|
body.dark-mode #tbl tr td.finished_winner {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
body.dark-mode tr.last_row {
|
||||||
|
background-color: #333333;
|
||||||
|
}
|
||||||
|
body.dark-mode #tbl tr td#last_row {
|
||||||
|
background-color: #333333;
|
||||||
|
}
|
||||||
|
body.dark-mode tr.upcoming.odd #resultat_holder,
|
||||||
|
body.dark-mode tr.upcoming.even #resultat_holder {
|
||||||
|
color: #eeeeee;
|
||||||
|
}
|
||||||
|
body.dark-mode #sponsorz {
|
||||||
|
background: #333333;
|
||||||
|
}
|
||||||
|
body.dark-mode .grey_button {
|
||||||
|
background: #333333;
|
||||||
|
}
|
||||||
|
body.dark-mode .grey_button a {
|
||||||
|
color: #eeeeee;
|
||||||
|
}
|
||||||
|
body.dark-mode .place_final {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
body.dark-mode .field_score {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
body.dark-mode .field_team {
|
||||||
|
color: #dddddd;
|
||||||
|
}
|
||||||
|
body.dark-mode .field_team.winner_bold {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
body.dark-mode #winner_area_positions span {
|
||||||
|
color: #dddddd;
|
||||||
|
}
|
||||||
|
body.dark-mode #winner_area_positions span#winner {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
body.dark-mode #winner_area_positions span#winner_name {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ COM_SPORTSMANAGER_DEFEAT="Niederlage"
|
|||||||
COM_SPORTSMANAGER_DEFEATS="Niederlagen"
|
COM_SPORTSMANAGER_DEFEATS="Niederlagen"
|
||||||
COM_SPORTSMANAGER_DEFEATS_SHORTCUT="N"
|
COM_SPORTSMANAGER_DEFEATS_SHORTCUT="N"
|
||||||
COM_SPORTSMANAGER_GOALS="Tore"
|
COM_SPORTSMANAGER_GOALS="Tore"
|
||||||
|
COM_SPORTSMANAGER_GOALS_SHORTCUT="T"
|
||||||
COM_SPORTSMANAGER_SETS="Sätze"
|
COM_SPORTSMANAGER_SETS="Sätze"
|
||||||
COM_SPORTSMANAGER_POINT="Punkt"
|
COM_SPORTSMANAGER_POINT="Punkt"
|
||||||
COM_SPORTSMANAGER_POINTS="Punkte"
|
COM_SPORTSMANAGER_POINTS="Punkte"
|
||||||
@@ -169,9 +170,9 @@ COM_SPORTSMANAGER_GAME_POINTS="Spielpunkte"
|
|||||||
COM_SPORTSMANAGER_GAME_POINTS_SHORTCUT="SP"
|
COM_SPORTSMANAGER_GAME_POINTS_SHORTCUT="SP"
|
||||||
COM_SPORTSMANAGER_SUFFIX_ONE_TEAM=" (eine Mannschaft)"
|
COM_SPORTSMANAGER_SUFFIX_ONE_TEAM=" (eine Mannschaft)"
|
||||||
COM_SPORTSMANAGER_SUFFIX_TEAMS_TOGETHER=" (Mannschaften zusammen)"
|
COM_SPORTSMANAGER_SUFFIX_TEAMS_TOGETHER=" (Mannschaften zusammen)"
|
||||||
COM_SPORTSMANAGER_DIFFERENCE="Differenz"
|
COM_SPORTSMANAGER_DIFFERENCE="Differenz Tore"
|
||||||
COM_SPORTSMANAGER_DIFFERENCE_IN_POINTS="Punktedifferenz"
|
COM_SPORTSMANAGER_DIFFERENCE_IN_POINTS="Differenz Spielpunkte"
|
||||||
COM_SPORTSMANAGER_POINTS_RATIO="Punkteverhältnis"
|
COM_SPORTSMANAGER_POINTS_RATIO="Verhältnis Spielpunkte"
|
||||||
COM_SPORTSMANAGER_SCHEDULE_DATE="Zeitpunkt"
|
COM_SPORTSMANAGER_SCHEDULE_DATE="Zeitpunkt"
|
||||||
COM_SPORTSMANAGER_TEAM_HOME="Heim"
|
COM_SPORTSMANAGER_TEAM_HOME="Heim"
|
||||||
COM_SPORTSMANAGER_TEAM_VISITOR="Gast"
|
COM_SPORTSMANAGER_TEAM_VISITOR="Gast"
|
||||||
@@ -296,7 +297,6 @@ COM_SPORTSMANAGER_REQUEST_MESSAGE_PLURAL="Es müssen mindestens %d Termine v
|
|||||||
COM_SPORTSMANAGER_REJECT_SHIFT="Verschiebung ablehnen"
|
COM_SPORTSMANAGER_REJECT_SHIFT="Verschiebung ablehnen"
|
||||||
COM_SPORTSMANAGER_TO="bis"
|
COM_SPORTSMANAGER_TO="bis"
|
||||||
COM_SPORTSMANAGER_PLAYER_STATISTICS="Spielerstatistiken"
|
COM_SPORTSMANAGER_PLAYER_STATISTICS="Spielerstatistiken"
|
||||||
COM_SPORTSMANAGER_PERFORMANCE_INDEX_SHORTCUT="LI"
|
|
||||||
COM_SPORTSMANAGER_WON="gewonnen"
|
COM_SPORTSMANAGER_WON="gewonnen"
|
||||||
COM_SPORTSMANAGER_LOST="verloren"
|
COM_SPORTSMANAGER_LOST="verloren"
|
||||||
COM_SPORTSMANAGER_RATE="Siegquote"
|
COM_SPORTSMANAGER_RATE="Siegquote"
|
||||||
@@ -500,6 +500,8 @@ COM_SPORTSMANAGER_WIN_1_POINT="Sieg: 1 Punkt"
|
|||||||
COM_SPORTSMANAGER_WIN_2_POINTS="Sieg: 2 Punkte, Unentschieden: 1 Punkt"
|
COM_SPORTSMANAGER_WIN_2_POINTS="Sieg: 2 Punkte, Unentschieden: 1 Punkt"
|
||||||
COM_SPORTSMANAGER_WIN_3_POINTS="Sieg: 3 Punkte, Unentschieden: 1 Punkt"
|
COM_SPORTSMANAGER_WIN_3_POINTS="Sieg: 3 Punkte, Unentschieden: 1 Punkt"
|
||||||
COM_SPORTSMANAGER_MEETING_CONCLUDED_AT="Begegnung abgeschlossen bei"
|
COM_SPORTSMANAGER_MEETING_CONCLUDED_AT="Begegnung abgeschlossen bei"
|
||||||
|
COM_SPORTSMANAGER_GAMES_IN_STATISTIK="Spiele in Spielerstatistik"
|
||||||
|
COM_SPORTSMANAGER_GAMES_IN_STATISTIK_ALL="Alle Spiele"
|
||||||
COM_SPORTSMANAGER_GENERALLY="Allgemein"
|
COM_SPORTSMANAGER_GENERALLY="Allgemein"
|
||||||
COM_SPORTSMANAGER_TYPE="Typ"
|
COM_SPORTSMANAGER_TYPE="Typ"
|
||||||
COM_SPORTSMANAGER_ELO_MIN="Elo min."
|
COM_SPORTSMANAGER_ELO_MIN="Elo min."
|
||||||
@@ -550,9 +552,22 @@ COM_SPORTSMANAGER_NO_RATING="Keine Wertung"
|
|||||||
COM_SPORTSMANAGER_TEAM_COMPETITIONS="Mannschaftswettbewerbe"
|
COM_SPORTSMANAGER_TEAM_COMPETITIONS="Mannschaftswettbewerbe"
|
||||||
COM_SPORTSMANAGER_TABLE_SUMMARY="Tabellenwertung"
|
COM_SPORTSMANAGER_TABLE_SUMMARY="Tabellenwertung"
|
||||||
COM_SPORTSMANAGER_HEAD_TO_HEAD_RECORD="Direkter Vergleich"
|
COM_SPORTSMANAGER_HEAD_TO_HEAD_RECORD="Direkter Vergleich"
|
||||||
|
COM_SPORTSMANAGER_HEAD_TO_HEAD_OPT_NOT="deaktiviert"
|
||||||
|
COM_SPORTSMANAGER_HEAD_TO_HEAD_OPT_POINTS="bei gleicher Punktzahl"
|
||||||
|
COM_SPORTSMANAGER_HEAD_TO_HEAD_OPT_SETS="bei gleicher Punktzahl, Satzpunkte"
|
||||||
|
COM_SPORTSMANAGER_HEAD_TO_HEAD_OPT_GOALS="bei gleicher Punktzahl, Satzpunkte, Tore"
|
||||||
COM_SPORTSMANAGER_POINTS_WON_LOST_DIFFERENCE="Spielpunkte gewonnen, Spielpunkte verloren, Punktedifferenz"
|
COM_SPORTSMANAGER_POINTS_WON_LOST_DIFFERENCE="Spielpunkte gewonnen, Spielpunkte verloren, Punktedifferenz"
|
||||||
COM_SPORTSMANAGER_PERFORMANCE_INDEX="Leistungsindex (SP+ * SP+ * 100) / (SP+ + SP-), Spielpunkte gewonnen, ..."
|
COM_SPORTSMANAGER_PERFORMANCE_INDEX0="Spielpunkte gewonnen, Spielpunkte verloren, Punktedifferenz"
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_INDEX1="Leistungsindex (SP+ * SP+ * 100) / (SP+ + SP-), Spielpunkte gewonnen, ..."
|
||||||
COM_SPORTSMANAGER_PERFORMANCE_INDEX2="Leistungsindex (S * P+ * 10) / (P+ + P-), Spielpunkte gewonnen, ..."
|
COM_SPORTSMANAGER_PERFORMANCE_INDEX2="Leistungsindex (S * P+ * 10) / (P+ + P-), Spielpunkte gewonnen, ..."
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_INDEX3="Race Performance Index (Siege*2 + Unentschieden + Tordifferenz)"
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_INDEX4="Effizienzindex (T+ / (T+ + T-))"
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_INDEX5="Punkteschnitt (P+ / Anzahl Sätze)"
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_SHORT1="LI"
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_SHORT2="LI"
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_SHORT3="RPI"
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_SHORT4="EI"
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_SHORT5="AVG"
|
||||||
COM_SPORTSMANAGER_INDIVIDUAL_STATISTICS="Einzelstatistik aus allen Spielen"
|
COM_SPORTSMANAGER_INDIVIDUAL_STATISTICS="Einzelstatistik aus allen Spielen"
|
||||||
COM_SPORTSMANAGER_INDIVIDUAL_STATISTICS_SINGLES="Einzelstatistik aus Einzel-Spielen"
|
COM_SPORTSMANAGER_INDIVIDUAL_STATISTICS_SINGLES="Einzelstatistik aus Einzel-Spielen"
|
||||||
COM_SPORTSMANAGER_INDIVIDUAL_STATISTICS_DOUBLES="Einzelstatistik aus Doppel-Spielen"
|
COM_SPORTSMANAGER_INDIVIDUAL_STATISTICS_DOUBLES="Einzelstatistik aus Doppel-Spielen"
|
||||||
@@ -1099,3 +1114,5 @@ COM_SPORTSMANAGER_REALLY_DELETE_MATCH_REPORT="Der Spielbericht wird zusammen mit
|
|||||||
COM_SPORTSMANAGER_MATCH_REPORT_DELETED="Spielbericht gelöscht"
|
COM_SPORTSMANAGER_MATCH_REPORT_DELETED="Spielbericht gelöscht"
|
||||||
COM_SPORTSMANAGER_MATCH_REPORT_WAS_DELETED="Der Spielbericht wurde erfolgreich gelöscht!"
|
COM_SPORTSMANAGER_MATCH_REPORT_WAS_DELETED="Der Spielbericht wurde erfolgreich gelöscht!"
|
||||||
COM_SPORTSMANAGER_MATCH_REPORT_CORRECTED="Spielberichtskorrektur"
|
COM_SPORTSMANAGER_MATCH_REPORT_CORRECTED="Spielberichtskorrektur"
|
||||||
|
COM_SPORTSMANAGER_MIN_MATCHES="Mindestzahl Spiele"
|
||||||
|
COM_SPORTSMANAGER_SELECT_ALL="Alle"
|
||||||
@@ -157,6 +157,7 @@ COM_SPORTSMANAGER_DEFEAT="Defeat"
|
|||||||
COM_SPORTSMANAGER_DEFEATS="Defeats"
|
COM_SPORTSMANAGER_DEFEATS="Defeats"
|
||||||
COM_SPORTSMANAGER_DEFEATS_SHORTCUT="F"
|
COM_SPORTSMANAGER_DEFEATS_SHORTCUT="F"
|
||||||
COM_SPORTSMANAGER_GOALS="Goals"
|
COM_SPORTSMANAGER_GOALS="Goals"
|
||||||
|
COM_SPORTSMANAGER_GOALS_SHORTCUT="G"
|
||||||
COM_SPORTSMANAGER_SETS="Sets"
|
COM_SPORTSMANAGER_SETS="Sets"
|
||||||
COM_SPORTSMANAGER_POINT="Point"
|
COM_SPORTSMANAGER_POINT="Point"
|
||||||
COM_SPORTSMANAGER_POINTS="Points"
|
COM_SPORTSMANAGER_POINTS="Points"
|
||||||
@@ -169,9 +170,9 @@ COM_SPORTSMANAGER_GAME_POINTS="Game points"
|
|||||||
COM_SPORTSMANAGER_GAME_POINTS_SHORTCUT="GP"
|
COM_SPORTSMANAGER_GAME_POINTS_SHORTCUT="GP"
|
||||||
COM_SPORTSMANAGER_SUFFIX_ONE_TEAM=" (one team)"
|
COM_SPORTSMANAGER_SUFFIX_ONE_TEAM=" (one team)"
|
||||||
COM_SPORTSMANAGER_SUFFIX_TEAMS_TOGETHER=" (teams together)"
|
COM_SPORTSMANAGER_SUFFIX_TEAMS_TOGETHER=" (teams together)"
|
||||||
COM_SPORTSMANAGER_DIFFERENCE="Difference"
|
COM_SPORTSMANAGER_DIFFERENCE="Goal difference"
|
||||||
COM_SPORTSMANAGER_DIFFERENCE_IN_POINTS="Difference in points"
|
COM_SPORTSMANAGER_DIFFERENCE_IN_POINTS="Difference in game points"
|
||||||
COM_SPORTSMANAGER_POINTS_RATIO="Points ratio"
|
COM_SPORTSMANAGER_POINTS_RATIO="Game points ratio"
|
||||||
COM_SPORTSMANAGER_SCHEDULE_DATE="Appointment date"
|
COM_SPORTSMANAGER_SCHEDULE_DATE="Appointment date"
|
||||||
COM_SPORTSMANAGER_TEAM_HOME="Home"
|
COM_SPORTSMANAGER_TEAM_HOME="Home"
|
||||||
COM_SPORTSMANAGER_TEAM_VISITOR="Visitor"
|
COM_SPORTSMANAGER_TEAM_VISITOR="Visitor"
|
||||||
@@ -296,7 +297,6 @@ COM_SPORTSMANAGER_REQUEST_MESSAGE_PLURAL="At least %d dates must be given comple
|
|||||||
COM_SPORTSMANAGER_REJECT_SHIFT="Reject shift"
|
COM_SPORTSMANAGER_REJECT_SHIFT="Reject shift"
|
||||||
COM_SPORTSMANAGER_TO="until"
|
COM_SPORTSMANAGER_TO="until"
|
||||||
COM_SPORTSMANAGER_PLAYER_STATISTICS="Player statistics"
|
COM_SPORTSMANAGER_PLAYER_STATISTICS="Player statistics"
|
||||||
COM_SPORTSMANAGER_PERFORMANCE_INDEX_SHORTCUT="PI"
|
|
||||||
COM_SPORTSMANAGER_WON="won"
|
COM_SPORTSMANAGER_WON="won"
|
||||||
COM_SPORTSMANAGER_LOST="lost"
|
COM_SPORTSMANAGER_LOST="lost"
|
||||||
COM_SPORTSMANAGER_RATE="Winning rate"
|
COM_SPORTSMANAGER_RATE="Winning rate"
|
||||||
@@ -500,6 +500,8 @@ COM_SPORTSMANAGER_WIN_1_POINT="Win: 1 point"
|
|||||||
COM_SPORTSMANAGER_WIN_2_POINTS="Win: 2 points, draw: 1 point"
|
COM_SPORTSMANAGER_WIN_2_POINTS="Win: 2 points, draw: 1 point"
|
||||||
COM_SPORTSMANAGER_WIN_3_POINTS="Win: 3 points, draw: 1 point"
|
COM_SPORTSMANAGER_WIN_3_POINTS="Win: 3 points, draw: 1 point"
|
||||||
COM_SPORTSMANAGER_MEETING_CONCLUDED_AT="Match won at"
|
COM_SPORTSMANAGER_MEETING_CONCLUDED_AT="Match won at"
|
||||||
|
COM_SPORTSMANAGER_GAMES_IN_STATISTIK="Games in player statistics"
|
||||||
|
COM_SPORTSMANAGER_GAMES_IN_STATISTIK_ALL="All games"
|
||||||
COM_SPORTSMANAGER_GENERALLY="Generally"
|
COM_SPORTSMANAGER_GENERALLY="Generally"
|
||||||
COM_SPORTSMANAGER_TYPE="Type"
|
COM_SPORTSMANAGER_TYPE="Type"
|
||||||
COM_SPORTSMANAGER_ELO_MIN="Elo min."
|
COM_SPORTSMANAGER_ELO_MIN="Elo min."
|
||||||
@@ -550,9 +552,22 @@ COM_SPORTSMANAGER_NO_RATING="No rating"
|
|||||||
COM_SPORTSMANAGER_TEAM_COMPETITIONS="Team competitions"
|
COM_SPORTSMANAGER_TEAM_COMPETITIONS="Team competitions"
|
||||||
COM_SPORTSMANAGER_TABLE_SUMMARY="Table rating"
|
COM_SPORTSMANAGER_TABLE_SUMMARY="Table rating"
|
||||||
COM_SPORTSMANAGER_HEAD_TO_HEAD_RECORD="Head-to-head record"
|
COM_SPORTSMANAGER_HEAD_TO_HEAD_RECORD="Head-to-head record"
|
||||||
|
COM_SPORTSMANAGER_HEAD_TO_HEAD_OPT_NOT="Off"
|
||||||
|
COM_SPORTSMANAGER_HEAD_TO_HEAD_OPT_POINTS="Tie: pts"
|
||||||
|
COM_SPORTSMANAGER_HEAD_TO_HEAD_OPT_SETS="Tie: pts, set points"
|
||||||
|
COM_SPORTSMANAGER_HEAD_TO_HEAD_OPT_GOALS="Tie: pts, set points, goals"
|
||||||
COM_SPORTSMANAGER_POINTS_WON_LOST_DIFFERENCE="Game points won, game points lost, point difference"
|
COM_SPORTSMANAGER_POINTS_WON_LOST_DIFFERENCE="Game points won, game points lost, point difference"
|
||||||
COM_SPORTSMANAGER_PERFORMANCE_INDEX="Performance index (GP+ * GP+ * 100) / (GP+ + GP-), game points won, ..."
|
COM_SPORTSMANAGER_PERFORMANCE_INDEX0="Game points won, game points lost, point difference"
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_INDEX1="Performance index (GP+ * GP+ * 100) / (GP+ + GP-), game points won, ..."
|
||||||
COM_SPORTSMANAGER_PERFORMANCE_INDEX2="Performance index (games * P+ * 10) / (P+ + P-), game points won, ..."
|
COM_SPORTSMANAGER_PERFORMANCE_INDEX2="Performance index (games * P+ * 10) / (P+ + P-), game points won, ..."
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_INDEX3="Race Performance Index (victories*2 + draws + goal difference)"
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_INDEX4="Efficency index (G+ / (G+ + G-))"
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_INDEX5="Set point average (P+ / count sets)"
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_SHORT1="LI"
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_SHORT2="LI"
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_SHORT3="RPI"
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_SHORT4="EI"
|
||||||
|
COM_SPORTSMANAGER_PERFORMANCE_SHORT5="AVG"
|
||||||
COM_SPORTSMANAGER_INDIVIDUAL_STATISTICS="Individual statistics of all games"
|
COM_SPORTSMANAGER_INDIVIDUAL_STATISTICS="Individual statistics of all games"
|
||||||
COM_SPORTSMANAGER_INDIVIDUAL_STATISTICS_SINGLES="Individual statistics of singles games"
|
COM_SPORTSMANAGER_INDIVIDUAL_STATISTICS_SINGLES="Individual statistics of singles games"
|
||||||
COM_SPORTSMANAGER_INDIVIDUAL_STATISTICS_DOUBLES="Individual statistics of doubles games"
|
COM_SPORTSMANAGER_INDIVIDUAL_STATISTICS_DOUBLES="Individual statistics of doubles games"
|
||||||
@@ -1099,3 +1114,5 @@ COM_SPORTSMANAGER_REALLY_DELETE_MATCH_REPORT="The match report and all its histo
|
|||||||
COM_SPORTSMANAGER_MATCH_REPORT_DELETED="Match report deleted"
|
COM_SPORTSMANAGER_MATCH_REPORT_DELETED="Match report deleted"
|
||||||
COM_SPORTSMANAGER_MATCH_REPORT_WAS_DELETED="The match report has been successfully deleted!"
|
COM_SPORTSMANAGER_MATCH_REPORT_WAS_DELETED="The match report has been successfully deleted!"
|
||||||
COM_SPORTSMANAGER_MATCH_REPORT_CORRECTED="Match report corrected"
|
COM_SPORTSMANAGER_MATCH_REPORT_CORRECTED="Match report corrected"
|
||||||
|
COM_SPORTSMANAGER_MIN_MATCHES="Min count matches"
|
||||||
|
COM_SPORTSMANAGER_SELECT_ALL="All"
|
||||||
@@ -526,6 +526,7 @@ return new class () implements InstallerScriptInterface
|
|||||||
. "\n `bestenliste_id` int(11) NOT NULL DEFAULT '0',"
|
. "\n `bestenliste_id` int(11) NOT NULL DEFAULT '0',"
|
||||||
. "\n `spieler_id` int(11) NOT NULL DEFAULT '0',"
|
. "\n `spieler_id` int(11) NOT NULL DEFAULT '0',"
|
||||||
. "\n `spieler_2_id` int(11) DEFAULT NULL,"
|
. "\n `spieler_2_id` int(11) DEFAULT NULL,"
|
||||||
|
. "\n `team_id` INT(11) DEFAULT NULL,"
|
||||||
. "\n `siege` smallint(6) DEFAULT NULL,"
|
. "\n `siege` smallint(6) DEFAULT NULL,"
|
||||||
. "\n `unentschieden` smallint(6) DEFAULT NULL,"
|
. "\n `unentschieden` smallint(6) DEFAULT NULL,"
|
||||||
. "\n `niederlagen` smallint(6) DEFAULT NULL,"
|
. "\n `niederlagen` smallint(6) DEFAULT NULL,"
|
||||||
@@ -789,6 +790,7 @@ return new class () implements InstallerScriptInterface
|
|||||||
. "\n `spielpunkte_bedingung` tinyint(4) NOT NULL DEFAULT '0',"
|
. "\n `spielpunkte_bedingung` tinyint(4) NOT NULL DEFAULT '0',"
|
||||||
. "\n `spielernamen` tinyint(4) NOT NULL DEFAULT '0',"
|
. "\n `spielernamen` tinyint(4) NOT NULL DEFAULT '0',"
|
||||||
. "\n `heimtausch` tinyint(4) NOT NULL DEFAULT '0',"
|
. "\n `heimtausch` tinyint(4) NOT NULL DEFAULT '0',"
|
||||||
|
. "\n `spiele_in_spielerstatistik` tinyint(4) NOT NULL DEFAULT '0',"
|
||||||
. "\n `modus` varchar(200) NOT NULL DEFAULT '',"
|
. "\n `modus` varchar(200) NOT NULL DEFAULT '',"
|
||||||
. "\n `status` tinyint(4) NOT NULL DEFAULT '0',"
|
. "\n `status` tinyint(4) NOT NULL DEFAULT '0',"
|
||||||
. "\n PRIMARY KEY (`teamspiel_modus_id`)"
|
. "\n PRIMARY KEY (`teamspiel_modus_id`)"
|
||||||
@@ -1272,7 +1274,28 @@ return new class () implements InstallerScriptInterface
|
|||||||
$db->setQuery( $query );
|
$db->setQuery( $query );
|
||||||
if (!$db->execute()) { die($db->stderr(true)); }
|
if (!$db->execute()) { die($db->stderr(true)); }
|
||||||
|
|
||||||
$query = "INSERT IGNORE #__sportsmanager_einstellungen SET name = 'datenbank_version', wert = '119';";
|
$query = "INSERT IGNORE #__sportsmanager_einstellungen SET name = 'datenbank_version', wert = '121';";
|
||||||
|
$db->setQuery( $query );
|
||||||
|
if (!$db->execute()) { die($db->stderr(true)); }
|
||||||
|
|
||||||
|
$query = "CREATE TABLE IF NOT EXISTS `#__sportsmanager_sync_log` ("
|
||||||
|
. "\n `sync_id` INT(11) NOT NULL AUTO_INCREMENT,"
|
||||||
|
. "\n `sync_timestamp` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,"
|
||||||
|
. "\n `sync_direction` ENUM('push', 'receive') NOT NULL,"
|
||||||
|
. "\n `sync_trigger` ENUM('manual', 'cron', 'api') NOT NULL,"
|
||||||
|
. "\n `sync_status` ENUM('success', 'error') NOT NULL,"
|
||||||
|
. "\n `spieler_count` INT(11) DEFAULT 0,"
|
||||||
|
. "\n `spieler_updated` INT(11) DEFAULT 0,"
|
||||||
|
. "\n `spieler_added` INT(11) DEFAULT 0,"
|
||||||
|
. "\n `message` TEXT,"
|
||||||
|
. "\n `details` TEXT,"
|
||||||
|
. "\n PRIMARY KEY (`sync_id`),"
|
||||||
|
. "\n INDEX `idx_timestamp` (`sync_timestamp`)"
|
||||||
|
. "\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
|
||||||
|
$db->setQuery( $query );
|
||||||
|
if (!$db->execute()) { die($db->stderr(true)); }
|
||||||
|
|
||||||
|
$query = "INSERT IGNORE #__sportsmanager_einstellungen SET name = 'dtfb_sync_url', wert = '';";
|
||||||
$db->setQuery( $query );
|
$db->setQuery( $query );
|
||||||
if (!$db->execute()) { die($db->stderr(true)); }
|
if (!$db->execute()) { die($db->stderr(true)); }
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# DTFB Player Sync — QA findings & applied fixes
|
||||||
|
|
||||||
|
Concise record of the defects found while reviewing the player-sync receiver
|
||||||
|
(`syncReceiveSpielerImport()` in `sync.php`) and the six fixes applied in this PR.
|
||||||
|
The exploratory test harness used to find these has been removed — the
|
||||||
|
authoritative next test is the **staging end-to-end sync** (see the PR description).
|
||||||
|
|
||||||
|
## The six issues fixed
|
||||||
|
|
||||||
|
| # | Issue | Impact | Fix in `sync.php` |
|
||||||
|
|---|-------|--------|-------------------|
|
||||||
|
| 1 | **Receiver did not normalise input encoding.** A latin1 / Windows-1252 CSV (the legacy manual export) has `ß` as the single byte `0xDF`. Staging the org name into the utf8mb4 table truncated it at that byte, so the org lookup missed and **every row was skipped**. | Critical — silent data loss (e.g. 2964 rows parsed, 0 imported, `success=true`). | Transcode the payload to UTF-8 when it is not already valid UTF-8, before staging. |
|
||||||
|
| 2 | **A zero-effect import reported success.** When N rows parsed but nothing was added or updated, the function returned `success=true`. | Critical — masks encoding/mapping failures. | Return `success=false` with a diagnostic message when `rows>0` but `added==0 && updated==0`. |
|
||||||
|
| 3 | **Dead `$naechste_spielernr` block** referenced an undefined variable in the insert branch. | Runtime notice; incoming rows already carry their Passnummer. | Removed the block. |
|
||||||
|
| 4 | **Unconditional mass-deactivation.** A partial CSV deactivated every member not listed. | High — a broken/partial export could wipe an org's roster. | Per organisation, skip the deactivation sweep when the incoming count is below `sync_deactivation_min_ratio` (default 0.5) of the org's currently-active members; adds/updates still proceed and a warning is returned. |
|
||||||
|
| 5 | **Split clock for staging.** `session_id` came from PHP `date()` while stale-row cleanup used MySQL `NOW()`; a PHP/MySQL timezone gap could delete in-flight staging rows. | Medium — another silent 0-row path. | Derive `session_id` from the DB clock (`NOW()`), with `date()` fallback. |
|
||||||
|
| 6 | **No Passnummer format check.** The manual import UI enforces `^[0-9]{2}-[0-9]{4,6}$`; the sync receiver did not. | Medium — inconsistent data quality vs the manual flow. | Apply the same regex to `spielernr` / `spielernr_alt` (blank/reject on mismatch). |
|
||||||
|
|
||||||
|
## Confirmed by design (not bugs)
|
||||||
|
- **No contact / personal data** (email, phone, address) is ever exported or imported.
|
||||||
|
- Existing players keep their `lizenznr` and `geburtsjahr` on update; only name / sex / Passnummer-driven fields change.
|
||||||
|
- An unknown organisation aborts the whole import with no mutation.
|
||||||
|
- The sync path itself (export → cURL push → receive) is UTF-8 end-to-end; the encoding defect (#1) only affected ingesting a legacy latin1 *manual* file.
|
||||||
Reference in New Issue
Block a user