index fertig bis auf rank

This commit is contained in:
Timon Ostertun
2020-09-22 23:32:48 +02:00
parent cb840a8451
commit 4a3a8b636b
19 changed files with 2215 additions and 73 deletions

View File

@@ -27,13 +27,6 @@
define('DB_TABLE_NEWS', 'news'); define('DB_TABLE_NEWS', 'news');
define('DB_TABLE_UPDATETIMES', '_updatetimes'); define('DB_TABLE_UPDATETIMES', '_updatetimes');
// PERMISSIONS
define('PERM_ALL', 0);
define('PERM_REGISTERED', 1);
define('PERM_READ', 2);
define('PERM_WRITE', 4);
define('PERM_ADMIN', 8);
// OUTGOING MAILS - Credentials for outgoing mails // OUTGOING MAILS - Credentials for outgoing mails
define('MAIL_SMTP_HOST', 'ssl://ostertun.net'); // SMTP Server address define('MAIL_SMTP_HOST', 'ssl://ostertun.net'); // SMTP Server address
define('MAIL_SMTP_PORT', 465); // port to use define('MAIL_SMTP_PORT', 465); // port to use

450
api/functions.php Normal file
View File

@@ -0,0 +1,450 @@
<?php
function get_db_entry($mysqli, $table, $id = false, $order = false) {
if ($id === false) {
return db_get_data($mysqli, $table, '*', ($order !== false ? ('1=1 ORDER BY ' . $order) : false));
} else {
$result = db_get_data($mysqli, $table, '*', '`id` = "' . mysqli_real_escape_string($mysqli, $id) . '"', 1);
if (($result === false) or (count($result) != 1))
return false;
else
return array_values($result)[0];
}
}
function get_club($mysqli, $id = false) {
return get_db_entry($mysqli, DB_TABLE_CLUBS, $id, '`kurz` ASC');
}
function get_boat($mysqli, $id = false) {
return get_db_entry($mysqli, BOATCLASS . DB_TABLE_SUFFIX_BOATS, $id, '`sailnumber` ASC');
}
function get_sailor($mysqli, $id = false) {
return get_db_entry($mysqli, BOATCLASS . DB_TABLE_SUFFIX_SAILORS, $id, '`name` ASC');
}
function get_planning($mysqli, $userId = false, $regattaId = false) {
$where = '';
$limit = false;
if ($userId !== false) {
$where .= '(`user`="' . mysqli_real_escape_string($mysqli, $userId) . '")';
}
if (($userId !== false) and ($regattaId !== false)) {
$where .= ' AND ';
$limit = 1;
}
if ($regattaId !== false) {
$where .= '(`regatta`="' . mysqli_real_escape_string($mysqli, $regattaId) . '")';
}
if ($where == '') $where = false;
if ($limit === false) {
return db_get_data($mysqli, BOATCLASS . DB_TABLE_SUFFIX_PLANNING, '*', $where);
} else {
$result = db_get_data($mysqli, BOATCLASS . DB_TABLE_SUFFIX_PLANNING, '*', $where, 1);
if (($result === false) or (count($result) != 1))
return false;
else
return array_values($result)[0];
}
}
function get_regatta($mysqli, $id = false) {
return get_db_entry($mysqli, BOATCLASS . DB_TABLE_SUFFIX_REGATTAS, $id, '`date` ASC');
}
function get_result($mysqli, $regattaId = false) {
if ($regattaId === false) {
return db_get_data($mysqli, BOATCLASS . DB_TABLE_SUFFIX_RESULTS);
} else {
return db_get_data($mysqli, BOATCLASS . DB_TABLE_SUFFIX_RESULTS, '*', '`regatta` = "' . mysqli_real_escape_string($mysqli, $regattaId) . '"');
}
}
function get_regattas_range($mysqli, $from, $to) {
return db_get_data($mysqli, BOATCLASS . DB_TABLE_SUFFIX_REGATTAS, '*', '(`date` >= "' . date('Y-m-d', $from) . '") AND (`date` <= "' . date('Y-m-d', $to) . '") ORDER BY `date`');
}
function get_regatta_years($mysqli) {
$query = 'SELECT DISTINCT(YEAR(`date`)) as year FROM ' . BOATCLASS . DB_TABLE_SUFFIX_REGATTAS . ' ORDER BY `date`;';
$response = mysqli_query($mysqli, $query);
if ($response !== false) {
$result = array();
if ($response->num_rows > 0) {
while ($row = $response->fetch_assoc()) {
$result[] = $row['year'];
}
}
return $result;
} else {
logE("functions", "get_data\nInvalid request\n" . $query . "\n" . mysqli_error($mysqli));
return false;
}
}
function get_result_calculated($mysqli, $regatta_id) {
$regatta = get_regatta($mysqli, $regatta_id);
if ($regatta === false) {
return false;
}
$results = get_result($mysqli, $regatta_id);
if ($results !== false) {
// *** Replace , with .
foreach ($results as $key => $value) {
for ($i = 1; $i <= $regatta['races']; $i ++) {
$results[$key]['race' . $i] = str_replace(',', '.', $results[$key]['race' . $i]);
}
}
// *** Calculation ***
$gemeldet = count($results);
$sortarray = array();
foreach ($results as $key => $value) {
$results[$key]['finished'] = false;
$results[$key]['values'] = array();
$results[$key]['values_all'] = array();
$results[$key]['texts'] = array();
$copy = array();
for ($i = 1; $i <= $regatta['races']; $i ++) {
if (is_numeric($value['race' . $i])) {
$results[$key]['values'][$i] = $value['race' . $i];
$results[$key]['texts'][$i] = $value['race' . $i];
$copy[$i] = $value['race' . $i];
$results[$key]['finished'] = true;
} else {
switch ($value['race' . $i]) {
// Nicht gestartet
case 'DNC': $results[$key]['values'][$i] = $gemeldet + 1; $copy[$i] = $gemeldet + 1; break; // Did not come
case 'DNS': $results[$key]['values'][$i] = $gemeldet + 1; $copy[$i] = $gemeldet + 1; break; // Did not started
// Startfehler
case 'OCS': $results[$key]['values'][$i] = $gemeldet + 1; $copy[$i] = $gemeldet + 1; /*$results[$key]['finished'] = true;*/ break; // On course site
// Muss v. Hand case 'ZFP': $results[$key]['values'][$i] = $gemeldet + 1; $copy[$i] = $gemeldet + 1; $results[$key]['finished'] = true; break; // Z-Flag penalty (20% nach 30.2)
case 'UFD': $results[$key]['values'][$i] = $gemeldet + 1; $copy[$i] = $gemeldet + 1; /*$results[$key]['finished'] = true;*/ break; // Uniform Flag Disqualified (disqu. nach 30.3)
case 'BFD': $results[$key]['values'][$i] = $gemeldet + 1; $copy[$i] = $gemeldet + 1; /*$results[$key]['finished'] = true;*/ break; // Black Flag Disqualified (disqu. nach 30.4)
// Nicht durch Ziel gegangen
case 'DNF': $results[$key]['values'][$i] = $gemeldet + 1; $copy[$i] = $gemeldet + 1; break; // Did not finish
case 'RET': $results[$key]['values'][$i] = $gemeldet + 1; $copy[$i] = $gemeldet + 1; break; // Retired (Aufgegeben)
case 'RAF': $results[$key]['values'][$i] = $gemeldet + 1; $copy[$i] = $gemeldet + 1; /*$results[$key]['finished'] = true;*/ break; // Retired after finish
// Disqualifizierun
case 'DSQ': $results[$key]['values'][$i] = $gemeldet + 1; $copy[$i] = $gemeldet + 1; /*$results[$key]['finished'] = true;*/ break; // Disqualified
case 'DNE': $results[$key]['values'][$i] = $gemeldet + 1; $copy[$i] = -1; /*$results[$key]['finished'] = true;*/ break; // Disqualified, not excludable (disqu. kann nach 90.3(b) nicht gestrichen werden)
case 'DGM': $results[$key]['values'][$i] = $gemeldet + 1; $copy[$i] = -2; /*$results[$key]['finished'] = true;*/ break; // Disqualification Gross Missconduct (kann nach 69.1(b)(2) nicht gestr. werden, grobes Fehlverhalten)
// Wiedergutmachung
// Muss v. Hand case 'RDG': $results[$key]['values'][$i] = $gemeldet + 1; $copy[$i] = $gemeldet + 1; $results[$key]['finished'] = true; break; // Redress given (Wiedergutmachung gewährt)
// Strafen
// Muss v. Hand case 'SCP': $results[$key]['values'][$i] = $gemeldet + 1; $copy[$i] = $gemeldet + 1; $results[$key]['finished'] = true; break; // Wertungsstrafe nach 44.3(a) (20%)
// Muss v. Hand case 'DPI': $results[$key]['values'][$i] = $gemeldet + 1; $copy[$i] = $gemeldet + 1; $results[$key]['finished'] = true; break; // Punktstrafe nach Ermessen der Jury
// Unbekannt
default: $results[$key]['values'][$i] = 0; $copy[$i] = 0; break;
}
if ($results[$key]['values'][$i] != 0) {
$results[$key]['texts'][$i] = $value['race' . $i] . ' (' . $results[$key]['values'][$i] . ')';
} else {
$results[$key]['texts'][$i] = $value['race' . $i] . ' (Unknown - 0)';
}
}
}
$results[$key]['values_all'] = $results[$key]['values'];
for ($s = 0; $s < $regatta['streicher']; $s ++) {
$max = max($copy);
for ($i = 1; $i <= $regatta['races']; $i ++) {
if ($copy[$i] == $max) {
$copy[$i] = 0;
break;
}
}
}
$brutto = $netto = 0;
for ($i = 1; $i <= $regatta['races']; $i ++) {
$brutto += $results[$key]['values_all'][$i];
if ($copy[$i] == -1) { $results[$key]['values'][$i] = $gemeldet + 1; }
elseif ($copy[$i] == -2) { $results[$key]['values'][$i] = $gemeldet + 1; }
else { $results[$key]['values'][$i] = $copy[$i]; }
if ($results[$key]['values'][$i] == 0) {
$results[$key]['texts'][$i] = '[' . $results[$key]['texts'][$i] . ']';
}
$netto += $results[$key]['values'][$i];
}
$results[$key]['brutto'] = $brutto;
$results[$key]['netto'] = $netto;
if ($results[$key]['finished']) {
$sortarray[$key] = 0;
} else {
$sortarray[$key] = 1;
}
$sortarray[$key] /*.*/= sprintf("%08.2f", $netto);
$temp = $results[$key]['values'];
sort($temp);
$i = 0;
foreach ($temp as $val) {
if ($i < $regatta['races']) {
$sortarray[$key] .= sprintf("%07.2f", $val);
}
$i ++;
}
for ($i = $regatta['races']; $i > 0; $i --) {
$sortarray[$key] .= sprintf("%07.2f", $results[$key]['values_all'][$i]);
}
$results[$key]['sortvalue'] = $sortarray[$key];
}
array_multisort($sortarray, $results);
$i = 1;
foreach ($results as $key => $value) {
if (($i > 1) and ($sortarray[$key] == $sortarray[$lastkey])) {
$results[$key]['place'] = $results[$lastkey]['place'];
} else {
$results[$key]['place'] = $i;
}
$i ++;
$lastkey = $key;
}
unset ($sortarray);
return $results;
} else {
return false;
}
}
function update_result_cache($mysqli, $regatta_id) {
$regatta = get_regatta($mysqli, $regatta_id);
if ($regatta === false) return;
$results = get_result_calculated($mysqli, $regatta['id']);
if ($results === false) return;
// count finished boats
$fb = 0;
foreach ($results as $result) {
if ($result['finished']) {
$fb ++;
}
}
db_update_data($mysqli, BOATCLASS . DB_TABLE_SUFFIX_REGATTAS, ['finishedBoats' => $fb], '`id`="' . $regatta['id'] . '"', 1);
foreach ($results as $result) {
if ($fb == 0) {
$rlp = 0;
} else {
$rlp = 100 * $regatta['rlf'] * (($fb + 1 - $result['place']) / $fb);
}
db_update_data($mysqli, BOATCLASS . DB_TABLE_SUFFIX_RESULTS, ['place' => $result['place'], 'rlp' => $rlp], '`id`="' . $result['id'] . '"', 1);
}
}
function get_ranking($mysqli, $from, $to, $jugend = false, $jugstrict = false) {
global $rankNoResults, $_CLASSES;
$rankNoResults = array();
$sailors = get_sailor($mysqli);
$regattas = get_regattas_range($mysqli, $from, $to);
if (($sailors !== false) and ($regattas !== false)) {
foreach ($sailors as $key => $sailor) {
$sailors[$key]['regattas'] = array();
$sailors[$key]['tmp_rlp'] = array();
}
foreach ($regattas as $regatta) {
$date = strtotime($regatta['date']);
// regatta has to be min. 2 days to be ranking-regatta
if ($regatta['length'] < 2) {
continue;
}
$results = get_result($mysqli, $regatta['id']);
if ($results === false) {
continue;
}
if (count($results) <= 0) {
if (strtotime('+' . ($regatta['length']-1) . ' days', $date) <= time()) {
if (!$regatta['canceled']) {
$rankNoResults[] = $regatta;
}
}
continue;
}
// in one race there must be at least 10 boats started
$ok = false;
for ($i = 1; $i <= $regatta['races']; $i ++) {
$temp = 0;
foreach ($results as $result) {
if (($result['race' . $i] != 'DNC') and ($result['race' . $i] != 'DNS')) {
$temp ++;
}
}
if ($temp >= 10) {
$ok = true;
break;
}
}
if (!$ok) {
continue;
}
$fb = $regatta['finishedBoats'];
// add regatta to each sailor
foreach ($results as $result) {
if ($result['rlp'] == 0) {
continue;
}
// check if crew is youth
//if ($jugend) {
// $crew = explode(',', $result['crew']);
// $okay = true;
// foreach ($crew as $sailor) {
// if (($sailor == '') or !isset($sailors[$sailor])) continue;
// $sailor = $sailors[$sailor];
// if ((($sailor['year'] !== null) and ($sailor['year'] < (date('Y', $date) - $_CLASSES[BOATCLASS]['youth-age']))) or
// (($sailor['year'] === null) and ($jugstrict))) {
// $okay = false;
// break;
// }
// }
// if (!$okay) continue;
//}
// calc m
if ($regatta['m'] > 0) {
$m = $regatta['m'];
} elseif ($regatta['races'] <= 4) {
$m = $regatta['races'];
} else {
if (($regatta['length'] > 2) and ($regatta['races'] >= 6)) {
$m = 5;
} else {
$m = 4;
}
}
$rlp = $result['rlp'];
$sailors[$result['steuermann']]['regattas'][$regatta['id']] = array(
'regatta' => $regatta['id'],
'boat' => $result['boat'],
'crew' => $result['crew'],
'place' => $result['place'],
'fb' => $fb,
'rlp' => $rlp,
'used' => 0,
'm' => $m
);
for ($i = 0; $i < $m; $i ++) {
array_push($sailors[$result['steuermann']]['tmp_rlp'], array($regatta['id'], $rlp));
}
}
}
foreach ($sailors as $key => $sailor) {
if ($sailor['german'] == 0) {
unset($sailors[$key]);
} elseif ($jugend) {
if ((($sailor['year'] !== null) and ($sailor['year'] < (date('Y', $to) - $_CLASSES[BOATCLASS]['youth-age']))) or
(($sailor['year'] === null) and ($jugstrict))) {
unset($sailors[$key]);
}
}
}
$sortarray = array();
foreach ($sailors as $key => $sailor) {
// sort rlps desc
$sort = array();
foreach ($sailor['tmp_rlp'] as $key2 => $value) {
$sort[$key2] = $value[1];
}
array_multisort($sort, SORT_DESC, $sailors[$key]['tmp_rlp']);
// calc mean. rlp
$sum = 0;
$cnt = 0;
foreach ($sailors[$key]['tmp_rlp'] as $value) {
$sum += $value[1];
$sailors[$key]['regattas'][$value[0]]['used'] ++;
$cnt ++;
if ($cnt >= 9) {
break;
}
}
unset($sailors[$key]['tmp_rlp']);
if ($cnt > 0) {
$rlp = $sum / $cnt;
$sailors[$key]['rlp'] = $rlp;
$sailors[$key]['m'] = $cnt;
} else {
unset($sailors[$key]);
continue;
}
if ($rlp == 0) {
$sortarray[$key] = $cnt;
} else {
$sortarray[$key] = $cnt * 1000 + $rlp;
}
}
array_multisort($sortarray, SORT_DESC, $sailors);
unset($sortarray);
$i = 1;
foreach ($sailors as $key => $sailor) {
$sailors[$key]['rank'] = $i;
$i ++;
}
return $sailors;
} else {
return false;
}
}
function get_trim_boat($mysqli, $id = false) {
return get_db_entry($mysqli, DB_TABLE_TRIM_BOATS, $id);
}
function get_trim_boat_users($mysqli, $id) {
$result = db_get_data($mysqli, DB_TABLE_TRIM_USERS, '*', '`boat` = "' . mysqli_real_escape_string($mysqli, $id) . '"');
if ($result === false)
return false;
else
return $result;
}
function get_trim_user_boats($mysqli, $id) {
$boats = db_get_data($mysqli, DB_TABLE_TRIM_USERS, '*', '`user` = "' . mysqli_real_escape_string($mysqli, $id) . '"');
if ($boats === false) {
return false;
} else {
$result = [];
foreach ($boats as $value) {
$result[$value['boat']] = get_trim_boat($mysqli, $value['boat']);
}
return $result;
}
}
function trim_is_boat_user($mysqli, $user, $boat) {
$res = db_get_data($mysqli, DB_TABLE_TRIM_USERS, '*', '`user` = "' . mysqli_real_escape_string($mysqli, $user) . '" AND `boat` = "' . mysqli_real_escape_string($mysqli, $boat) . '"');
return ($res !== false) and (count($res) == 1);
}
function get_trim_trim($mysqli, $id = false) {
return get_db_entry($mysqli, DB_TABLE_TRIM_TRIMS, $id);
}
function get_trim_boat_trims($mysqli, $id) {
$result = db_get_data($mysqli, DB_TABLE_TRIM_TRIMS, '*', '`boat` = "' . mysqli_real_escape_string($mysqli, $id) . '"');
if ($result === false) {
return false;
} else {
return $result;
}
}
?>

View File

@@ -5,6 +5,7 @@
require_once(__DIR__ . '/../server/log.php'); require_once(__DIR__ . '/../server/log.php');
require_once(__DIR__ . '/database.php'); require_once(__DIR__ . '/database.php');
require_once(__DIR__ . '/login.php'); require_once(__DIR__ . '/login.php');
require_once(__DIR__ . '/functions.php');
$request = false; $request = false;
if (isset($_GET['request'])) { if (isset($_GET['request'])) {
@@ -76,15 +77,14 @@
} else { } else {
$user_id = false; $user_id = false;
} }
$perm = get_perm($mysqli, $user_id);
function has_perm($permission) { function isLoggedIn() {
global $perm; global $user_id;
return ($perm & $permission) == $permission; return $user_id !== false;
} }
function checkPermission($perm) { function checkLoggedIn() {
if (!has_perm($perm)) done(DONE_UNAUTHORIZED, ['error' => 'permission denied']); if (!isLoggedIn()) done(DONE_UNAUTHORIZED, ['error' => 'permission denied']);
} }
function checkRequest($param) { function checkRequest($param) {
@@ -98,6 +98,35 @@
}, $array); }, $array);
} }
$whereString = false;
if (isset($_REQUEST['index'], $_REQUEST['value'])) {
$whereString = '`' . mysqli_real_escape_string($mysqli, $_REQUEST['index']) . '`="' . mysqli_real_escape_string($mysqli, $_REQUEST['value']) . '"';
}
function sendEntries($table) {
global $mysqli, $whereString;
$response = db_get_data($mysqli, $table, '*', $whereString);
if ($response === false) done(DONE_DATABASE);
$keys = array_keys($response);
if (isset($_REQUEST['changed-after'])) {
$response = db_get_data($mysqli, $table, '*', '`changed` > "' . mysqli_real_escape_string($mysqli, date('Y-m-d H:i:s', $_REQUEST['changed-after'])) . '"' . ($whereString ? (' AND ' . $whereString) : ''));
if ($response === false) done(DONE_DATABASE);
}
$response = array_values($response);
done(DONE_OKAY, array('data' => replaceChanged($response), 'keys' => $keys));
}
function sendEntry($table) {
global $mysqli;
checkRequest('id');
$response = db_get_data($mysqli, $table, '*', '`id` = "' . mysqli_real_escape_string($mysqli, $_REQUEST['id']) . '"');
if ($response === false) done(DONE_DATABASE);
if (count($response) != 1) done(DONE_BAD_REQUEST, ['error' => 'id not found']);
$response = array_values($response)[0];
unset($response['changed']);
done(DONE_OKAY, ['data' => $response]);
}
switch ($action) { switch ($action) {
case 'login': case 'login':
@@ -110,11 +139,325 @@
break; break;
case 'logout': case 'logout':
checkPermission(PERM_REGISTERED); checkLoggedIn();
auth_logout($mysqli, $_REQUEST['auth']['id']); auth_logout($mysqli, $_REQUEST['auth']['id']);
done(DONE_OKAY); done(DONE_OKAY);
break; break;
case 'get_update_time':
$times = array();
$response = db_get_data($mysqli, DB_TABLE_UPDATETIMES, '`update`', '`table` = "' . DB_TABLE_CLUBS . '"', 1);
if (($response !== false) and (count($response) > 0)) {
$times['clubs'] = strtotime(array_values($response)[0]['update']);
} else {
done(DONE_DATABASE);
}
$response = db_get_data($mysqli, DB_TABLE_UPDATETIMES, '`update`', '`table` = "' . BOATCLASS . DB_TABLE_SUFFIX_BOATS . '"', 1);
if (($response !== false) and (count($response) > 0)) {
$times['boats'] = strtotime(array_values($response)[0]['update']);
} else {
done(DONE_DATABASE);
}
$response = db_get_data($mysqli, DB_TABLE_UPDATETIMES, '`update`', '`table` = "' . BOATCLASS . DB_TABLE_SUFFIX_SAILORS . '"', 1);
if (($response !== false) and (count($response) > 0)) {
$times['sailors'] = strtotime(array_values($response)[0]['update']);
} else {
done(DONE_DATABASE);
}
$response = db_get_data($mysqli, DB_TABLE_UPDATETIMES, '`update`', '`table` = "' . BOATCLASS . DB_TABLE_SUFFIX_REGATTAS . '"', 1);
if (($response !== false) and (count($response) > 0)) {
$times['regattas'] = strtotime(array_values($response)[0]['update']);
} else {
done(DONE_DATABASE);
}
$response = db_get_data($mysqli, DB_TABLE_UPDATETIMES, '`update`', '`table` = "' . BOATCLASS . DB_TABLE_SUFFIX_RESULTS . '"', 1);
if (($response !== false) and (count($response) > 0)) {
$times['results'] = strtotime(array_values($response)[0]['update']);
} else {
done(DONE_DATABASE);
}
$response = db_get_data($mysqli, DB_TABLE_UPDATETIMES, '`update`', '`table` = "' . BOATCLASS . DB_TABLE_SUFFIX_PLANNING . '"', 1);
if (($response !== false) and (count($response) > 0)) {
$times['plannings'] = strtotime(array_values($response)[0]['update']);
} else {
done(DONE_DATABASE);
}
$response = db_get_data($mysqli, DB_TABLE_UPDATETIMES, '`update`', '`table` = "' . DB_TABLE_TRIM_BOATS . '"', 1);
if (($response !== false) and (count($response) > 0)) {
$times['trim_boats'] = strtotime(array_values($response)[0]['update']);
} else {
done(DONE_DATABASE);
}
$response = db_get_data($mysqli, DB_TABLE_UPDATETIMES, '`update`', '`table` = "' . DB_TABLE_TRIM_USERS . '"', 1);
if (($response !== false) and (count($response) > 0)) {
$times['trim_users'] = strtotime(array_values($response)[0]['update']);
} else {
done(DONE_DATABASE);
}
$response = db_get_data($mysqli, DB_TABLE_UPDATETIMES, '`update`', '`table` = "' . DB_TABLE_TRIM_TRIMS . '"', 1);
if (($response !== false) and (count($response) > 0)) {
$times['trim_trims'] = strtotime(array_values($response)[0]['update']);
} else {
done(DONE_DATABASE);
}
$response = db_get_data($mysqli, DB_TABLE_UPDATETIMES, '`update`', '`table` = "' . DB_TABLE_USERS . '"', 1);
if (($response !== false) and (count($response) > 0)) {
$times['users'] = strtotime(array_values($response)[0]['update']);
} else {
done(DONE_DATABASE);
}
done(DONE_OKAY, $times);
break;
case 'get_clubs':
sendEntries(DB_TABLE_CLUBS);
break;
case 'get_club':
sendEntry(DB_TABLE_CLUBS);
break;
case 'get_boats':
sendEntries(BOATCLASS . DB_TABLE_SUFFIX_BOATS);
break;
case 'get_boat':
sendEntry(BOATCLASS . DB_TABLE_SUFFIX_BOATS);
break;
case 'get_sailors':
sendEntries(BOATCLASS . DB_TABLE_SUFFIX_SAILORS);
break;
case 'get_sailor':
sendEntry(BOATCLASS . DB_TABLE_SUFFIX_SAILORS);
break;
case 'get_years':
$response = get_regatta_years($mysqli);
if ($response === false) done(DONE_DATABASE);
foreach ($response as $key => $value)
$response[$key] = ['year' => $value];
done(DONE_OKAY, ['data' => $response]);
break;
case 'get_regattas':
sendEntries(BOATCLASS . DB_TABLE_SUFFIX_REGATTAS);
break;
case 'get_regatta':
sendEntry(BOATCLASS . DB_TABLE_SUFFIX_REGATTAS);
break;
case 'get_results':
sendEntries(BOATCLASS . DB_TABLE_SUFFIX_RESULTS);
break;
case 'get_result':
sendEntry(BOATCLASS . DB_TABLE_SUFFIX_RESULTS);
break;
case 'get_plannings':
$response = db_get_data($mysqli, BOATCLASS . DB_TABLE_SUFFIX_PLANNING, '*', $whereString);
if ($response === false) done(DONE_DATABASE);
$keys = array_keys($response);
if (isset($_REQUEST['changed-after'])) {
$response = db_get_data($mysqli, BOATCLASS . DB_TABLE_SUFFIX_PLANNING, '*', '`changed` > "' . mysqli_real_escape_string($mysqli, date('Y-m-d H:i:s', $_REQUEST['changed-after'])) . '"' . ($whereString ? (' AND ' . $whereString) : ''));
if ($response === false) done(DONE_DATABASE);
}
$response = array_map(function ($entry) {
global $user_id;
if (($user_id === false) or ($entry['user'] != $user_id)) {
unset($entry['gemeldet'], $entry['bezahlt']);
}
return $entry;
}, $response);
$response = array_values($response);
done(DONE_OKAY, array('data' => replaceChanged($response), 'keys' => $keys));
break;
case 'get_planning':
checkRequest('id');
$response = db_get_data($mysqli, BOATCLASS . DB_TABLE_SUFFIX_PLANNING, '*', '`id` = "' . mysqli_real_escape_string($mysqli, $_REQUEST['id']) . '"');
if ($response === false) done(DONE_DATABASE);
if (count($response) != 1) done(DONE_BAD_REQUEST, ['error' => 'id not found']);
$response = array_values($response)[0];
if (($user_id === false) or ($response['user'] != $user_id)) {
unset($response['gemeldet'], $response['bezahlt']);
}
unset($response['changed']);
done(DONE_OKAY, ['data' => $response]);
break;
case 'get_trim_boats':
checkLoggedIn();
$users = db_get_data($mysqli, DB_TABLE_TRIM_USERS, 'boat', '`user`="' . $user_id . '"');
$boats = implode(',', array_column($users, 'boat'));
if ($boats == '') {
done(DONE_OKAY, array('data' => [], 'keys' => []));
}
$response = db_get_data($mysqli, DB_TABLE_TRIM_BOATS, '*', '`id` IN (' . $boats . ')' . ($whereString ? (' AND ' . $whereString) : ''));
if ($response === false) done(DONE_DATABASE);
$keys = array_keys($response);
if (isset($_REQUEST['changed-after'])) {
$response = db_get_data($mysqli, DB_TABLE_TRIM_BOATS, '*', '`id` IN (' . $boats . ') AND `changed` > "' . mysqli_real_escape_string($mysqli, date('Y-m-d H:i:s', $_REQUEST['changed-after'])) . '"' . ($whereString ? (' AND ' . $whereString) : ''));
if ($response === false) done(DONE_DATABASE);
}
$response = array_values($response);
done(DONE_OKAY, array('data' => replaceChanged($response), 'keys' => $keys));
break;
case 'get_trim_boat':
checkLoggedIn();
checkRequest('id');
$response = db_get_data($mysqli, DB_TABLE_TRIM_BOATS, '*', '`id` = "' . mysqli_real_escape_string($mysqli, $_REQUEST['id']) . '"');
if ($response === false) done(DONE_DATABASE);
if (count($response) != 1) done(DONE_BAD_REQUEST, ['error' => 'id not found']);
$response = array_values($response)[0];
if (count(db_get_data($mysqli, DB_TABLE_TRIM_USERS, 'id', '`user`="' . $user_id . '" AND `boat`="' . $response['id'] . '"')) != 1)
done(DONE_BAD_REQUEST, ['error' => 'id not found']);
unset($response['changed']);
done(DONE_OKAY, ['data' => $response]);
break;
case 'get_trim_users':
checkLoggedIn();
$users = db_get_data($mysqli, DB_TABLE_TRIM_USERS, 'boat', '`user`="' . $user_id . '"');
$boats = implode(',', array_column($users, 'boat'));
if ($boats == '') {
done(DONE_OKAY, array('data' => [], 'keys' => []));
}
$response = db_get_data($mysqli, DB_TABLE_TRIM_USERS, '*', '`boat` IN (' . $boats . ')' . ($whereString ? (' AND ' . $whereString) : ''));
if ($response === false) done(DONE_DATABASE);
$keys = array_keys($response);
if (isset($_REQUEST['changed-after'])) {
$response = db_get_data($mysqli, DB_TABLE_TRIM_USERS, '*', '`boat` IN (' . $boats . ') AND `changed` > "' . mysqli_real_escape_string($mysqli, date('Y-m-d H:i:s', $_REQUEST['changed-after'])) . '"' . ($whereString ? (' AND ' . $whereString) : ''));
if ($response === false) done(DONE_DATABASE);
}
$response = array_values($response);
done(DONE_OKAY, array('data' => replaceChanged($response), 'keys' => $keys));
break;
case 'get_trim_user':
checkLoggedIn();
checkRequest('id');
$response = db_get_data($mysqli, DB_TABLE_TRIM_USERS, '*', '`id` = "' . mysqli_real_escape_string($mysqli, $_REQUEST['id']) . '"');
if ($response === false) done(DONE_DATABASE);
if (count($response) != 1) done(DONE_BAD_REQUEST, ['error' => 'id not found']);
$response = array_values($response)[0];
if (count(db_get_data($mysqli, DB_TABLE_TRIM_USERS, 'id', '`user`="' . $user_id . '" AND `boat`="' . $response['boat'] . '"')) != 1)
done(DONE_BAD_REQUEST, ['error' => 'id not found']);
unset($response['changed']);
done(DONE_OKAY, ['data' => $response]);
break;
case 'get_trim_trims':
checkLoggedIn();
$users = db_get_data($mysqli, DB_TABLE_TRIM_USERS, 'boat', '`user`="' . $user_id . '"');
$boats = implode(',', array_column($users, 'boat'));
if ($boats == '') {
done(DONE_OKAY, array('data' => [], 'keys' => []));
}
$response = db_get_data($mysqli, DB_TABLE_TRIM_TRIMS, '*', '`boat` IN (' . $boats . ')' . ($whereString ? (' AND ' . $whereString) : ''));
if ($response === false) done(DONE_DATABASE);
$keys = array_keys($response);
if (isset($_REQUEST['changed-after'])) {
$response = db_get_data($mysqli, DB_TABLE_TRIM_TRIMS, '*', '`boat` IN (' . $boats . ') AND `changed` > "' . mysqli_real_escape_string($mysqli, date('Y-m-d H:i:s', $_REQUEST['changed-after'])) . '"' . ($whereString ? (' AND ' . $whereString) : ''));
if ($response === false) done(DONE_DATABASE);
}
$response = array_values($response);
done(DONE_OKAY, array('data' => replaceChanged($response), 'keys' => $keys));
break;
case 'get_trim_trim':
checkLoggedIn();
checkRequest('id');
$response = db_get_data($mysqli, DB_TABLE_TRIM_TRIMS, '*', '`id` = "' . mysqli_real_escape_string($mysqli, $_REQUEST['id']) . '"');
if ($response === false) done(DONE_DATABASE);
if (count($response) != 1) done(DONE_BAD_REQUEST, ['error' => 'id not found']);
$response = array_values($response)[0];
if (count(db_get_data($mysqli, DB_TABLE_TRIM_USERS, 'id', '`user`="' . $user_id . '" AND `boat`="' . $response['boat'] . '"')) != 1)
done(DONE_BAD_REQUEST, ['error' => 'id not found']);
unset($response['changed']);
done(DONE_OKAY, ['data' => $response]);
break;
case 'get_users':
$followFields = '';
for ($i = 1; $i <= 5; $i ++) $followFields .= ',' . BOATCLASS . '_sailor' . $i . ' AS sailor' . $i;
$response = db_get_data($mysqli, DB_TABLE_USERS, 'id,username,email' . $followFields, $whereString);
if ($response === false) done(DONE_DATABASE);
$keys = array_keys($response);
if (isset($_REQUEST['changed-after'])) {
$response = db_get_data($mysqli, DB_TABLE_USERS, 'id,username,email,' . $followFields, '`changed` > "' . mysqli_real_escape_string($mysqli, date('Y-m-d H:i:s', $_REQUEST['changed-after'])) . '"' . ($whereString ? (' AND ' . $whereString) : ''));
if ($response === false) done(DONE_DATABASE);
}
$response = array_map(function ($entry) {
global $user_id;
if ($entry['id'] != $user_id) {
$entry = ['id' => $entry['id'], 'username' => $entry['username']];
}
return $entry;
}, $response);
$response = array_values($response);
done(DONE_OKAY, array('data' => replaceChanged($response), 'keys' => $keys));
break;
case 'get_user':
checkRequest('id');
$followFields = '';
for ($i = 1; $i <= 5; $i ++) $followFields .= ',' . BOATCLASS . '_sailor' . $i . ' AS sailor' . $i;
$response = db_get_data($mysqli, DB_TABLE_USERS, 'id,username,email' . $followFields, '`id` = "' . mysqli_real_escape_string($mysqli, $_REQUEST['id']) . '"');
if ($response === false) done(DONE_DATABASE);
if (count($response) != 1) done(DONE_BAD_REQUEST, ['error' => 'id not found']);
$response = array_values($response)[0];
if ($response['id'] != $user_id) {
$response = ['id' => $response['id'], 'username' => $response['username']];
}
unset($response['changed']);
done(DONE_OKAY, ['data' => $response]);
break;
case 'add_subscription':
checkRequest('subscription');
$data = [
'auth' => PUSH_AUTH,
'subscription' => $_REQUEST['subscription']
];
$ch = curl_init('https://push.ostertun.net/add_subscription');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$result = curl_exec($ch);
curl_close($ch);
if ($result == "OK")
done(DONE_OKAY);
else {
logE('add_subscription', $result);
done(DONE_SERVER_ERROR);
}
break;
case 'remove_subscription':
checkRequest('subscription');
$data = [
'auth' => PUSH_AUTH,
'subscription' => $_REQUEST['subscription']
];
$ch = curl_init('https://push.ostertun.net/remove_subscription');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$result = curl_exec($ch);
curl_close($ch);
if ($result == "OK")
done(DONE_OKAY);
else {
logE('remove_subscription', $result);
done(DONE_SERVER_ERROR);
}
break;
default: default:
done(DONE_BAD_REQUEST, ['error' => 'action invalid']); done(DONE_BAD_REQUEST, ['error' => 'action invalid']);

799
client/scripts/database.js Normal file
View File

@@ -0,0 +1,799 @@
const DB_VERSION = 3;
const USER_ID = localStorage.getItem('auth_user');
const USER_NAME = localStorage.getItem('auth_username');
var canUseLocalDB = false;
var syncTimer = null;
var updateSyncStatusTimer;
var syncInProgress = 0;
var db;
var user = null;
var getJSON = function(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.responseType = 'json';
xhr.timeout = 60000;
xhr.onload = function() {
callback(xhr.status, xhr.response);
};
xhr.ontimeout = function () {
console.log("getJSON: timeout");
callback(0, null);
}
xhr.onerror = function () {
console.log("getJSON: error");
callback(0, null);
}
if (USER_ID != null) {
authString = 'auth[id]=' + localStorage.getItem('auth_id');
authString += '&auth[hash]=' + encodeURIComponent(localStorage.getItem('auth_hash'));
xhr.send(authString);
} else {
xhr.send();
}
};
function isLoggedIn() {
return USER_ID !== null;
}
function search(string, fields) {
var keywords = string.split(' ');
for (kid in keywords) {
var keyword = keywords[kid].toLowerCase();
var found = false;
for (fid in fields) {
var field = fields[fid].toLowerCase();
if (field.indexOf(keyword) >= 0) {
found = true;
break;
}
}
if (!found) return false;
}
return true;
}
function dbGetData(table, id = null) {
return new Promise(function(resolve) {
if (canUseLocalDB) {
if (id == null) {
db.transaction(table).objectStore(table).getAll().onsuccess = function (event) {
resolve(event.target.result);
};
} else {
var request = db.transaction(table).objectStore(table).get(id.toString());
request.onsuccess = function (event) {
resolve(typeof request.result != 'undefined' ? request.result : null);
}
}
} else {
if (id == null) {
getJSON(QUERY_URL + 'get_' + table, function (code, data) {
if (code == 200) {
resolve(data.data);
} else {
console.log("Something went wrong (HTTP " + code + ")");
fail(strings.error_network, 5000);
resolve([]);
}
});
} else {
getJSON(QUERY_URL + 'get_' + table.substr(0, table.length - 1) + '?id=' + id, function (code, data) {
if (code == 200) {
resolve(data.data);
} else {
console.log("Something went wrong (HTTP " + code + ")");
fail(strings.error_network, 5000);
resolve(null);
}
});
}
}
});
}
function dbGetDataIndex(table, indexName, value) {
return new Promise(function(resolve) {
if (canUseLocalDB) {
var request = db.transaction(table).objectStore(table).index(indexName).getAll(IDBKeyRange.only(value.toString()));
request.onsuccess = function (event) {
resolve(request.result);
}
} else {
getJSON(QUERY_URL + 'get_' + table + '?index=' + indexName + '&value=' + value, function (code, data) {
if (code == 200) {
resolve(data.data);
} else {
console.log("Something went wrong (HTTP " + code + ")");
fail(strings.error_network, 5000);
resolve([]);
}
});
}
});
}
function dbGetRegattasRange(minDate, maxDate) {
return new Promise(async function(resolve) {
var regattas = await dbGetData('regattas');
var result = [];
for (id in regattas) {
var regatta = regattas[id];
var dateFrom = parseDate(regatta['date']);
var dateTo = parseDate(regatta['date']);
dateTo.setDate(dateTo.getDate() + parseInt(regatta['length']) - 1);
if ((minDate <= dateTo) && (maxDate >= dateFrom)) {
regatta['dateFrom'] = dateFrom;
regatta['dateTo'] = dateTo;
result.push(regatta);
}
}
result.sort(function (a, b) {
if (a['date'] < b['date']) return -1;
if (a['date'] > b['date']) return 1;
return 0;
});
resolve(result);
});
}
var compareResultsRaceCount;
function compareResults (a, b) {
if (a['netto'] != b['netto']) return (a['netto'] < b['netto']) ? -1 : 1;
var tempA = [...a['values']];
tempA.sort();
var tempB = [...b['values']];
tempB.sort();
for (var i = 0; i < compareResultsRaceCount; i ++) {
if (tempA[i] != tempB[i]) return (tempA[i] < tempB[i]) ? -1 : 1;
}
for (var i = compareResultsRaceCount - 1; i >= 0; i --) {
if (a['values_all'][i] != b['values_all'][i]) return (a['values_all'][i] < b['values_all'][i]) ? -1 : 1;
}
return 0;
}
function dbGetResultCalculated(regatta) {
return new Promise(async function(resolve) {
var results = await dbGetDataIndex('results', 'regatta', regatta.id);
if (results.length > 0) {
var gemeldet = results.length;
for (id in results) {
results[id]['finished'] = false;
results[id]['values'] = [];
results[id]['values_all'] = [];
results[id]['texts'] = [];
var copy = [];
for (var i = 0; i < regatta['races']; i ++) {
var race = results[id]['race' + (i + 1)].replace(',', '.');
if (!isNaN(race)) {
copy[i] = results[id]['values'][i] = parseFloat(race);
results[id]['texts'][i] = race;
results[id]['finished'] = true;
} else {
switch (race.toUpperCase()) {
// Nicht gestartet
case 'DNC': results[id]['values'][i] = gemeldet + 1; copy[i] = gemeldet + 1; break; // Did not come
case 'DNS': results[id]['values'][i] = gemeldet + 1; copy[i] = gemeldet + 1; break; // Did not started
// Startfehler
case 'OCS': results[id]['values'][i] = gemeldet + 1; copy[i] = gemeldet + 1; break; // On course site
case 'UFD': results[id]['values'][i] = gemeldet + 1; copy[i] = gemeldet + 1; break; // Uniform Flag Disqualified (disqu. nach 30.3)
case 'BFD': results[id]['values'][i] = gemeldet + 1; copy[i] = gemeldet + 1; break; // Black Flag Disqualified (disqu. nach 30.4)
// Nicht durch Ziel gegangen
case 'DNF': results[id]['values'][i] = gemeldet + 1; copy[i] = gemeldet + 1; break; // Did not finish
case 'RET': results[id]['values'][i] = gemeldet + 1; copy[i] = gemeldet + 1; break; // Retired (Aufgegeben)
case 'RAF': results[id]['values'][i] = gemeldet + 1; copy[i] = gemeldet + 1; break; // Retired after finish
// Disqualifizierun
case 'DSQ': results[id]['values'][i] = gemeldet + 1; copy[i] = gemeldet + 1; break; // Disqualified
case 'DNE': results[id]['values'][i] = gemeldet + 1; copy[i] = -1; break; // Disqualified, not excludable (disqu. kann nach 90.3(b) nicht gestrichen werden)
case 'DGM': results[id]['values'][i] = gemeldet + 1; copy[i] = -2; break; // Disqualification Gross Missconduct (kann nach 69.1(b)(2) nicht gestr. werden, grobes Fehlverhalten)
// Unbekannt
default: results[id]['values'][i] = 0; copy[i] = 0; break;
}
if (results[id]['values'][i] != 0) {
results[id]['texts'][i] = race + ' (' + results[id]['values'][i] + ')';
} else {
results[id]['texts'][i] = race + ' (Unknown - 0)';
}
}
}
results[id]['values_all'] = [...results[id]['values']];
for (var s = 0; s < regatta['streicher']; s ++) {
var max = Math.max(...copy);
for (var i = 0; i < regatta['races']; i ++) {
if (copy[i] == max) {
copy[i] = 0;
break;
}
}
}
var brutto = 0;
var netto = 0;
for (var i = 0; i < regatta['races']; i ++) {
brutto += results[id]['values_all'][i];
if (copy[i] == -1) { results[id]['values'][i] = gemeldet + 1; }
else if (copy[i] == -2) { results[id]['values'][i] = gemeldet + 1; }
else { results[id]['values'][i] = copy[i]; }
if (results[id]['values'][i] == 0) {
results[id]['texts'][i] = '[' + results[id]['texts'][i] + ']';
}
netto += results[id]['values'][i];
}
results[id]['brutto'] = brutto;
results[id]['netto'] = netto;
}
compareResultsRaceCount = regatta['races'];
results.sort(compareResults);
var place = 1;
for (id in results) {
if ((id > 0) && (compareResults(results[id], results[id - 1]) == 0)) {
results[id]['place'] = results[id - 1]['place'];
} else {
results[id]['place'] = place;
}
place ++;
}
resolve(results);
} else {
resolve([]);
}
});
}
async function updateSyncStatus() { // TODO
// var syncStatus = document.getElementById('syncstatus');
// var lastSync = await dbGetData('update_times', 'last_sync');
// lastSync = new Date(lastSync.time * 1000);
// var now = new Date();
// var diff = Math.round((now - lastSync) / 1000);
// var txt = '';
//
// if (diff < 30) { // 30 sec
// txt = 'jetzt';
// } else if (diff < 3600) { // 60 min
// diff = Math.round(diff / 60);
// txt = 'vor ' + diff + ' ' + (diff == 1 ? 'Minute' : 'Minuten');
// } else if (diff < 86400) { // 24 std
// diff = Math.round(diff / 3600);
// txt = 'vor ' + diff + ' ' + (diff == 1 ? 'Stunde' : 'Stunden');
// } else {
// diff = Math.round(diff / 86400);
// txt = 'vor ' + diff + ' ' + (diff == 1 ? 'Tag' : 'Tagen');
// }
//
// var btn = '<a href="#" onclick="setLoading(true); sync(); return false;"><i class="fas fa-sync"></i> Sync</a>';
// syncStatus.innerHTML = 'Zuletzt aktualisiert: ' + txt + btn;
}
async function runPageScript() {
if (canUseLocalDB) {
updateSyncStatus();
}
if (typeof updateSyncStatusTimer == 'undefined') { // TODO
// var syncStatus = document.getElementById('syncstatus');
if (canUseLocalDB) {
updateSyncStatusTimer = window.setInterval(updateSyncStatus, 10000);
} else {
// syncStatus.innerHTML = 'Keine Offline-Nutzung möglich.';
updateSyncStatusTimer = null;
}
// syncStatus.style.display = 'block';
}
if (typeof siteScript === 'function') {
siteScript();
}
hideLoader();
}
function sync() {
if (!canUseLocalDB) return false;
if (syncInProgress > 0) return false;
var now = Math.floor(Date.now() / 1000);
db.transaction('update_times').objectStore('update_times').getAll().onsuccess = function (event) {
var localTimes = {};
event.target.result.forEach(function (entry) {
localTimes[entry['table']] = entry['time'];
});
syncInProgress = 10;
var syncOkay = true;
console.log("Sync Start");
var interval = window.setInterval(function () {
if (syncInProgress <= 0) {
window.clearInterval(interval);
if (syncOkay) {
var osUpdateTimes = db.transaction('update_times', 'readwrite').objectStore('update_times');
osUpdateTimes.put({ table: 'last_sync', time: now });
}
console.log("Sync Stop");
runPageScript();
}
}, 100);
getJSON(QUERY_URL + 'get_update_time', function (code, serverTimes) {
if (code == 200) {
// CLUBS
if (localTimes['clubs'] < serverTimes['clubs']) {
getJSON(QUERY_URL + 'get_clubs?changer-after=' + localTimes['clubs'], function (code, data) {
if (code == 200) {
var os = db.transaction('clubs', 'readwrite').objectStore('clubs');
console.log(data);
data.data.forEach(function (entry) {
os.put(entry);
});
os.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
if (!data.keys.includes(parseInt(cursor.key))) {
os.delete(cursor.key);
}
cursor.continue();
} else {
var osUpdateTimes = db.transaction('update_times', 'readwrite').objectStore('update_times');
osUpdateTimes.put({ table: 'clubs', time: serverTimes['clubs'] });
syncInProgress --;
}
};
} else {
console.log("Something went wrong (HTTP " + code + ")");
syncOkay = false;
syncInProgress --;
}
});
} else {
syncInProgress --;
}
// BOATS
if (localTimes['boats'] < serverTimes['boats']) {
getJSON(QUERY_URL + 'get_boats?changer-after=' + localTimes['boats'], function (code, data) {
if (code == 200) {
var os = db.transaction('boats', 'readwrite').objectStore('boats');
console.log(data);
data.data.forEach(function (entry) {
os.put(entry);
});
os.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
if (!data.keys.includes(parseInt(cursor.key))) {
os.delete(cursor.key);
}
cursor.continue();
} else {
var osUpdateTimes = db.transaction('update_times', 'readwrite').objectStore('update_times');
osUpdateTimes.put({ table: 'boats', time: serverTimes['boats'] });
syncInProgress --;
}
};
} else {
console.log("Something went wrong (HTTP " + code + ")");
syncOkay = false;
syncInProgress --;
}
});
} else {
syncInProgress --;
}
// SAILORS
if (localTimes['sailors'] < serverTimes['sailors']) {
getJSON(QUERY_URL + 'get_sailors?changer-after=' + localTimes['sailors'], function (code, data) {
if (code == 200) {
var os = db.transaction('sailors', 'readwrite').objectStore('sailors');
console.log(data);
data.data.forEach(function (entry) {
os.put(entry);
});
os.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
if (!data.keys.includes(parseInt(cursor.key))) {
os.delete(cursor.key);
}
cursor.continue();
} else {
var osUpdateTimes = db.transaction('update_times', 'readwrite').objectStore('update_times');
osUpdateTimes.put({ table: 'sailors', time: serverTimes['sailors'] });
syncInProgress --;
}
};
} else {
console.log("Something went wrong (HTTP " + code + ")");
syncOkay = false;
syncInProgress --;
}
});
} else {
syncInProgress --;
}
// REGATTAS
if (localTimes['regattas'] < serverTimes['regattas']) {
getJSON(QUERY_URL + 'get_regattas?changer-after=' + localTimes['regattas'], function (code, data) {
if (code == 200) {
var os = db.transaction('regattas', 'readwrite').objectStore('regattas');
console.log(data);
data.data.forEach(function (entry) {
os.put(entry);
});
os.openCursor().onsuccess = async function (event) {
var cursor = event.target.result;
if (cursor) {
if (!data.keys.includes(parseInt(cursor.key))) {
os.delete(cursor.key);
}
cursor.continue();
} else {
// update years
var regattas = await dbGetData('regattas');
var years = {};
for (id in regattas) {
var entry = regattas[id];
var date = parseDate(entry['date']);
var y = date.getFullYear();
years[y] = y;
}
var osYears = db.transaction('years', 'readwrite').objectStore('years');
osYears.clear().onsuccess = function (event) {
for (var y in years) {
osYears.put({ year: y });
}
}
var osUpdateTimes = db.transaction('update_times', 'readwrite').objectStore('update_times');
osUpdateTimes.put({ table: 'regattas', time: serverTimes['regattas'] });
syncInProgress --;
}
};
} else {
console.log("Something went wrong (HTTP " + code + ")");
syncOkay = false;
syncInProgress --;
}
});
} else {
syncInProgress --;
}
// RESULTS
if (localTimes['results'] < serverTimes['results']) {
getJSON(QUERY_URL + 'get_results?changer-after=' + localTimes['results'], function (code, data) {
if (code == 200) {
var os = db.transaction('results', 'readwrite').objectStore('results');
console.log(data);
data.data.forEach(function (entry) {
os.put(entry);
});
os.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
if (!data.keys.includes(parseInt(cursor.key))) {
os.delete(cursor.key);
}
cursor.continue();
} else {
var osUpdateTimes = db.transaction('update_times', 'readwrite').objectStore('update_times');
osUpdateTimes.put({ table: 'results', time: serverTimes['results'] });
syncInProgress --;
}
};
} else {
console.log("Something went wrong (HTTP " + code + ")");
syncOkay = false;
syncInProgress --;
}
});
} else {
syncInProgress --;
}
// PLANNINGS
if (localTimes['plannings'] < serverTimes['plannings']) {
getJSON(QUERY_URL + 'get_plannings?changer-after=' + localTimes['plannings'], function (code, data) {
if (code == 200) {
var os = db.transaction('plannings', 'readwrite').objectStore('plannings');
console.log(data);
data.data.forEach(function (entry) {
os.put(entry);
});
os.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
if (!data.keys.includes(parseInt(cursor.key))) {
os.delete(cursor.key);
}
cursor.continue();
} else {
var osUpdateTimes = db.transaction('update_times', 'readwrite').objectStore('update_times');
osUpdateTimes.put({ table: 'plannings', time: serverTimes['plannings'] });
syncInProgress --;
}
};
} else {
console.log("Something went wrong (HTTP " + code + ")");
syncOkay = false;
syncInProgress --;
}
});
} else {
syncInProgress --;
}
if (isLoggedIn()) {
// TRIM_BOATS
if (localTimes['trim_boats'] < serverTimes['trim_boats']) {
getJSON(QUERY_URL + 'get_trim_boats?changer-after=' + localTimes['trim_boats'], function (code, data) {
if (code == 200) {
var os = db.transaction('trim_boats', 'readwrite').objectStore('trim_boats');
console.log(data);
data.data.forEach(function (entry) {
os.put(entry);
});
os.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
if (!data.keys.includes(parseInt(cursor.key))) {
os.delete(cursor.key);
}
cursor.continue();
} else {
var osUpdateTimes = db.transaction('update_times', 'readwrite').objectStore('update_times');
osUpdateTimes.put({ table: 'trim_boats', time: serverTimes['trim_boats'] });
syncInProgress --;
}
};
} else {
console.log("Something went wrong (HTTP " + code + ")");
syncOkay = false;
syncInProgress --;
}
});
} else {
syncInProgress --;
}
// TRIM_USERS
if (localTimes['trim_users'] < serverTimes['trim_users']) {
getJSON(QUERY_URL + 'get_trim_users?changer-after=' + localTimes['trim_users'], function (code, data) {
if (code == 200) {
var os = db.transaction('trim_users', 'readwrite').objectStore('trim_users');
console.log(data);
data.data.forEach(function (entry) {
os.put(entry);
});
os.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
if (!data.keys.includes(parseInt(cursor.key))) {
os.delete(cursor.key);
}
cursor.continue();
} else {
var osUpdateTimes = db.transaction('update_times', 'readwrite').objectStore('update_times');
osUpdateTimes.put({ table: 'trim_users', time: serverTimes['trim_users'] });
syncInProgress --;
}
};
} else {
console.log("Something went wrong (HTTP " + code + ")");
syncOkay = false;
syncInProgress --;
}
});
} else {
syncInProgress --;
}
// TRIM_TRIMS
if (localTimes['trim_trims'] < serverTimes['trim_trims']) {
getJSON(QUERY_URL + 'get_trim_trims?changer-after=' + localTimes['trim_trims'], function (code, data) {
if (code == 200) {
var os = db.transaction('trim_trims', 'readwrite').objectStore('trim_trims');
console.log(data);
data.data.forEach(function (entry) {
os.put(entry);
});
os.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
if (!data.keys.includes(parseInt(cursor.key))) {
os.delete(cursor.key);
}
cursor.continue();
} else {
var osUpdateTimes = db.transaction('update_times', 'readwrite').objectStore('update_times');
osUpdateTimes.put({ table: 'trim_trims', time: serverTimes['trim_trims'] });
syncInProgress --;
}
};
} else {
console.log("Something went wrong (HTTP " + code + ")");
syncOkay = false;
syncInProgress --;
}
});
} else {
syncInProgress --;
}
} else {
syncInProgress -= 3;
}
// USERS
if (localTimes['users'] < serverTimes['users']) {
getJSON(QUERY_URL + 'get_users?changer-after=' + localTimes['users'], function (code, data) {
if (code == 200) {
var os = db.transaction('users', 'readwrite').objectStore('users');
console.log(data);
data.data.forEach(function (entry) {
os.put(entry);
});
os.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
if (!data.keys.includes(parseInt(cursor.key))) {
os.delete(cursor.key);
}
cursor.continue();
} else {
var osUpdateTimes = db.transaction('update_times', 'readwrite').objectStore('update_times');
osUpdateTimes.put({ table: 'users', time: serverTimes['users'] });
syncInProgress --;
}
};
} else {
console.log("Something went wrong (HTTP " + code + ")");
syncOkay = false;
syncInProgress --;
}
});
} else {
syncInProgress --;
}
} else {
console.log("Something went wrong (HTTP " + code + ")");
syncOkay = false;
syncInProgress = 0;
}
});
};
}
function checkSync() {
if (!canUseLocalDB) return;
var osUpdateTimes = db.transaction('update_times').objectStore('update_times');
osUpdateTimes.get('last_sync').onsuccess = function (event) {
var lastSync = event.target.result.time;
var now = Math.floor(Date.now() / 1000);
if ((lastSync + 600) < now) { // sync max all 10 minutes
sync();
}
};
}
function initDatabase() {
if (window.indexedDB) {
var request = window.indexedDB.open('regatten_app_db_' + BOATCLASS, DB_VERSION);
request.onerror = function (event) {
console.log("Cannot open DB: " + event.target.errorCode);
runPageScript();
};
request.onsuccess = function (event) {
console.log("Database loaded");
db = event.target.result;
db.onversionchange = function (event) {
if (syncTimer != null) window.clearInterval(syncTimer);
if (updateSyncStatusTimer != null) window.clearInterval(updateSyncStatusTimer);
// TODO document.getElementById('syncstatus').innerHTML = '';
canUseLocalDB = false;
db.close();
location.reload;
}
db.onerror = function (event) {
console.log("DB Error: " + event.target.errorCode);
};
canUseLocalDB = true;
db.transaction('update_times').objectStore('update_times').get('last_sync').onsuccess = function (event) {
var lastSync = event.target.result.time;
if (lastSync > 0) {
runPageScript();
}
};
checkSync();
syncTimer = window.setInterval(checkSync, 300000); // 5 min
window.ononline = function () {
checkSync();
}
};
request.onupgradeneeded = function (event) {
var db = event.target.result;
var upgradeTransaction = event.target.transaction;
var oldVersion = event.oldVersion;
var newVersion = event.newVersion;
console.log("Datenbank Version Upgrade von " + oldVersion + " auf " + newVersion);
if ((oldVersion < 1) && (newVersion >= 1)) {
console.log('to version 1');
var osClubs = db.createObjectStore('clubs', { keyPath: 'id' });
var osBoats = db.createObjectStore('boats', { keyPath: 'id' });
var osSailors = db.createObjectStore('sailors', { keyPath: 'id' });
var osRegattas = db.createObjectStore('regattas', { keyPath: 'id' });
var osResults = db.createObjectStore('results', { keyPath: 'id' });
osResults.createIndex('regatta', 'regatta', { unique: false });
var osPlannings = db.createObjectStore('plannings', { keyPath: 'id' });
osPlannings.createIndex('user', 'user', { unique: false });
osPlannings.createIndex('regatta', 'regatta', { unique: false });
var osTrimBoats = db.createObjectStore('trim_boats', { keyPath: 'id' });
var osTrimUsers = db.createObjectStore('trim_users', { keyPath: 'id' });
osTrimUsers.createIndex('boat', 'boat', { unique: false });
var osTrimTrims = db.createObjectStore('trim_trims', { keyPath: 'id' });
osTrimTrims.createIndex('boat', 'boat', { unique: false });
var osUpdateTimes = db.createObjectStore('update_times', { keyPath: 'table' });
osUpdateTimes.add({ table: 'last_sync', time: 0 });
osUpdateTimes.add({ table: 'clubs', time: 0 });
osUpdateTimes.add({ table: 'boats', time: 0 });
osUpdateTimes.add({ table: 'sailors', time: 0 });
osUpdateTimes.add({ table: 'regattas', time: 0 });
osUpdateTimes.add({ table: 'results', time: 0 });
osUpdateTimes.add({ table: 'plannings', time: 0 });
osUpdateTimes.add({ table: 'trim_boats', time: 0 });
osUpdateTimes.add({ table: 'trim_users', time: 0 });
osUpdateTimes.add({ table: 'trim_trims', time: 0 });
}
if ((oldVersion < 2) && (newVersion >= 2)) {
console.log('to version 2');
var osUsers = db.createObjectStore('users', { keyPath: 'id' });
osUsers.createIndex('username', 'username', { unique: true });
var osUpdateTimes = upgradeTransaction.objectStore('update_times');
osUpdateTimes.add({ table: 'users', time: 0 });
}
if ((oldVersion < 3) && (newVersion >= 3)) {
console.log('to version 3');
var osYears = db.createObjectStore('years', { keyPath: 'year' });
var osUpdateTimes = upgradeTransaction.objectStore('update_times');
osUpdateTimes.put({ table: 'regattas', time: 0 });
}
var osUpdateTimes = upgradeTransaction.objectStore('update_times');
osUpdateTimes.put({ table: 'last_sync', time: 0 });
}
} else {
runPageScript();
}
}

View File

@@ -0,0 +1,87 @@
function parseDate(string) {
var year, month, day;
if (string.includes('.')) {
var split = string.split('.');
if (split.length != 3) return null;
year = parseInt(split[2]);
month = parseInt(split[1]);
day = parseInt(split[0]);
} else if (string.includes('/')) {
var split = string.split('/');
if (split.length != 3) return null;
year = parseInt(split[2]);
month = parseInt(split[0]);
day = parseInt(split[1]);
} else if (string.includes('-')) {
var split = string.split('-');
if (split.length != 3) return null;
if (split[2].length > 2) {
year = parseInt(split[2]);
month = parseInt(split[1]);
day = parseInt(split[0]);
} else {
year = parseInt(split[0]);
month = parseInt(split[1]);
day = parseInt(split[2]);
}
} else {
return null;
}
if (isNaN(year) || isNaN(month) || isNaN(day)) return null;
if (year.toString().length == 2) year = (year < 70 ? 2000 : 1900) + year;
if ((year < 1970) || (year > 3000)) return null;
if ((month < 1) || (month > 12)) return null;
if ((day < 1) || (day > 31)) return null;
var date = new Date(Date.UTC(year, month - 1, day));
return date;
}
function getToday() {
var date = new Date();
date = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
return date;
}
function formatDate(format, date = null) {
if (date === null) {
date = new Date();
} else {
date = new Date(date.valueOf());
date.setMinutes(date.getMinutes() + date.getTimezoneOffset());
}
format = format.replace("M", "%1%");
format = format.replace("F", "%2%");
format = format.replace("D", "%3%");
format = format.replace("l", "%4%");
var tmp = date.getFullYear().toString();
var tmp2 = tmp.substr(2);
format = format.replace("Y", tmp);
format = format.replace('y', tmp2);
tmp = (date.getMonth() + 1).toString();
tmp2 = (tmp.length > 1 ? tmp : ('0' + tmp));
format = format.replace('n', tmp);
format = format.replace('m', tmp2);
tmp = date.getDate().toString();
tmp2 = (tmp.length > 1 ? tmp : ('0' + tmp));
format = format.replace('j', tmp);
format = format.replace('d', tmp2);
tmp = date.getDay();
tmp2 = (tmp == 0 ? 7 : tmp);
format = format.replace('w', tmp);
format = format.replace('N', tmp2);
format = format.replace('%1%', strings.months_short[date.getMonth()]);
format = format.replace('%2%', strings.months_long[date.getMonth()]);
format = format.replace('%3%', strings.weekdays_short[date.getDay()]);
format = format.replace('%4%', strings.weekdays_long[date.getDay()]);
return format;
}

View File

@@ -6,7 +6,8 @@
?> ?>
const apiUrl = '<?php echo SERVER_ADDR; ?>/api/'; const QUERY_URL = '<?php echo SERVER_ADDR; ?>/api/';
const BOATCLASS = '<?php echo BOATCLASS; ?>';
var randomId = function() { return '_' + Math.random().toString(36).substr(2, 9); } var randomId = function() { return '_' + Math.random().toString(36).substr(2, 9); }
@@ -181,33 +182,53 @@ var logout = function() {
}); });
} }
var initRegatten = function() { function resetDb() {
loggedin = (localStorage.getItem('auth_id') !== null); $('#menu-developer').hideMenu();
if (canUseLocalDB) {
if (loggedin) { showLoader();
var auth = { var request = window.indexedDB.deleteDatabase('regatten_app_db_' + BOATCLASS);
id: localStorage.getItem('auth_id'), request.onerror = function (event) {
hash: localStorage.getItem('auth_hash') console.log("Cannot open DB: " + event.target.errorCode);
} toastError('There was an error deleting your database.<br>Please report this to <a href="mailto:dev@regatten.net">dev@regatten.net</a>');
var user = { hideLoader();
id: localStorage.getItem('auth_user'), };
name: localStorage.getItem('auth_username') request.onsuccess = function (event) {
} console.log('DB deleted');
if ((auth.hash === null) || (user.id === null) || (user.name === null)) { toastInfo('The database was deleted. Please reload or close this tab.<br>At the next visit, a new database will be created.');
logoutClearStorage(); hideLoader();
return;
} }
} else {
toastWarn('Your device does not support storing data locally. All data is fetched directly from our server.<br>As a result, you can not reset your database.');
} }
}
function resetCache() {
$('#menu-developer').hideMenu();
navigator.serviceWorker.getRegistrations().then(function (registrations) {
for (let registration of registrations) {
console.log('Unregister sW:', registration);
registration.unregister();
}
});
caches.keys().then((keyList) => {
return Promise.all(keyList.map((key) => {
console.log('Cache deleted:', key);
return caches.delete(key);
}));
});
toastInfo('The serviceWorker and the cache were deleted. A new serviceWorker will be generated on the next refresh.');
}
var initRegatten = function() {
showLoader();
if (loggedin) { initDatabase();
if (isLoggedIn) {
$('.show-notloggedin').css('display', 'none'); $('.show-notloggedin').css('display', 'none');
$('.replace-userid-href').attr('href', $('.replace-userid-href').attr('href').replace('%USERID%', user.id)); $('.replace-userid-href').attr('href', $('.replace-userid-href').attr('href').replace('%USERID%', USER_ID));
$('.replace-username').html(user.name); $('.replace-username').html(USER_NAME);
} else { } else {
$('.show-loggedin').css('display', 'none'); $('.show-loggedin').css('display', 'none');
} }
if (typeof siteScript !== 'undefined') {
siteScript();
}
} }

View File

@@ -8,4 +8,51 @@
const strings = { const strings = {
inetMsgOffline: "Keine Internet-Verbindung erkannt", inetMsgOffline: "Keine Internet-Verbindung erkannt",
inetMsgOnline: "Du bist wieder online", inetMsgOnline: "Du bist wieder online",
error_network: "Verbindung fehlgeschlagen.<br>Stelle sicher, dass Du mit dem Internet verbunden bist und versuche es erneut!",
months_short: [
'Jan.',
'Feb.',
'März',
'Apr.',
'Mai',
'Juni',
'Juli',
'Aug.',
'Sep.',
'Okt.',
'Nov.',
'Dez.'
],
months_long: [
'Januar',
'Februar',
'März',
'April',
'Mai',
'Juni',
'Juli',
'August',
'September',
'Oktober',
'November',
'Dezember'
],
weekdays_short: [
'So',
'Mo',
'Di',
'Mi',
'Do',
'Fr',
'Sa'
],
weekdays_long: [
'Sonntag',
'Montag',
'Dienstag',
'Mittwoch',
'Donnerstag',
'Freitag',
'Samstag'
],
} }

View File

@@ -7,30 +7,52 @@
$sp['output'] .= $tpl->load('card', [$content]); $sp['output'] .= $tpl->load('card', [$content]);
// Favorites // Favorites
$content = "<h2>Deine Favoriten</h2>"; $content = '<h2>Deine Favoriten</h2>';
$thead = "<tr><th>Segler</th><th>Rangliste 2020</th></tr>"; $thead = '<tr><th>Segler</th><th id="th-ranking">Rangliste</th></tr>';
$content .= $tpl->load('table', [$thead, 'html-id' => 'table-favorites', 'css-class' => 'mb-0 mt-3']); $content .= $tpl->load('table', [$thead, 'html-id' => 'table-favorites', 'css-class' => 'mb-0 mt-3']);
$content .= '<p id="p-favorites" class="mt-3">';
$content .= 'Du folgst <b>keinen</b> Seglern.<br>';
$content .= 'Um jemandem zu folgen, gehe zur <a href="' . LINK_PRE . 'sailors">Segler-Liste</a> und w&auml;hle bis zu f&uuml;nf Segler aus.';
$content .= '</p>';
$sp['output'] .= $tpl->load('card', [$content, 'html-id' => 'card-favorites']); $sp['output'] .= $tpl->load('card', [$content, 'html-id' => 'card-favorites']);
// Planning next // Planning next
$content = "<h2>Deine n&auml;chsten Regatten</h2>"; $content = '<h2>Deine n&auml;chsten Regatten</h2>';
$thead = "<tr><th>Datum</th><th>Regatta</th><th>Informationen</th><th>RLF</th><th>Segler</th></tr>"; $thead = '<tr><th>Datum</th><th>Regatta</th><th>Informationen</th><th>RLF</th><th>Segler</th></tr>';
$content .= $tpl->load('table', [$thead, 'html-id' => 'table-yournext', 'css-class' => 'mb-0 mt-3']); $content .= $tpl->load('table', [$thead, 'html-id' => 'table-yournext', 'css-class' => 'mb-0 mt-3']);
$content .= '<p id="p-yournext" class="mt-3">';
$content .= 'Du f&auml;hrst in den n&auml;chsten vier Wochen auf keine Regatta!';
$content .= '</p>';
$sp['output'] .= $tpl->load('card', [$content, 'html-id' => 'card-yournext']); $sp['output'] .= $tpl->load('card', [$content, 'html-id' => 'card-yournext']);
// Not logged in
$content = '<h2>Nicht angemeldet</h2>';
$content .= '<p class="mt-3">';
$content .= 'Um alle Funktionen dieser Seite nutzen zu k&ouml;nnen, <a href="#" data-menu="menu-login">logge Dich bitte ein</a>.<br>';
$content .= 'Solltest Du noch kein Benutzerkonto haben, kannst Du Dich kostenlos <a href="#" data-menu="menu-signup">registrieren</a>.';
$content .= '</p>';
$sp['output'] .= $tpl->load('card', [$content, 'html-id' => 'card-notloggedin']);
// Next // Next
$content = "<h2>N&auml;chste Regatten</h2>"; $content = '<h2>N&auml;chste Regatten</h2>';
$thead = "<tr><th>Datum</th><th>Regatta</th><th>Informationen</th><th>RLF</th></tr>"; $thead = '<tr><th>Datum</th><th>Regatta</th><th>Informationen</th><th>RLF</th></tr>';
$content .= $tpl->load('table', [$thead, 'html-id' => 'table-next', 'css-class' => 'mb-0 mt-3']); $content .= $tpl->load('table', [$thead, 'html-id' => 'table-next', 'css-class' => 'mb-0 mt-3']);
$content .= '<p id="p-next" class="mt-3">';
$content .= 'Keine Regatten in den n&auml;chsten zwei Wochen!';
$content .= '</p>';
$sp['output'] .= $tpl->load('card', [$content, 'html-id' => 'card-next']); $sp['output'] .= $tpl->load('card', [$content, 'html-id' => 'card-next']);
// Last // Last
$content = "<h2>Letzte Regatten</h2>"; $content = '<h2>Letzte Regatten</h2>';
$thead = "<tr><th>Datum</th><th>Regatta</th><th>Ergebnisse</th><th>RLF</th></tr>"; $thead = '<tr><th>Datum</th><th>Regatta</th><th>Ergebnisse</th><th>RLF</th></tr>';
$content .= $tpl->load('table', [$thead, 'html-id' => 'table-last', 'css-class' => 'mb-0 mt-3']); $content .= $tpl->load('table', [$thead, 'html-id' => 'table-last', 'css-class' => 'mb-0 mt-3']);
$content .= '<p id="p-last" class="mt-3">';
$content .= 'Keine Regatten in den letzten zwei Wochen!';
$content .= '</p>';
$sp['output'] .= $tpl->load('card', [$content, 'html-id' => 'card-last']); $sp['output'] .= $tpl->load('card', [$content, 'html-id' => 'card-last']);
@@ -46,20 +68,6 @@
$sp['output'] .= $tpl->load('card', [$content]); $sp['output'] .= $tpl->load('card', [$content]);
$sp['scripts'] = ' $sp['scripts'] = '<!-- DEBUG -->' . $scripts->load('index');
<script>
var siteScript = function() {
if (loggedin) {
$(\'#table-favorites\').find(\'tbody\').html(\'<tr><td>Finn Soetebier</td><td>noch nicht verf&uuml;gbar</td></tr>\');
$(\'#table-yournext\').find(\'tbody\').html(\'<tr><td style="white-space:nowrap;">10. Oct \\\'20<br>14. Oct \\\'20</td><td><a href="#">BSC</a><br>VERSCHOBEN: IDJM, Blankenese</td><td><a href="#">Informationen</a><br><a href="#">Meldung</a> <font style="color:red;">(noch 5 Tage)</a></td><td>1,26</td><td>Finn Soetebier<br>Timon Ostertun</td></tr>\');
} else {
$(\'#card-favorites\').hide();
$(\'#card-yournext\').hide();
}
$(\'#table-next\').find(\'tbody\').html(\'<tr><td style="white-space:nowrap;">10. Oct \\\'20<br>14. Oct \\\'20</td><td><a href="#">BSC</a><br>VERSCHOBEN: IDJM, Blankenese</td><td><a href="#">Informationen</a><br><a href="#">Meldung</a> <font style="color:red;">(noch 5 Tage)</a></td><td>1,26</td></tr>\');
$(\'#table-last\').find(\'tbody\').html(\'<tr><td style="white-space:nowrap;">10. Oct \\\'20<br>14. Oct \\\'20</td><td><a href="#">BSC</a><br>VERSCHOBEN: IDJM, Blankenese</td><td><i style="color:green;" class="fas fa-check"></i> <a href="#">Ergebnisse</a></td><td>1,26</td></tr>\');
}
</script>
';
?> ?>

View File

@@ -3,6 +3,7 @@
require_once(__DIR__ . '/server/config.php'); require_once(__DIR__ . '/server/config.php');
require_once(__DIR__ . '/server/log.php'); require_once(__DIR__ . '/server/log.php');
require_once(__DIR__ . '/server/templates.php'); require_once(__DIR__ . '/server/templates.php');
require_once(__DIR__ . '/server/scripts.php');
$request = false; $request = false;
if (isset($_GET['request'])) { if (isset($_GET['request'])) {
@@ -36,6 +37,7 @@
]; ];
$tpl = new Templates(__DIR__ . '/server/templates/'); $tpl = new Templates(__DIR__ . '/server/templates/');
$scripts = new Scripts(__DIR__ . '/server/scripts/');
require_once(__DIR__ . '/content/' . $site . '.php'); require_once(__DIR__ . '/content/' . $site . '.php');

View File

@@ -7,6 +7,7 @@
else else
echo '<a href="' . LINK_PRE . $sp['backbutton'] . '" class="header-icon header-icon-1"><i class="fas fa-arrow-left"></i></a>'; echo '<a href="' . LINK_PRE . $sp['backbutton'] . '" class="header-icon header-icon-1"><i class="fas fa-arrow-left"></i></a>';
} ?> } ?>
<a href="#" data-menu="menu-developer" class="header-icon header-icon-3"><i class="fas fa-code"></i></a>
<a href="#" data-menu="menu-settings" class="header-icon header-icon-4"><i class="fas fa-cog"></i></a> <a href="#" data-menu="menu-settings" class="header-icon header-icon-4"><i class="fas fa-cog"></i></a>
</div> </div>
<div id="footer-bar" class="footer-bar-1"> <div id="footer-bar" class="footer-bar-1">

View File

@@ -129,6 +129,35 @@
</div> </div>
</div> </div>
<div id="menu-developer" class="menu menu-box-bottom menu-box-detached rounded-m" data-menu-height="310">
<div class="menu-title"><h1>Entwickler-Optionen</h1><p class="color-highlight">&nbsp;</p><a href="#" class="close-menu"><i class="fa fa-times"></i></a></div>
<div class="divider divider-margins mb-n2"></div>
<div class="content">
<div class="list-group list-custom-small">
<a href="https://info.ostertun.net/regatten/beta">
<i class="fa font-14 fa-info rounded-s bg-highlight color-white"></i>
<span>Infos zur BETA</span>
<i class="fa fa-angle-right"></i>
</a>
<a href="javascript:resetDb();">
<i class="fa font-14 fa-database rounded-s bg-highlight color-white"></i>
<span>Reset Database</span>
<i class="fa fa-angle-right"></i>
</a>
<a href="javascript:resetCache();">
<i class="fa font-14 fa-trash-alt rounded-s bg-highlight color-white"></i>
<span>Reset Cache</span>
<i class="fa fa-angle-right"></i>
</a>
<a href="https://report.regatten.net/" class="border-0">
<i class="fa font-14 fa-bug rounded-s bg-highlight color-white"></i>
<span>Problem melden</span>
<i class="fa fa-angle-right"></i>
</a>
</div>
</div>
</div>
<div id="menu-login" class="menu menu-box-top menu-box-detached rounded-m" data-menu-height="270"> <div id="menu-login" class="menu menu-box-top menu-box-detached rounded-m" data-menu-height="270">
<div class="content bottom-0"> <div class="content bottom-0">
<h1 class="text-center mt-5 font-900">Login</h1> <h1 class="text-center mt-5 font-900">Login</h1>

View File

@@ -49,6 +49,8 @@
<script type="text/javascript" src="<?php echo SERVER_ADDR; ?>/client/scripts/bootstrap.min.js"></script> <script type="text/javascript" src="<?php echo SERVER_ADDR; ?>/client/scripts/bootstrap.min.js"></script>
<script type="text/javascript" src="<?php echo SERVER_ADDR; ?>/client/scripts/strings.js.php"></script> <script type="text/javascript" src="<?php echo SERVER_ADDR; ?>/client/scripts/strings.js.php"></script>
<script type="text/javascript" src="<?php echo SERVER_ADDR; ?>/client/scripts/regatten.js.php"></script> <script type="text/javascript" src="<?php echo SERVER_ADDR; ?>/client/scripts/regatten.js.php"></script>
<script type="text/javascript" src="<?php echo SERVER_ADDR; ?>/client/scripts/datetime.js"></script>
<script type="text/javascript" src="<?php echo SERVER_ADDR; ?>/client/scripts/database.js"></script>
<script type="text/javascript" src="<?php echo SERVER_ADDR; ?>/client/scripts/custom.js.php"></script> <script type="text/javascript" src="<?php echo SERVER_ADDR; ?>/client/scripts/custom.js.php"></script>
<script type="text/javascript" src="<?php echo SERVER_ADDR; ?>/client/scripts/pwa.js.php"></script> <script type="text/javascript" src="<?php echo SERVER_ADDR; ?>/client/scripts/pwa.js.php"></script>
</body> </body>

37
server/scripts.php Normal file
View File

@@ -0,0 +1,37 @@
<?php
class Scripts {
private $path;
private $scripts;
function __construct($path) {
if (substr($path, -1) != '/') $path .= '/';
$this->path = $path;
$this->scripts = [];
}
function load($name, $params = []) {
if (!isset($this->scripts[$name])) {
$filename = $this->path . $name . '.js';
if (file_exists($filename) and is_file($filename)) {
$this->scripts[$name] = file_get_contents($filename);
} else {
return "<p>Script '$name' not found!</p>";
}
}
$script = $this->scripts[$name];
while (($pos = strpos($script, '$$')) !== false) {
$pos += 2;
$pos2 = strpos($script, ';', $pos);
if ($pos2 === false) return "<p>Syntax error in script '$name'!</p>";
$ph = substr($script, $pos, $pos2 - $pos);
if (!isset($params[$ph])) $params[$ph] = '';
$script = str_replace('$$' . $ph . ';', $params[$ph], $script);
}
return '<script>' . $script . '</script>';
}
}
?>

323
server/scripts/index.js Normal file
View File

@@ -0,0 +1,323 @@
var siteScript = async function() {
if (isLoggedIn()) {
$('#card-notloggedin').hide();
var user = await dbGetData('users', localStorage.getItem('auth_user'));
var today = getToday();
// Favorites
var watched = [];
for (var i = 1; i <= 5; i ++) {
sailor_id = user['sailor' + i];
if (sailor_id != null) {
watched.push(await dbGetData('sailors', sailor_id));
}
}
if (watched.length > 0) {
var year = (new Date()).getFullYear();
$('#th-ranking').html('Rangliste ' + year);
// TODO: get ranking
tbody = '';
for (i in watched) {
sailor = watched[i];
tbody += '<tr><td>' + sailor.name + '</td><td>';
// TODO: check if ranking and output
//tbody += '<i>nicht in der Rangliste</i>';
tbody += '<i>Ranglisten werden aktuell noch nicht unterst&uuml;tzt</i>';
tbody += '</td></tr>';
}
$('#table-favorites').find('tbody').html(tbody);
$('#p-favorites').hide();
$('#table-favorites').show();
} else {
$('#table-favorites').hide();
$('#p-favorites').show();
}
$('#card-favorites').show();
// Your next
var planningsDB = await dbGetDataIndex('plannings', 'user', user.id);
var minDate = getToday();
minDate.setDate(minDate.getDate() - 1);
var maxDate = getToday();
maxDate.setDate(maxDate.getDate() + 28);
var regattas = await dbGetRegattasRange(minDate, maxDate);
var plannings = [];
for (i = planningsDB.length - 1; i >= 0; i --) {
var planning = planningsDB[i];
for (j in regattas) {
var regatta = regattas[j];
if (regatta.id == planning.regatta) {
planning.regatta = regatta;
plannings.push(planning);
}
}
}
plannings.sort(function (a, b) {
if (a.regatta.date < b.regatta.date) return -1;
if (a.regatta.date > b.regatta.date) return 1;
return 0;
});
if (plannings.length > 0) {
tbody = '';
for (i in plannings) {
var planning = plannings[i];
var regatta = planning.regatta;
var club = null;
if (regatta['club'] != null)
club = await dbGetData('clubs', regatta['club']);
var dateFrom = regatta['dateFrom'];
var dateTo = regatta['dateTo'];
// TODO: get steuermann and crew
var steuermann = '<i>noch unklar</i>';
if (planning.steuermann !== null) {
steuermann = (await dbGetData('sailors', planning.steuermann)).name;
}
var crew = [];
if (planning.crew !== '') {
crewIds = planning.crew.split(',');
for (j in crewIds) {
crew.push((await dbGetData('sailors', crewIds[j])).name);
}
}
// output
tbody += '<tr>';
tbody += '<td><span style="white-space:nowrap;">' + formatDate("j. M 'y", dateFrom) + '<br>' + formatDate("j. M 'y", dateTo) + '</span></td>';
var content = '';
if (club != null) {
content = club['kurz'];
if (club['website'] != '') {
content = '<a href="' + club['website'] + '" target="_blank">' + content + '</a>';
}
}
tbody += '<td>' + content + '<br>' + (regatta['canceled'] == 1 ? '<s>' : '') + regatta['name'] + (regatta['canceled'] == 1 ? '</s>' : '') + '</td>';
var buf = '';
if (regatta['info'] != '') {
buf += '<a target="_blank" href="' + regatta['info'] + '">Informationen</a>';
}
if ((regatta['meldung'] != '') && (dateTo >= today)) {
buf += '<br><a target="_blank" href="' + regatta['meldung'] + '">Meldung</a>';
if ((planning != null) && (planning['gemeldet'] == "1")) {
buf += ' <i>(du hast gemeldet)</i>';
} else if (regatta['meldungOffen'] == "0") {
buf += ' <i>(geschlossen)</i>';
} else if (regatta['meldungSchluss'] != null) {
early = false;
if (regatta['meldungEarly'] != null) {
ms = parseDate(regatta['meldungEarly']);
if (ms >= today) {
early = true;
}
}
if (!early)
ms = parseDate(regatta['meldungSchluss']);
if (ms >= today) {
diff = Math.round((ms - today) / 86400000);
red = (diff < 7);
if (diff <= 14) {
txt = 'noch ' + diff + ' Tag' + (diff != 1 ? 'e' : '');
} else if (diff < 35) {
diff = Math.floor(diff / 7);
txt = 'noch ' + diff + ' Woche' + (diff != 1 ? 'n' : '');
} else {
diff = Math.floor(diff / 30.5);
txt = 'noch ' + diff + ' Monat' + (diff != 1 ? 'e' : '');
}
buf += ' <i>' + (red ? '<b><font style="color:red;">(' : '(') + txt + (early ? ' verg&uuml;nstigt' : '') + (red ? ')</font></b>' : ')') + '</i>';
} else {
buf += ' <i>(Meldeschluss abgelaufen)</i>';
}
}
}
if (regatta['bericht'] != '') {
buf += '<br><a target="_blank" href="' + regatta['bericht'] + '">Bericht</a>';
}
if (regatta['oresults'] != '') {
buf += '<br><a target="_blank" href="' + regatta['oresults'] + '">off. Ergebnisse</a>';
}
tbody += '<td>' + buf + '</td>';
tbody += '<td><span style="white-space:nowrap;">' + parseFloat(regatta['rlf']).toFixed(2) + '</span></td>';
tbody += '<td>' + steuermann + '<br>' + crew.join('<br>') + '</td>';
tbody += '</tr>';
}
$('#table-yournext').find('tbody').html(tbody);
$('#p-yournext').hide();
$('#table_yournext').show();
} else {
$('#table-yournext').hide();
$('#p-yournext').show();
}
$('#card-yournext').show();
} else {
$('#card-favorites').hide();
$('#card-yournext').hide();
$('#card-notloggedin').show();
}
// Next
var minDate = getToday();
minDate.setDate(minDate.getDate() - 1);
var maxDate = getToday();
maxDate.setDate(maxDate.getDate() + 14);
var regattas = await dbGetRegattasRange(minDate, maxDate);
if (regattas.length > 0) {
tbody = '';
for (i in regattas) {
var regatta = regattas[i];
var club = null;
if (regatta['club'] != null)
club = await dbGetData('clubs', regatta['club']);
var plannings = await dbGetDataIndex('plannings', 'regatta', regatta['id']);
var dateFrom = regatta['dateFrom'];
var dateTo = regatta['dateTo'];
// output
tbody += '<tr>';
tbody += '<td><span style="white-space:nowrap;">' + formatDate("j. M 'y", dateFrom) + '<br>' + formatDate("j. M 'y", dateTo) + '</span></td>';
var content = '';
if (club != null) {
content = club['kurz'];
if (club['website'] != '') {
content = '<a href="' + club['website'] + '" target="_blank">' + content + '</a>';
}
}
tbody += '<td>' + content + '<br>' + (regatta['canceled'] == 1 ? '<s>' : '') + regatta['name'] + (regatta['canceled'] == 1 ? '</s>' : '') + '</td>';
var buf = '';
if (regatta['info'] != '') {
buf += '<a target="_blank" href="' + regatta['info'] + '">Informationen</a>';
}
if ((regatta['meldung'] != '') && (dateTo >= today)) {
buf += '<br><a target="_blank" href="' + regatta['meldung'] + '">Meldung</a>';
var planning = null;
if (isLoggedIn()) {
for (id in plannings) {
if (plannings[id]['user'] == USER_ID) {
planning = plannings[id];
break;
}
}
}
if ((planning != null) && (planning['gemeldet'] == "1")) {
buf += ' <i>(du hast gemeldet)</i>';
} else if (regatta['meldungOffen'] == "0") {
buf += ' <i>(geschlossen)</i>';
} else if (regatta['meldungSchluss'] != null) {
early = false;
if (regatta['meldungEarly'] != null) {
ms = parseDate(regatta['meldungEarly']);
if (ms >= today) {
early = true;
}
}
if (!early)
ms = parseDate(regatta['meldungSchluss']);
if (ms >= today) {
diff = Math.round((ms - today) / 86400000);
red = (diff < 7);
if (diff <= 14) {
txt = 'noch ' + diff + ' Tag' + (diff != 1 ? 'e' : '');
} else if (diff < 35) {
diff = Math.floor(diff / 7);
txt = 'noch ' + diff + ' Woche' + (diff != 1 ? 'n' : '');
} else {
diff = Math.floor(diff / 30.5);
txt = 'noch ' + diff + ' Monat' + (diff != 1 ? 'e' : '');
}
buf += ' <i>' + (red ? '<b><font style="color:red;">(' : '(') + txt + (early ? ' verg&uuml;nstigt' : '') + (red ? ')</font></b>' : ')') + '</i>';
} else {
buf += ' <i>(Meldeschluss abgelaufen)</i>';
}
}
}
if (regatta['bericht'] != '') {
buf += '<br><a target="_blank" href="' + regatta['bericht'] + '">Bericht</a>';
}
if (regatta['oresults'] != '') {
buf += '<br><a target="_blank" href="' + regatta['oresults'] + '">off. Ergebnisse</a>';
}
tbody += '<td>' + buf + '</td>';
tbody += '<td><span style="white-space:nowrap;">' + parseFloat(regatta['rlf']).toFixed(2) + '</span></td>';
tbody += '</tr>';
}
$('#table-next').find('tbody').html(tbody);
$('#p-next').hide();
$('#table-next').show();
} else {
$('#table-next').hide();
$('#p-next').show();
}
// Last
var minDate = getToday();
minDate.setDate(minDate.getDate() - 14);
var maxDate = getToday();
maxDate.setDate(maxDate.getDate() - 1);
var regattas = await dbGetRegattasRange(minDate, maxDate);
var regattaResults = [];
for (id in regattas) {
var entry = regattas[id];
var results = await dbGetDataIndex('results', 'regatta', entry['id']);
regattaResults[entry['id']] = (results.length > 0);
}
if (regattas.length > 0) {
tbody = '';
for (i in regattas) {
var regatta = regattas[i];
var club = null;
if (regatta['club'] != null)
club = await dbGetData('clubs', regatta['club']);
var dateFrom = regatta['dateFrom'];
var dateTo = regatta['dateTo'];
// output
tbody += '<tr>';
tbody += '<td><span style="white-space:nowrap;">' + formatDate("j. M 'y", dateFrom) + '<br>' + formatDate("j. M 'y", dateTo) + '</span></td>';
var content = '';
if (club != null) {
content = club['kurz'];
if (club['website'] != '') {
content = '<a href="' + club['website'] + '" target="_blank">' + content + '</a>';
}
}
tbody += '<td>' + content + '<br>' + (regatta['canceled'] == 1 ? '<s>' : '') + regatta['name'] + (regatta['canceled'] == 1 ? '</s>' : '') + '</td>';
var buf = '';
if (regatta['canceled'] == "1") {
buf = '<i style="color:red;" class="fas fa-times"></i> Ausgefallen</td>';
} else {
if (regattaResults[regatta['id']]) {
buf = '<i style="color:green;" class="fas fa-check"></i> <a href="' + LINK_PRE + 'result?regatta=' + regatta['id'] + '">Ergebnisse</a></td>';
} else {
buf = 'Nicht verf&uuml;gbar';
}
}
tbody += '<td>' + buf + '</td>';
tbody += '<td><span style="white-space:nowrap;">' + parseFloat(regatta['rlf']).toFixed(2) + '</span></td>';
tbody += '</tr>';
}
$('#table-last').find('tbody').html(tbody);
$('#p-last').hide();
$('#table-last').show();
} else {
$('#table-last').hide();
$('#p-last').show();
}
}

View File

@@ -22,13 +22,13 @@
} }
$template = $this->templates[$name]; $template = $this->templates[$name];
while (($pos = strpos($template, '$')) !== false) { while (($pos = strpos($template, '$$')) !== false) {
$pos ++; $pos += 2;
$pos2 = strpos($template, ';', $pos); $pos2 = strpos($template, ';', $pos);
if ($pos2 === false) return "<p>Syntax error in template '$name'!</p>"; if ($pos2 === false) return "<p>Syntax error in template '$name'!</p>";
$ph = substr($template, $pos, $pos2 - $pos); $ph = substr($template, $pos, $pos2 - $pos);
if (!isset($params[$ph])) $params[$ph] = ''; if (!isset($params[$ph])) $params[$ph] = '';
$template = str_replace('$' . $ph . ';', $params[$ph], $template); $template = str_replace('$$' . $ph . ';', $params[$ph], $template);
} }
return $template; return $template;
} }

View File

@@ -1,3 +1,3 @@
<a id="$html-id;" class="btn btn-full rounded-s text-uppercase font-900 shadow-m bg-highlight $css-class;" href="$1;"> <a id="$$html-id;" class="btn btn-full rounded-s text-uppercase font-900 shadow-m bg-highlight $$css-class;" href="$$1;">
$0; $$0;
</a> </a>

View File

@@ -1,5 +1,5 @@
<div id="$html-id;" class="card card-style"> <div id="$$html-id;" class="card card-style">
<div class="content $css-class;"> <div class="content $$css-class;">
$0; $$0;
</div> </div>
</div> </div>

View File

@@ -1,3 +1,3 @@
<i class="fa fa-exclamation-triangle fa-8x color-red2-dark"></i> <i class="fa fa-exclamation-triangle fa-8x color-red2-dark"></i>
<h1 class="fa-6x mt-5 font-900">$0;</h1> <h1 class="fa-6x mt-5 font-900">$$0;</h1>
<h4 class="mb-5 mt-3">$1;</h4> <h4 class="mb-5 mt-3">$$1;</h4>

View File

@@ -1,10 +1,10 @@
<div style="width: 100%; overflow-x: auto;"> <div style="width: 100%; overflow-x: auto;">
<table id="$html-id;" class="table table-striped table-bordered $css-class;"> <table id="$$html-id;" class="table table-striped table-bordered $$css-class;">
<thead> <thead>
$0; $$0;
</thead> </thead>
<tbody> <tbody>
$1; $$1;
</tbody> </tbody>
</table> </table>
</div> </div>