diff --git a/homepage/participo/.gitignore b/homepage/participo/.gitignore index be8da08..e047986 100644 --- a/homepage/participo/.gitignore +++ b/homepage/participo/.gitignore @@ -1 +1,3 @@ -local/*.php \ No newline at end of file +local/*.php +node_modules/* +testApi.config.yaml diff --git a/homepage/participo/.vscode/launch.json b/homepage/participo/.vscode/launch.json new file mode 100644 index 0000000..b2fddbf --- /dev/null +++ b/homepage/participo/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "post", + "type": "python", + "request": "launch", + "program": "testApi.py", + "console": "integratedTerminal", + "justMyCode": true, + "args": [ + "POST", + "--input", "testShiai.json" + ] + } + ] +} \ No newline at end of file diff --git a/homepage/participo/.vscode/settings.json b/homepage/participo/.vscode/settings.json index 1da7818..d248b80 100644 --- a/homepage/participo/.vscode/settings.json +++ b/homepage/participo/.vscode/settings.json @@ -1,7 +1,16 @@ { + "cSpell.language": "en,de-de", "cSpell.words": [ + "CURDATE", + "cwsv", + "cwsvjudo", "participo", "retval", - "shiai" + "shiai", + "vormundschaft", + "wettkampfkalender" + ], + "prettier.documentSelectors": [ + "**/*.{js,jsx,ts,tsx,vue,html,css,scss,less,json,md,mdx,graphql,yaml,yml,php}" ] } \ No newline at end of file diff --git a/homepage/participo/.vscode/sftp.json b/homepage/participo/.vscode/sftp.json index 447647d..fbe7d1e 100644 --- a/homepage/participo/.vscode/sftp.json +++ b/homepage/participo/.vscode/sftp.json @@ -7,7 +7,10 @@ "remotePath": "/www/participo", "ignore": [ ".vscode", - "*.py" + "*.py", + "*.config.yaml", + "package.json", "package-lock.json" + , "node-modules" ], "uploadOnSave": true } \ No newline at end of file diff --git a/homepage/participo/api/inc/.htaccess b/homepage/participo/api/inc/.htaccess new file mode 100644 index 0000000..3a42882 --- /dev/null +++ b/homepage/participo/api/inc/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/homepage/participo/api/inc/bootstrap.php b/homepage/participo/api/inc/bootstrap.php new file mode 100644 index 0000000..9836fb3 --- /dev/null +++ b/homepage/participo/api/inc/bootstrap.php @@ -0,0 +1,52 @@ +isValidFor("api")) { + die( + json_encode([ + "success" => false, + "reason" => "apiKey not sufficient or no api key provided", + ]) + ); + } +} + +/// - initialize the database connection +dbConnector::connect( + $cwsvJudoConfig["db"]["host"], + $cwsvJudoConfig["db"]["name"], + $cwsvJudoConfig["db"]["user"], + $cwsvJudoConfig["db"]["password"] +); diff --git a/homepage/participo/api/index.php b/homepage/participo/api/index.php new file mode 100644 index 0000000..8559627 --- /dev/null +++ b/homepage/participo/api/index.php @@ -0,0 +1,13 @@ + 'Welcome to the API' +// ]); +// break; +// } +?> \ No newline at end of file diff --git a/homepage/participo/api/shiai.php b/homepage/participo/api/shiai.php new file mode 100644 index 0000000..54d199c --- /dev/null +++ b/homepage/participo/api/shiai.php @@ -0,0 +1,54 @@ +$postData . " not valid json data!" + ])); + } + die(json_encode( + Shiai::fromArray($postData)->asArray() + )); + break; + // Read + case 'GET': + echo(json_encode( + Shiai::dbSelect() + )); + break; + // Update + case 'PUT': + die(json_encode([ + 'success'=>false, + 'reason'=>$method.".not supported yet." + ])); + break; + // Delete + case 'DELETE': + die(json_encode([ + 'success'=>false, + 'reason'=>$method.".not supported yet." + ])); + break; + // all other methods not supported + default: + die(json_encode([ + 'success'=>false, + 'reason'=>$method.".not supported." + ])); +} +?> diff --git a/homepage/participo/api/trainees.php b/homepage/participo/api/trainees.php new file mode 100644 index 0000000..8bf39de --- /dev/null +++ b/homepage/participo/api/trainees.php @@ -0,0 +1,37 @@ +userAttributes`" . + " ON `wkParticipo_user<=>userAttributes`.`userId` = `wkParticipo_Users`.`id`" . + " WHERE `wkParticipo_user<=>userAttributes`.`attributeId` = 4". + " ORDER BY `wkParticipo_Users`.`id` ASC;"; + + $wkSqlResponse = dbConnector::query($wkSqlQuery); + + // Postprocessing + // - convert the comma separated list into an array + foreach ($wkSqlResponse as &$user) { + $user["eMail"] = explode(",", $user["eMail"]); + foreach ($user["eMail"] as &$email) { + $email = trim($email); + } + } + return $wkSqlResponse; +} + +authorize(); +$wkSqlResponse = get(); + +// Sending Response +// - setting header +header("Content-Type: application/json"); +// - sending body payload +echo json_encode($wkSqlResponse); diff --git a/homepage/participo/api/users.php b/homepage/participo/api/users.php new file mode 100644 index 0000000..93820b4 --- /dev/null +++ b/homepage/participo/api/users.php @@ -0,0 +1,81 @@ +isValidFor("api")) { + die( + json_encode([ + "success" => false, + "reason" => "apiKey not sufficient or no api key provided", + ]) + ); + } +} + +function get() +{ + $wkSqlQuery = + "SELECT DISTINCT" . + " `wkParticipo_Users`.* " . + " FROM `wkParticipo_Users`" . + " JOIN `vormundschaft`" . + " ON `wkParticipo_Users`.`id` =`vormundschaft`.`userId`" . + " JOIN `wkParticipo_user<=>userAttributes`" . + " ON `wkParticipo_user<=>userAttributes`.`userId` = `vormundschaft`.`kidId`" . + " WHERE `wkParticipo_user<=>userAttributes`.`attributeId` = 4" . + " ORDER BY `wkParticipo_Users`.`id` ASC;"; + + $wkSqlResponse = dbConnector::query($wkSqlQuery); + + // Postprocessing + // - convert the comma separated list into an array + foreach ($wkSqlResponse as &$user) { + $user["eMail"] = explode(",", $user["eMail"]); + foreach ($user["eMail"] as &$email) { + $email = trim($email); + } + } + return $wkSqlResponse; +} + +init($cwsvJudoConfig); +authorize(); +$wkSqlResponse = get(); + +// Sending Response +// - setting header +header("Content-Type: application/json"); +// - sending body payload +echo json_encode($wkSqlResponse); + +// exit(0); + +?> diff --git a/homepage/participo/event.php b/homepage/participo/event.php index c3bc23a..2da7d96 100644 --- a/homepage/participo/event.php +++ b/homepage/participo/event.php @@ -3,8 +3,6 @@ setlocale(LC_ALL, 'de_DE@euro', 'de_DE', 'de', 'ge'); set_include_path(get_include_path() . PATH_SEPARATOR . './lib/'); require_once 'participoLib/event.php'; -// require_once 'participoLib/starter.php'; -// require_once 'participoLib/planer.php'; // Configs require_once 'config/participo.php'; @@ -46,4 +44,4 @@ participo::init($cwsvJudoConfig); - \ No newline at end of file + diff --git a/homepage/participo/index.js b/homepage/participo/index.js index 1c3b19f..ade2266 100644 --- a/homepage/participo/index.js +++ b/homepage/participo/index.js @@ -1,9 +1,13 @@ // What to do when the document is loaded. -document.addEventListener('DOMContentLoaded', function () { - // init materialize elements - initModals(); - initSidenav(); -}); +document.addEventListener( + 'DOMContentLoaded' + , function () { + // init materialize elements + initModals(); + initSidenav(); + initSelects(); + } +); function initSidenav() { var sidenavElements = document.querySelectorAll('.sidenav'); diff --git a/homepage/participo/index.php b/homepage/participo/index.php index 8d0b7eb..14b1878 100644 --- a/homepage/participo/index.php +++ b/homepage/participo/index.php @@ -1,6 +1,4 @@ - + diff --git a/homepage/participo/lib/participoLib/apiKey.php b/homepage/participo/lib/participoLib/apiKey.php index 77bfba1..5b31871 100644 --- a/homepage/participo/lib/participoLib/apiKey.php +++ b/homepage/participo/lib/participoLib/apiKey.php @@ -132,7 +132,7 @@ class ApiKey // @todo differentiate between inserting and updating if the id is set it should only be updated (e.g. prolonging) } - /** create an Api key from the return of an sql select * */ + /** create an Api key from the return of an sql select */ private static function fromDbArray(array $apiKey) { return new ApiKey( diff --git a/homepage/participo/lib/participoLib/dbConnector.php b/homepage/participo/lib/participoLib/dbConnector.php index f0ea0f0..1af8c20 100644 --- a/homepage/participo/lib/participoLib/dbConnector.php +++ b/homepage/participo/lib/participoLib/dbConnector.php @@ -28,7 +28,7 @@ class dbConnector public static function query($aQueryString, $aBindArray = [], $someOptions = []) { // var_dump($aQueryString, $aBindArray); - // Standardbelegungen + // Standardbelegungen if (empty($someOptions['dbCharset'])) { $someOptions['dbCharset'] = 'ISO-8859-1'; } @@ -65,7 +65,7 @@ class dbConnector ); } $pdoResult = $pdoStatement->execute(); - if (!$ignoreErrors && !$pdoResult) { + if (!$ignoreErrors && !$pdoResult) { echo("Error during dbQuery!\n"); echo("DB-Error:\n"); var_dump(self::$db->errorInfo()); @@ -128,6 +128,7 @@ class dbConnector } else { self::$db = null; } + return $success; } public static function debugEchoQuery($query, $params) diff --git a/homepage/participo/lib/participoLib/event.php b/homepage/participo/lib/participoLib/event.php index e08d207..c37e5cf 100644 --- a/homepage/participo/lib/participoLib/event.php +++ b/homepage/participo/lib/participoLib/event.php @@ -87,6 +87,9 @@ class Event if ((!isset($this->shiai) || $forceLoading) && isset($this->shiaiId)) { $this->shiai = Shiai::loadFromDb($this->shiaiId); } + if ($this->shiai == null){ + $this->shiai = Shiai::fromDbArray(json_decode($this->remarks, true)); + } return $this->shiai; } diff --git a/homepage/participo/lib/participoLib/participo.php b/homepage/participo/lib/participoLib/participo.php index 42fca1d..e0e3861 100644 --- a/homepage/participo/lib/participoLib/participo.php +++ b/homepage/participo/lib/participoLib/participo.php @@ -55,7 +55,7 @@ class participo /** lazy loading of the session user */ public static function sessionUser(bool $forceLoading = true) { - if (is_null($sessionUser) || $forceLoading) { + if (is_null(self::$sessionUser) || $forceLoading) { self::$sessionUser = User::loadFromDb(self::getSessionUserId()); } return self::$sessionUser; @@ -250,7 +250,7 @@ class participo 'user' => [ 'username' => $user->getLoginName(), 'userId' => $user->getId(), - 'userConfig' => json_decode($user->getConfig(), true) + 'userConfig' => $user->getConfig() ] ]; diff --git a/homepage/participo/lib/participoLib/shiai.php b/homepage/participo/lib/participoLib/shiai.php index 150a1da..1419556 100644 --- a/homepage/participo/lib/participoLib/shiai.php +++ b/homepage/participo/lib/participoLib/shiai.php @@ -15,10 +15,16 @@ class Shiai private $galleryUrl = null; //< url of the gallery to a gallery of the shiai private $promoImgUrl = null; //< promotional image for the shiai (as url) - public function __construct($id, $date, $name, $ageclasses, $place, $announcementUrl, $routeUrl, $galleryUrl, $promoImgUrl) + /** name of the table in the db holding the Shiai-s + * + * @var string + */ + private static $tableName = "wettkampfkalender"; + + public function __construct($id, $date, $name, $ageclasses, $place, $announcementUrl, $routeUrl, $galleryUrl=null, $promoImgUrl=null) { //! @todo input validation and sanitation - $this->id = (int) $id; + $this->id = filterId($id); $this->date = DateTime::createFromFormat('Y-m-d', $date); $this->name = $name; $this->ageclasses = $ageclasses ? self::akListString2jgArray($ageclasses) : null; @@ -29,6 +35,32 @@ class Shiai $this->promoImgUrl = $promoImgUrl; } + public static function fromArray(array $shiai){ + $id = $shiai['id'] ?? null; + $date = $shiai['date'] ?? null; + $name = $shiai['name'] ?? null; + $ageclasses = $shiai['ageclasses'] ?? null; + $place = $shiai['place'] ?? null; + $announcementUrl = $shiai['announcementUrl'] ?? null; + $routeUrl = $shiai['routeUrl'] ?? null; + // gallery stuff removed for now + + return new Shiai($id, $date, $name, $ageclasses, $place, $announcementUrl, $routeUrl); + } + + public function asArray(){ + return [ + 'id'=>$this->id, + 'date'=>$this->date->format('Y-m-d'), + 'name'=>$this->name, + // @todo at least in theory this should again hold age categories + 'ageclasses'=>implode(" ", $this->ageclasses), + 'place'=>$this->place, + 'announcementUrl'=>$this->announcementUrl, + 'routeUrl'=>$this->announcementUrl + ]; + } + public function getId() { return $this->id; @@ -83,6 +115,17 @@ class Shiai return self::fromDbArray($response[0]); } + /** select shiai from the database + * + * - by default, only coming events will be returned + */ + public static function dbSelect(){ + $query = "SELECT `".self::$tableName."`.* FROM `".self::$tableName."` WHERE `Datum` >= CURDATE();"; + $response = dbConnector::query($query); + + return $response; + } + public static function fromDbArray($member) { return new shiai( diff --git a/homepage/participo/lib/participoLib/user.php b/homepage/participo/lib/participoLib/user.php index e736c40..a5476f0 100644 --- a/homepage/participo/lib/participoLib/user.php +++ b/homepage/participo/lib/participoLib/user.php @@ -75,6 +75,26 @@ class User return dbConnector::getLastInsertId(); } + public static function dbSelectWithAttribute(int $attributeId) + { + $query = + "SELECT DISTINCT" . + " `wkParticipo_Users`.* " . + " FROM `wkParticipo_Users`" . + " JOIN `wkParticipo_user<=>userAttributes`" . + " ON `wkParticipo_user<=>userAttributes`.`userId` = `wkParticipo_Users`.`id`" . + " WHERE `wkParticipo_user<=>userAttributes`.`attributeId` = :attributeId". + " ORDER BY `wkParticipo_Users`.`id` ASC;"; + + $params = [ + ':attributeId' => ['value' => $attributeId, 'data_type' => PDO::PARAM_INT] + ]; + + $response = dbConnector::query($query, $params); + + return $response; + } + /** Name of the table with all the Users * * @var string @@ -139,13 +159,13 @@ class User /** List of users kids */ private $kids = null; - public function kidIds(bool $forceLoading = false) - { - if (is_null($this->kidIds) || $forceLoading) { - $this->kidIds = self::getKidIds($id); - } - return self::$kidIds; - } + // public function kidIds(bool $forceLoading = false) + // { + // if (is_null($this->kidIds) || $forceLoading) { + // $this->kidIds = self::getKidIds($id); + // } + // return self::$kidIds; + // } public function kids(bool $forceLoading = false) { @@ -155,26 +175,26 @@ class User return $this->kids; } - private static function getKidIds(int $id) - { - $response = dbConnector::query( - 'SELECT * FROM `wkParticipo_Users` WHERE `' . $name . '` = :' . $name, - [$name => ['value' => $value, 'data_type' => self::$dbColumns[$name]]] - ); +// private static function getKidIds(int $id) +// { +// $response = dbConnector::query( +// 'SELECT * FROM `wkParticipo_Users` WHERE `' . $name . '` = :' . $name, +// [$name => ['value' => $value, 'data_type' => self::$dbColumns[$name]]] +// ); - $query = << ['value' => $userId, 'data_type' => PDO::PARAM_INT] - ]; - $response = dbConnector::query($query, $params); - return $response; - } +// $query = << ['value' => $userId, 'data_type' => PDO::PARAM_INT] +// ]; +// $response = dbConnector::query($query, $params); +// return $response; +// } /** Export the User data into an associative array * @@ -221,14 +241,21 @@ SQL; return $this->name; } - public function getFirstname() + public function getFirstName() { return $this->firstName; } public function getConfig() { - return $this->$config; + return $this->config; + } + + public function getDateOfBirth(){ + return $this->dateOfBirth; + } + public function getStrBirthday(){ + return $this->dateOfBirth->format("Y-m-d"); } // static functions @@ -305,4 +332,34 @@ SQL; } return User::fromDbArray($response[0]); } + + public static function loadFromDbByAttribute(int $attributeId){ + $query = + "SELECT DISTINCT" . + " `wkParticipo_Users`.* " . + " FROM `wkParticipo_Users`" . + " JOIN `wkParticipo_user<=>userAttributes`" . + " ON `wkParticipo_user<=>userAttributes`.`userId` = `wkParticipo_Users`.`id`" . + " WHERE `wkParticipo_user<=>userAttributes`.`attributeId` = :attributeId". + " ORDER BY `wkParticipo_Users`.`id` ASC;"; + + $response = dbConnector::query( + $query + , [ + 'attributeId'=>[ + 'value'=>filterId($attributeId) + , 'data_type'=>PDO::PARAM_INT] + ] + ); + + // Postprocessing + // - convert the comma separated list into an array + foreach ($response as &$user) { + $user["eMail"] = explode(",", $user["eMail"]); + foreach ($user["eMail"] as &$email) { + $email = trim($email); + } + } + return $response; + } } diff --git a/homepage/participo/package-lock.json b/homepage/participo/package-lock.json new file mode 100644 index 0000000..c92a28a --- /dev/null +++ b/homepage/participo/package-lock.json @@ -0,0 +1,103 @@ +{ + "name": "participo", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "@prettier/plugin-php": "^0.22.1", + "prettier": "^3.1.1" + } + }, + "node_modules/@prettier/plugin-php": { + "version": "0.22.1", + "resolved": "https://registry.npmjs.org/@prettier/plugin-php/-/plugin-php-0.22.1.tgz", + "integrity": "sha512-TN7tzC2/jCM1/H/mlUjqPos8lIV+vm8Qwp83KofuZclGlG9PoUWHU7m0yqskjAoCy+R4ZCV0hxdBLPBkU69S2Q==", + "dev": true, + "dependencies": { + "linguist-languages": "^7.27.0", + "mem": "^9.0.2", + "php-parser": "^3.1.5" + }, + "peerDependencies": { + "prettier": "^3.0.0" + } + }, + "node_modules/linguist-languages": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/linguist-languages/-/linguist-languages-7.27.0.tgz", + "integrity": "sha512-Wzx/22c5Jsv2ag+uKy+ITanGA5hzvBZngrNGDXLTC7ZjGM6FLCYGgomauTkxNJeP9of353OM0pWqngYA180xgw==", + "dev": true + }, + "node_modules/map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "dependencies": { + "p-defer": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/mem": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/mem/-/mem-9.0.2.tgz", + "integrity": "sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==", + "dev": true, + "dependencies": { + "map-age-cleaner": "^0.1.3", + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sindresorhus/mem?sponsor=1" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/php-parser": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/php-parser/-/php-parser-3.1.5.tgz", + "integrity": "sha512-jEY2DcbgCm5aclzBdfW86GM6VEIWcSlhTBSHN1qhJguVePlYe28GhwS0yoeLYXpM2K8y6wzLwrbq814n2PHSoQ==", + "dev": true + }, + "node_modules/prettier": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz", + "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + } + } +} diff --git a/homepage/participo/package.json b/homepage/participo/package.json new file mode 100644 index 0000000..06ec2e3 --- /dev/null +++ b/homepage/participo/package.json @@ -0,0 +1,10 @@ +{ + "devDependencies": { + "@prettier/plugin-php": "^0.22.1", + "prettier": "^3.1.1" + }, + "prettier":{ + "parser": "php", + "plugins": ["@prettier/plugin-php"] + } +} diff --git a/homepage/participo/pmelo.inc.php b/homepage/participo/pmelo.inc.php new file mode 100644 index 0000000..5cfaeb6 --- /dev/null +++ b/homepage/participo/pmelo.inc.php @@ -0,0 +1,179 @@ +var_log($_SESSION, "session"); + // starting/continuing a session + session_start(); + + // create 'pmelo' section in the sessions data + if(!array_key_exists('pmelo', $_SESSION)){ + $_SESSION['pmelo'] = []; + } + // - data storage for id-s of chosen fighters + if(!array_key_exists('fighterIds', $_SESSION['pmelo'])){ + $_SESSION['pmelo']['fighterIds'] = []; + } + + // check for action in post data + if(array_key_exists('pmelo', $_POST)){ + if(array_key_exists('fighterIds', $_POST['pmelo'])){ + $_SESSION['pmelo']['fighterIds']=$_POST['pmelo']['fighterIds']; + } + // $this->var_log($_SESSION, "session"); + } + + // load/recreate ranking data + if(!is_file(self::$pmeloJson)){ + $this->log['info'][] = "Couldn't find `".self::$pmeloJson."`. Create a new one!"; + file_put_contents(self::$pmeloJson, json_encode([])); + } + + // init members + $this->trainees = self::getTrainees(); + $this->var_log(array_map(function($user){return $user->getFirstName();},$this->trainees), "trainees from db"); + $this->rankings = $this->createRankings(); + $this->var_log(array_map(function($id){return $this->trainees[$id]->getFirstName();},$this->rankings), "current ranking"); + $this->fighters = []; + foreach($_SESSION['pmelo']['fighterIds'] as $id){ + $this->fighters[$id] = $this->trainees[$id]; + }; + $this->var_log(array_map(function($user){return $user->getFirstName();},$this->fighters), "fighters"); + + + // save the updated ranking + // @todo should be in destructor + self::saveRankings($this->rankings); + } + + function __destruct(){ + // sad, the destructor is not allowed to use file_put_contents + } + + // load all active trainees into a id=>User assoc array + public static function getTrainees(){ + $traineeList = array_map('User::fromDbArray', User::dbSelectWithAttribute(4)); + $traineeAssocArray = []; + foreach($traineeList as $trainee){ + $traineeAssocArray[$trainee->getId()] = $trainee; + } + return $traineeAssocArray; + } + + // load ranking from json file + public static function loadRankings(){ + return json_decode(file_get_contents(self::$pmeloJson)); + } + + // save a ranking to json file + public static function saveRankings(array $rankings){ + file_put_contents(self::$pmeloJson, json_encode($rankings)); + } + + // simple logger to a logging buffer + function var_log($variable, string $prefix=null, string $logChannel='info'){ + if(!in_array($logChannel, ['info', 'warning', 'error'])){ + $logChannel='info'; + } + $prefix = (!empty($prefix) ? $prefix.": " : ""); + $this->log[$logChannel][]=$prefix.var_export($variable, true); + } + + // create the ranking for the current session (load saved ranking from file, remove old trainees, add new trainees) + public function createRankings(){ + // load the last state of the ranking + $loadedRanking = self::loadRankings(); + $this->var_log(array_map(function($id){$user=$this->trainees[$id]; return $user->getFirstName();}, $loadedRanking), "loaded ranking"); + + // check if the ranked trainees still are in training + // - the ranking with + $cleanRanking = []; + // - trainees that aren't currently in the ranking for later inserting + $toBeInsertedTrainees = $this->trainees; + foreach($loadedRanking as $id){ + if(array_key_exists($id, $this->trainees)){ + // userId is still in training, so append it to the cleaned up ranking + $cleanRanking[] = $id; + // trainees already in the ranking we won't have to insert manual + unset($toBeInsertedTrainees[$id]); + } + } + + // get the ids of the to be inserted trainees sorted by the birthday + $newTraineesIds = array_map(function($u){return $u->getId();},$toBeInsertedTrainees); + usort( + $newTraineesIds + , function($lhs, $rhs){ + return $this->trainees[$lhs]->getStrBirthday() < $this->trainees[$rhs]->getStrBirthday() ? -1 : ($this->trainees[$lhs]->getStrBirthday() > $this->trainees[$rhs]->getStrBirthday() ? 1 : 0); + } + ); + // $this->var_log( + // array_map( + // function($id){return $this->trainees[$id]->getStrBirthday()." ".$this->trainees[$id]->getFirstName();} + // , $newTraineesIds + // ) + // , "newTraineesBy B-Day" + // ); + + // now we do a mergesort (step) + $updatedRanking = []; + $idxNewTrainees = count($newTraineesIds)-1; + $idxRanking = count($cleanRanking)-1; + // - while we can merge, we merge + while( ($idxRanking >= 0) && ($idxNewTrainees >= 0) ){ + // $this->var_log( [$idxRanking.", ".$idxNewTrainees=>$updatedRanking] ); + // $this->var_log( + // [$this->trainees[$cleanRanking[$idxRanking]]->getStrBirthday(), $this->trainees[$newTraineesIds[$idxRanking]]->getStrBirthday()] + // ); + if( + $this->trainees[$cleanRanking[$idxRanking]]->getDateOfBirth() + > $this->trainees[$newTraineesIds[$idxNewTrainees]]->getDateOfBirth() + ){ + // $this->var_log( $this->trainees[$cleanRanking[$idxRanking]]->getFirstName(), "merge ranking insert" ); + array_unshift($updatedRanking, $cleanRanking[$idxRanking]); + $idxRanking-=1; + }else{ + // $this->var_log( $this->trainees[$newTraineesIds[$idxNewTrainees]]->getFirstName(), "merge trainees insert" ); + array_unshift($updatedRanking, $newTraineesIds[$idxNewTrainees]); + $idxNewTrainees-=1; + } + } + // $this->var_log( + // ["idxR ".$idxRanking." idxNT ".$idxNewTrainees=>[$cleanRanking, $newTraineesIds]] + // , "after merge" + // ); + while( $idxRanking >= 0 ){ + // $this->var_log( $this->trainees[$cleanRanking[$idxRanking]]->getFirstName(), "rest ranking insert" ); + array_unshift($updatedRanking, $cleanRanking[$idxRanking]); + $idxRanking-=1; + } + while( $idxNewTrainees >= 0 ){ + // $this->var_log( $this->trainees[$newTraineesIds[$idxNewTrainees]]->getFirstName(), "rest newTrainees insert" ); + array_unshift($updatedRanking, $newTraineesIds[$idxNewTrainees]); + $idxNewTrainees-=1; + } + return $updatedRanking; + } + + public $log = ['error'=>[], 'warning'=>[], 'info'=>[]]; + public $fighters = null; + public $trainees = null; + // list of id-s in the order of the current ranking + public $rankings = null; + + static $pmeloJson="./pmeloRanking.json"; +} \ No newline at end of file diff --git a/homepage/participo/pmelo.php b/homepage/participo/pmelo.php new file mode 100644 index 0000000..da60dfb --- /dev/null +++ b/homepage/participo/pmelo.php @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + participo + + + + + + + +
+ + +
+ +
+

pmElo

+ +
+
+ + + +
+
+ + + + + + + fighters)){ + foreach($pmelo->rankings as $rank=>$id){ + if(array_key_exists($id, $pmelo->fighters)){ + $fighter = $pmelo->fighters[$id]; + // echo("".PHP_EOL); + echo("".PHP_EOL); + } + } +} + ?> + +
PlatzNameAufstieg
".$rank."".$fighter->getFirstName()."
".$rank."".$fighter->getFirstName()." ".$fighter->getName()."^
+ +
    +
  • Logs

  • +log as $logLevel=>$messages){ + if(!empty($messages)){ +?> +
  • +
      +
    • + +
    • + +
    • + +
    +
  • + + +
+
+ + diff --git a/homepage/participo/testApi.py b/homepage/participo/testApi.py new file mode 100755 index 0000000..a43325c --- /dev/null +++ b/homepage/participo/testApi.py @@ -0,0 +1,132 @@ +#! /usr/bin/env python + +import logging +import json + + +class TestApi: + @staticmethod + def __parse_arguments(): + import argparse + + argParser = argparse.ArgumentParser( + "testApi" + ) + argParser.add_argument( + "method", + choices=['GET', 'POST'] + ) + argParser.add_argument( + "--endpoint", + default="shiai" + ) + argParser.add_argument( + "--host", + default="cwsvjudo.bplaced.net" + ) + argParser.add_argument( + "--path", + default="participo/api" + ) + argParser.add_argument( + "--key", + default=None + ) + argParser.add_argument( + "--configFile", + type=argparse.FileType('r'), + default="testApi.config.yaml" + ) + _LOG_LEVEL = ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"] + argParser.add_argument( + "--logLevel", + choices=_LOG_LEVEL, + default="WARNING" + ) + argParser.add_argument( + "--input", "-i", + type=argparse.FileType("r"), + default="-" + ) + + return argParser.parse_args() + + def __init__(self): + self.config = self.__parse_arguments() + self.config.logLevel = getattr(logging, self.config.logLevel) + logging.basicConfig(level=self.config.logLevel) + + with self.config.configFile as cf: + from yaml import safe_load + configData = safe_load(cf) + + # @todo: add the attributes from the config file to the config (if not + # already set) + if not self.config.key and 'apiKey' in configData: + self.config.key = configData['apiKey'] + + def apiCall(self): + return apiCall.call( + method=self.config.method, + host=self.config.host, + url="/".join([self.config.path, self.config.endpoint]), + headers={ + "Authorization": f"Basic {self.config.key}" + }, + input=load_json(self.config.input) + ) + + +def load_json(jsonFile): + import json + with jsonFile as f: + return json.load(f) + +class apiCall: + @staticmethod + def call( + method: str, + host: str, + url: str, + headers: dict = None, + input: dict = None, + ) -> dict: + import requests + + if(method=="GET"): + r = requests.get( + url=f"http://{host}/{url}", + timeout=10, + headers=headers + ) + elif(method=="POST"): + r = requests.post( + json=input, + url=f"http://{host}/{url}", + timeout=10, + headers=headers + ) + else: + logging.error("This line should never been reached!") + + try: + return r.json() + except Exception as e: + logging.error(f"Exception {repr(e)} ({e}) while parsing json:") + logging.error(r.text) + + +if __name__ == "__main__": + testApi = TestApi() + + response = testApi.apiCall() + + try: + print( + json.dumps( + response, + indent=2 + ) + ) + except Exception as e: + logging.error(f"Exception {repr(e)} ({e}) while parsing json:") diff --git a/homepage/participo/wk.api.php b/homepage/participo/wk.api.php index a512f4e..bee2c7b 100644 --- a/homepage/participo/wk.api.php +++ b/homepage/participo/wk.api.php @@ -13,7 +13,6 @@ $db = dbConnector::connect( $cwsvJudoConfig['db']['user'], $cwsvJudoConfig['db']['password'] ); -echo($db); $wkSqlQuery = 'SELECT * FROM `wettkampfkalender` WHERE `Datum` >= CURDATE();'; $wkSqlResponse = dbConnector::query($wkSqlQuery); @@ -22,3 +21,4 @@ header('Access-Control-Allow-Headers: *'); header('Access-Control-Allow-Origin: *'); echo(json_encode($wkSqlResponse)); +?> \ No newline at end of file diff --git a/infoZettelOrg/Makefile b/infoZettelOrg/Makefile index 096d549..7f53d09 100644 --- a/infoZettelOrg/Makefile +++ b/infoZettelOrg/Makefile @@ -2,6 +2,7 @@ include Makefile.private infoZettel=$(patsubst %.md,%.pdf,$(wildcard *.md)) infoZettel-2x2=$(patsubst %.md,%-2x2.pdf,$(wildcard *.md)) +infoZettel-booklet=$(patsubst %.md,%-booklet.pdf,$(wildcard *.md)) wkZettel=$(patsubst %.md,%.pdf,$(wildcard wkZettel/*.md)) wkZettel-2x2=$(patsubst %.md,%-2x2.pdf,$(wildcard wkZettel/*.md)) kyuZettel=$(patsubst %.md,%.pdf,$(wildcard kyuZettel/*.md)) @@ -37,7 +38,7 @@ aushaenge: $(aushaenge) --variable classoption="twoside=true" \ --variable classoption="DIV=28" \ --variable classoption="BCOR=0mm" \ - --variable classoption="paper=A6" \ + --variable classoption="paper=A5" \ --variable classoption="fontsize=10pt" \ --variable classoption="parskip=never" \ --variable classoption="headsepline=true" \ @@ -48,7 +49,10 @@ aushaenge: $(aushaenge) $^ %-2x2.pdf: %.pdf - pdfjam --no-landscape --nup 2x2 --suffix '2x2' $^ '1,1,1,1,2,2,2,2' --outfile $@ + pdfjam --no-landscape --nup 2x1 --suffix '2x2' $^ '2,3,1,4,2,2,2,2' --outfile $@ + +%-booklet.pdf: %.pdf + pdfjam --landscape --nup 2x1 --suffix 'booklet' $^ '2,3,1,4' --outfile $@ aushang/%.pdf: aushang/%.md pandoc \ diff --git a/submodules/Makefile b/submodules/Makefile index 1dff116..f17068a 100644 --- a/submodules/Makefile +++ b/submodules/Makefile @@ -4,7 +4,7 @@ include passwords .PHONY: updateSubmodules updateSubmodules: checkoutSubmodulesDefaultBranches git submodule foreach git pull - + .PHONY: checkoutSubmodulesDefaultBranches: git -C lite-youtube-embed checkout master @@ -13,12 +13,11 @@ checkoutSubmodulesDefaultBranches: git -C spyc checkout master git -C zopfli checkout master - .PHONY: buildMaterialize buildMaterialize: updateSubmodules ./buildMaterialize.sh .PHONY: deployMaterialize -# deployMaterialize: buildMaterialize -deployMaterialize: $(materialiceCssDist) - cd materialize/dist/ && find . -type f -exec curl --verbose -u cwsvjudo:$(ftpPassword) --ftp-create-dirs -T {} ftp://cwsvjudo.bplaced.net/www/ressourcen/materializeCss/{} \; \ No newline at end of file +deployMaterialize: buildMaterialize + # @todo correctly check the cert + lftp -e "set ftp:ssl-allow no; mirror -R 'materialize/dist' 'www/ressourcen/materializeCss'; bye;" -u cwsvjudo,$(ftpPassword) cwsvjudo.bplaced.net diff --git a/submodules/lite-youtube-embed b/submodules/lite-youtube-embed index be6f03e..f9fc3a2 160000 --- a/submodules/lite-youtube-embed +++ b/submodules/lite-youtube-embed @@ -1 +1 @@ -Subproject commit be6f03ef53b33866e38a917a256cefca95262804 +Subproject commit f9fc3a2475ade166d0cf7bb3e3caa3ec236ee74e diff --git a/submodules/materialize b/submodules/materialize index bf29da7..68e5224 160000 --- a/submodules/materialize +++ b/submodules/materialize @@ -1 +1 @@ -Subproject commit bf29da7b2a234ec3d3428b7585d5ac7f724541f2 +Subproject commit 68e5224811ba6b568316de60da5af66d9a569a48 diff --git a/submodules/parsedown b/submodules/parsedown index 6598f38..77947ed 160000 --- a/submodules/parsedown +++ b/submodules/parsedown @@ -1 +1 @@ -Subproject commit 6598f3860c2698fe2f0f1bc98212fc01d0a1893c +Subproject commit 77947eda2fdaf06b181c63a7db13e38968306aee diff --git a/tShirts/tShirts.2023/groessen.gnumeric b/tShirts/tShirts.2023/groessen.gnumeric index d5f2570..ee1da88 100644 Binary files a/tShirts/tShirts.2023/groessen.gnumeric and b/tShirts/tShirts.2023/groessen.gnumeric differ