From 868c05f0c1485046b549b1bb233ed96fdb23480b Mon Sep 17 00:00:00 2001 From: marko Date: Sat, 23 Dec 2023 14:32:48 +0100 Subject: [PATCH 01/16] added eventpage (not in linkstructure yet) --- homepage/participo/event.php | 47 ++++++++++++++++++ homepage/participo/lib/participoLib/event.php | 3 ++ homepage/participo/wk.api.php | 2 +- infoZettelOrg/Makefile | 8 ++- submodules/Makefile | 9 ++-- submodules/lite-youtube-embed | 2 +- submodules/materialize | 2 +- submodules/parsedown | 2 +- tShirts/tShirts.2023/groessen.gnumeric | Bin 2849 -> 3713 bytes 9 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 homepage/participo/event.php diff --git a/homepage/participo/event.php b/homepage/participo/event.php new file mode 100644 index 0000000..a74d301 --- /dev/null +++ b/homepage/participo/event.php @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + <?php echo($meta['title']); ?> + + + + + + + + +
+ + +
+ +
+ html(); ?> +
+ + + \ No newline at end of file diff --git a/homepage/participo/lib/participoLib/event.php b/homepage/participo/lib/participoLib/event.php index 5906ddc..5328cce 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/wk.api.php b/homepage/participo/wk.api.php index a512f4e..2c307eb 100644 --- a/homepage/participo/wk.api.php +++ b/homepage/participo/wk.api.php @@ -13,7 +13,7 @@ $db = dbConnector::connect( $cwsvJudoConfig['db']['user'], $cwsvJudoConfig['db']['password'] ); -echo($db); +// echo($db); $wkSqlQuery = 'SELECT * FROM `wettkampfkalender` WHERE `Datum` >= CURDATE();'; $wkSqlResponse = dbConnector::query($wkSqlQuery); 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 d5f257058393ae47d26f7248c565783a6f60ce06..ee1da88da08859a18e9b6f6870d1d8546aecfc93 100644 GIT binary patch literal 3713 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 literal 2849 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 Date: Sat, 23 Dec 2023 14:54:48 +0100 Subject: [PATCH 02/16] develop version for new api concept --- homepage/participo/api/users.php | 40 ++++++++++++++++++++++++++++++++ homepage/participo/testApi.py | 33 ++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 homepage/participo/api/users.php create mode 100644 homepage/participo/testApi.py diff --git a/homepage/participo/api/users.php b/homepage/participo/api/users.php new file mode 100644 index 0000000..c81cb29 --- /dev/null +++ b/homepage/participo/api/users.php @@ -0,0 +1,40 @@ +isValidFor('api')) { + die(json_encode(['success' => false])); +} + +$wkSqlQuery = 'SELECT * FROM `wettkampfkalender` WHERE `Datum` >= CURDATE();'; +$wkSqlResponse = dbConnector::query($wkSqlQuery); + +header('Access-Control-Allow-Headers: *'); +header('Access-Control-Allow-Origin: *'); + +echo( + json_encode($wkSqlResponse) + // json_encode(getallheaders()) + // json_encode($_SERVER) +); diff --git a/homepage/participo/testApi.py b/homepage/participo/testApi.py new file mode 100644 index 0000000..1b37554 --- /dev/null +++ b/homepage/participo/testApi.py @@ -0,0 +1,33 @@ +from http import client +import logging +import json +import yaml + +host="cwsvjudo.bplaced.net" + +with open("testApi.config.yaml", "r") as f: + config = yaml.load(f) + +logging.basicConfig(level=logging.DEBUG) + +connection = client.HTTPConnection(host=host, port=80, timeout=1) +connection.request( + method="GET", + url="/participo/api/users", + headers={ + "Authorization": f"Basic {config['apiKey']}" + } +) +response = connection.getresponse() + +print("Status: {} and reason: {}".format(response.status, response.reason)) + +body = response.read() +try: + print(json.dumps(json.loads(body),indent=2)) +except: + print(f"failed to parse to json") + print(body + ) + +connection.close() From 9ab62485a63e6838b6e4236a1b262af9848c64e5 Mon Sep 17 00:00:00 2001 From: marko Date: Sun, 24 Dec 2023 15:34:07 +0100 Subject: [PATCH 03/16] api endpoint returns actives parents by default --- homepage/participo/api/users.php | 15 ++++++++++++++- homepage/participo/testApi.py | 5 +++-- homepage/participo/wk.api.php | 1 - 3 files changed, 17 insertions(+), 4 deletions(-) mode change 100644 => 100755 homepage/participo/testApi.py diff --git a/homepage/participo/api/users.php b/homepage/participo/api/users.php index c81cb29..ffeb110 100644 --- a/homepage/participo/api/users.php +++ b/homepage/participo/api/users.php @@ -27,9 +27,22 @@ if (!$allowKey || !$allowKey->isValidFor('api')) { die(json_encode(['success' => false])); } -$wkSqlQuery = 'SELECT * FROM `wettkampfkalender` WHERE `Datum` >= CURDATE();'; +$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); +foreach( $wkSqlResponse as &$user){ + $user['eMail'] = explode(",", $user['eMail']); +} + header('Access-Control-Allow-Headers: *'); header('Access-Control-Allow-Origin: *'); diff --git a/homepage/participo/testApi.py b/homepage/participo/testApi.py old mode 100644 new mode 100755 index 1b37554..5ef39d2 --- a/homepage/participo/testApi.py +++ b/homepage/participo/testApi.py @@ -1,3 +1,5 @@ +#! /usr/bin/env python + from http import client import logging import json @@ -27,7 +29,6 @@ try: print(json.dumps(json.loads(body),indent=2)) except: print(f"failed to parse to json") - print(body - ) + print(body) connection.close() diff --git a/homepage/participo/wk.api.php b/homepage/participo/wk.api.php index 2c307eb..3afe702 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); From 38cc02120c6cbbcd3270a12200426660275aa7f7 Mon Sep 17 00:00:00 2001 From: marko Date: Sun, 24 Dec 2023 19:46:49 +0100 Subject: [PATCH 04/16] wip: rest api user endpoint --- homepage/participo/.vscode/sftp.json | 3 +- homepage/participo/api/users.php | 18 +++++--- homepage/participo/testApi.py | 66 ++++++++++++++++++---------- homepage/participo/wk.api.php | 1 + 4 files changed, 60 insertions(+), 28 deletions(-) diff --git a/homepage/participo/.vscode/sftp.json b/homepage/participo/.vscode/sftp.json index 447647d..39cd462 100644 --- a/homepage/participo/.vscode/sftp.json +++ b/homepage/participo/.vscode/sftp.json @@ -7,7 +7,8 @@ "remotePath": "/www/participo", "ignore": [ ".vscode", - "*.py" + "*.py", + "*.config.yaml" ], "uploadOnSave": true } \ No newline at end of file diff --git a/homepage/participo/api/users.php b/homepage/participo/api/users.php index ffeb110..c30f7af 100644 --- a/homepage/participo/api/users.php +++ b/homepage/participo/api/users.php @@ -39,15 +39,23 @@ $wkSqlQuery = "SELECT DISTINCT" $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); + } } -header('Access-Control-Allow-Headers: *'); -header('Access-Control-Allow-Origin: *'); - +// Sending Response +// - setting header +header('Content-Type: application/json'); +// - sending body payload echo( json_encode($wkSqlResponse) - // json_encode(getallheaders()) - // json_encode($_SERVER) ); + +// @todo Should not be necessary. But until the problem with the timeout time of the requesting client is solved, this explicit exit() stands! +exit(0); +?> \ No newline at end of file diff --git a/homepage/participo/testApi.py b/homepage/participo/testApi.py index 5ef39d2..b84fa23 100755 --- a/homepage/participo/testApi.py +++ b/homepage/participo/testApi.py @@ -3,32 +3,54 @@ from http import client import logging import json -import yaml -host="cwsvjudo.bplaced.net" -with open("testApi.config.yaml", "r") as f: - config = yaml.load(f) +def init(): + logging.basicConfig(level=logging.DEBUG) + with open("testApi.config.yaml", "r") as f: + from yaml import safe_load + config = safe_load(f) + + return config -logging.basicConfig(level=logging.DEBUG) -connection = client.HTTPConnection(host=host, port=80, timeout=1) -connection.request( - method="GET", - url="/participo/api/users", - headers={ - "Authorization": f"Basic {config['apiKey']}" - } -) -response = connection.getresponse() +class apiCall: + @staticmethod + def call( + host: str, + url: str, + headers: dict = None + ) -> dict: + import requests -print("Status: {} and reason: {}".format(response.status, response.reason)) + r = requests.get( + url=f"http://{host}/{url}", + # @todo The client always awaits this timeout. Even when the meaningful body is already received.params= + # - I don't see any of the examples out there do it different from me. + # - The browser doesn't seem to have this problem. + timeout=10, + headers=headers + ) -body = response.read() -try: - print(json.dumps(json.loads(body),indent=2)) -except: - print(f"failed to parse to json") - print(body) + try: + return r.json() + except: + logging.error(f"failed to parse json: {r.text}") -connection.close() +if __name__ == "__main__": + config = init() + + response = apiCall.call( + host=config["host"], + url="participo/api/users", + # url = "participo/api", + headers={ + "Authorization": f"Basic {config['apiKey']}" + } + ) + + try: + logging.info(json.dumps(response,indent=2)) + except: + logging.error(f"failed to parse to json:") + logging.error(response) diff --git a/homepage/participo/wk.api.php b/homepage/participo/wk.api.php index 3afe702..bee2c7b 100644 --- a/homepage/participo/wk.api.php +++ b/homepage/participo/wk.api.php @@ -21,3 +21,4 @@ header('Access-Control-Allow-Headers: *'); header('Access-Control-Allow-Origin: *'); echo(json_encode($wkSqlResponse)); +?> \ No newline at end of file From 49978a48df0b714ed4e4296f5ac9e5dbcde2b4b0 Mon Sep 17 00:00:00 2001 From: marko Date: Mon, 25 Dec 2023 11:13:26 +0100 Subject: [PATCH 05/16] wip: participo rest api `users` endpoint --- homepage/participo/api/users.php | 79 ++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/homepage/participo/api/users.php b/homepage/participo/api/users.php index c30f7af..2e50205 100644 --- a/homepage/participo/api/users.php +++ b/homepage/participo/api/users.php @@ -7,52 +7,61 @@ require_once 'local/cwsvJudo.php'; require_once 'participoLib/participo.php'; +$db = dbConnector::connect( + $cwsvJudoConfig['db']['host'], + $cwsvJudoConfig['db']['name'], + $cwsvJudoConfig['db']['user'], + $cwsvJudoConfig['db']['password'] +); -if(array_key_exists("HTTP_AUTHORIZATION", $_SERVER)){ - if(!empty($_SERVER["HTTP_AUTHORIZATION"])){ - $auth = explode(" ", $_SERVER["HTTP_AUTHORIZATION"]); - if($auth[0]="Basic"){ - $db = dbConnector::connect( - $cwsvJudoConfig['db']['host'], - $cwsvJudoConfig['db']['name'], - $cwsvJudoConfig['db']['user'], - $cwsvJudoConfig['db']['password'] - ); - $allowKey = ApiKey::loadFromDb($auth[1]); +function authorize(){ + if(array_key_exists("HTTP_AUTHORIZATION", $_SERVER)){ + if(!empty($_SERVER["HTTP_AUTHORIZATION"])){ + $auth = explode(" ", $_SERVER["HTTP_AUTHORIZATION"]); + if($auth[0]="Basic"){ + $allowKey = ApiKey::loadFromDb($auth[1]); + } } } -} -if (!$allowKey || !$allowKey->isValidFor('api')) { - die(json_encode(['success' => false])); -} - -$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); + if (!$allowKey || !$allowKey->isValidFor('api')) { + die(json_encode(['success' => false])); } } +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; +} + +authorize(); +$wkSqlResponse = get(); + // Sending Response // - setting header header('Content-Type: application/json'); // - sending body payload -echo( +// @todo die() seems to be more a error handling function. But echo+exit doesn't seem to close the connection (?). What leads to pythons requests.get() always wait for the complete timeout. +die( json_encode($wkSqlResponse) ); From f2cf7ff7640511afbd8a3325858e719e19fa9963 Mon Sep 17 00:00:00 2001 From: marko Date: Tue, 26 Dec 2023 20:24:34 +0100 Subject: [PATCH 06/16] wip: added rest api endpoint shiai --- homepage/participo/.gitignore | 4 +- homepage/participo/.vscode/settings.json | 11 +- homepage/participo/.vscode/sftp.json | 4 +- homepage/participo/api/inc/.htaccess | 1 + homepage/participo/api/inc/bootstrap.php | 31 ++++++ homepage/participo/api/shiai.php | 14 +++ homepage/participo/api/users.php | 87 ++++++++------- .../participo/lib/participoLib/apiKey.php | 2 +- .../lib/participoLib/dbConnector.php | 5 +- homepage/participo/lib/participoLib/shiai.php | 17 +++ homepage/participo/package-lock.json | 103 ++++++++++++++++++ homepage/participo/package.json | 10 ++ 12 files changed, 245 insertions(+), 44 deletions(-) create mode 100644 homepage/participo/api/inc/.htaccess create mode 100644 homepage/participo/api/inc/bootstrap.php create mode 100644 homepage/participo/api/shiai.php create mode 100644 homepage/participo/package-lock.json create mode 100644 homepage/participo/package.json 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/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 39cd462..fbe7d1e 100644 --- a/homepage/participo/.vscode/sftp.json +++ b/homepage/participo/.vscode/sftp.json @@ -8,7 +8,9 @@ "ignore": [ ".vscode", "*.py", - "*.config.yaml" + "*.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..3ce6c3c --- /dev/null +++ b/homepage/participo/api/inc/bootstrap.php @@ -0,0 +1,31 @@ + diff --git a/homepage/participo/api/users.php b/homepage/participo/api/users.php index 2e50205..93820b4 100644 --- a/homepage/participo/api/users.php +++ b/homepage/participo/api/users.php @@ -1,70 +1,81 @@ isValidFor('api')) { - die(json_encode(['success' => false])); + if (!$allowKey || !$allowKey->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;"; +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){ + 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'); +header("Content-Type: application/json"); // - sending body payload -// @todo die() seems to be more a error handling function. But echo+exit doesn't seem to close the connection (?). What leads to pythons requests.get() always wait for the complete timeout. -die( - json_encode($wkSqlResponse) -); +echo json_encode($wkSqlResponse); -// @todo Should not be necessary. But until the problem with the timeout time of the requesting client is solved, this explicit exit() stands! -exit(0); -?> \ No newline at end of file +// exit(0); + +?> 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/shiai.php b/homepage/participo/lib/participoLib/shiai.php index 150a1da..ab59543 100644 --- a/homepage/participo/lib/participoLib/shiai.php +++ b/homepage/participo/lib/participoLib/shiai.php @@ -15,6 +15,12 @@ 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) + /** 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, $promoImgUrl) { //! @todo input validation and sanitation @@ -83,6 +89,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/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"] + } +} From 13ea342be80bb0a7531232c9a1feaeb60b72d796 Mon Sep 17 00:00:00 2001 From: marko Date: Sat, 30 Dec 2023 11:09:06 +0100 Subject: [PATCH 07/16] refactoring testApi --- homepage/participo/api/index.php | 13 +++++ homepage/participo/api/shiai.php | 6 ++- homepage/participo/testApi.py | 83 ++++++++++++++++++++++++-------- 3 files changed, 81 insertions(+), 21 deletions(-) create mode 100644 homepage/participo/api/index.php 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 index aa1a4aa..e024153 100644 --- a/homepage/participo/api/shiai.php +++ b/homepage/participo/api/shiai.php @@ -8,7 +8,9 @@ require_once("participoLib/shiai.php"); // - we send a json-formatted response header("Content-Type: application/json"); // - sending body payload -echo json_encode( - Shiai::dbSelect() +echo( + json_encode( + Shiai::dbSelect() + ) ); ?> diff --git a/homepage/participo/testApi.py b/homepage/participo/testApi.py index b84fa23..0880793 100755 --- a/homepage/participo/testApi.py +++ b/homepage/participo/testApi.py @@ -5,14 +5,60 @@ import logging import json -def init(): - logging.basicConfig(level=logging.DEBUG) - with open("testApi.config.yaml", "r") as f: - from yaml import safe_load - config = safe_load(f) - - return config +class TestApi: + @staticmethod + def __parse_arguments(): + import argparse + argParser = argparse.ArgumentParser( + "testApi" + ) + + 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" + ) + + 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( + host=self.config.host, + url="/".join([self.config.path, self.config.endpoint]), + headers={ + "Authorization": f"Basic {self.config.key}" + } + ) class apiCall: @staticmethod @@ -37,20 +83,19 @@ class apiCall: except: logging.error(f"failed to parse json: {r.text}") -if __name__ == "__main__": - config = init() - response = apiCall.call( - host=config["host"], - url="participo/api/users", - # url = "participo/api", - headers={ - "Authorization": f"Basic {config['apiKey']}" - } - ) +if __name__ == "__main__": + testApi = TestApi() + + response = testApi.apiCall() try: - logging.info(json.dumps(response,indent=2)) + print( + json.dumps( + response, + indent=2 + ) + ) except: - logging.error(f"failed to parse to json:") + logging.error("failed to parse to json:") logging.error(response) From d285f2ba2cb746125ce5adb62a592e831849773f Mon Sep 17 00:00:00 2001 From: marko Date: Sun, 31 Dec 2023 07:39:34 +0100 Subject: [PATCH 08/16] pep8 --- homepage/participo/testApi.py | 47 +++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/homepage/participo/testApi.py b/homepage/participo/testApi.py index 0880793..b31824e 100755 --- a/homepage/participo/testApi.py +++ b/homepage/participo/testApi.py @@ -1,12 +1,11 @@ #! /usr/bin/env python -from http import client import logging import json class TestApi: - @staticmethod + @staticmethod def __parse_arguments(): import argparse @@ -14,30 +13,36 @@ class TestApi: "testApi" ) - argParser.add_argument("--endpoint", + argParser.add_argument( + "--endpoint", default="shiai" ) - argParser.add_argument("--host", + argParser.add_argument( + "--host", default="cwsvjudo.bplaced.net" ) - argParser.add_argument("--path", + argParser.add_argument( + "--path", default="participo/api" ) - argParser.add_argument("--key", + argParser.add_argument( + "--key", default=None ) - argParser.add_argument("--configFile", + argParser.add_argument( + "--configFile", type=argparse.FileType('r'), default="testApi.config.yaml" - ) + ) _LOG_LEVEL = ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"] - argParser.add_argument("--logLevel", + argParser.add_argument( + "--logLevel", choices=_LOG_LEVEL, default="WARNING" ) return argParser.parse_args() - + def __init__(self): self.config = self.__parse_arguments() self.config.logLevel = getattr(logging, self.config.logLevel) @@ -46,8 +51,9 @@ class TestApi: 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) + + # @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'] @@ -60,6 +66,7 @@ class TestApi: } ) + class apiCall: @staticmethod def call( @@ -71,8 +78,10 @@ class apiCall: r = requests.get( url=f"http://{host}/{url}", - # @todo The client always awaits this timeout. Even when the meaningful body is already received.params= - # - I don't see any of the examples out there do it different from me. + # @todo The client always awaits this timeout. Even when the + # meaningful body is already received.params= + # - I don't see any of the examples out there do it different from + # me. # - The browser doesn't seem to have this problem. timeout=10, headers=headers @@ -80,8 +89,9 @@ class apiCall: try: return r.json() - except: - logging.error(f"failed to parse json: {r.text}") + except Exception as e: + logging.error(f"Exception {repr(e)} ({e}) while parsing json:") + logging.error(r.text) if __name__ == "__main__": @@ -96,6 +106,5 @@ if __name__ == "__main__": indent=2 ) ) - except: - logging.error("failed to parse to json:") - logging.error(response) + except Exception as e: + logging.error(f"Exception {repr(e)} ({e}) while parsing json:") From 9cd4eb3226018bc32b5a00c580faaa9a8a6124ad Mon Sep 17 00:00:00 2001 From: marko Date: Mon, 1 Jan 2024 10:07:48 +0100 Subject: [PATCH 09/16] added trainees endpoint --- homepage/participo/api/inc/bootstrap.php | 21 +++++++++++++ homepage/participo/api/trainees.php | 38 ++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 homepage/participo/api/trainees.php diff --git a/homepage/participo/api/inc/bootstrap.php b/homepage/participo/api/inc/bootstrap.php index 3ce6c3c..9836fb3 100644 --- a/homepage/participo/api/inc/bootstrap.php +++ b/homepage/participo/api/inc/bootstrap.php @@ -22,6 +22,27 @@ require_once("local/cwsvJudo.php"); /// - since this is a rest api implementation we can assume each endpoint needs dbAccess require_once("participoLib/dbConnector.php"); +function authorize() +{ + if (array_key_exists("HTTP_AUTHORIZATION", $_SERVER)) { + if (!empty($_SERVER["HTTP_AUTHORIZATION"])) { + $auth = explode(" ", $_SERVER["HTTP_AUTHORIZATION"]); + if ($auth[0] = "Basic") { + $allowKey = ApiKey::loadFromDb($auth[1]); + } + } + } + + if (!$allowKey || !$allowKey->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"], diff --git a/homepage/participo/api/trainees.php b/homepage/participo/api/trainees.php new file mode 100644 index 0000000..358fde3 --- /dev/null +++ b/homepage/participo/api/trainees.php @@ -0,0 +1,38 @@ +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); From 14108660f9c9e7fd8ac44c5e44edaa2e39e7f810 Mon Sep 17 00:00:00 2001 From: marko Date: Sun, 7 Jan 2024 18:36:43 +0100 Subject: [PATCH 10/16] WIP: posting shiai to the wkKalendar via api --- homepage/participo/.vscode/launch.json | 20 +++++++ homepage/participo/api/shiai.php | 54 ++++++++++++++++--- .../participo/lib/participoLib/participo.php | 2 +- homepage/participo/lib/participoLib/shiai.php | 30 ++++++++++- homepage/participo/lib/participoLib/user.php | 20 +++++++ homepage/participo/testApi.py | 48 ++++++++++++----- 6 files changed, 150 insertions(+), 24 deletions(-) create mode 100644 homepage/participo/.vscode/launch.json 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/api/shiai.php b/homepage/participo/api/shiai.php index e024153..54d199c 100644 --- a/homepage/participo/api/shiai.php +++ b/homepage/participo/api/shiai.php @@ -3,14 +3,52 @@ require_once("inc/bootstrap.php"); require_once("participoLib/shiai.php"); +$method = $_SERVER['REQUEST_METHOD']; + // Sending Response -// - setting header -// - we send a json-formatted response +// - we send a json-formatted response header("Content-Type: application/json"); -// - sending body payload -echo( - json_encode( - Shiai::dbSelect() - ) -); +// - check if an valid api key was send +authorize(); +// - depending on the method we perform different actions +switch($method){ + // Create + case 'POST': + $postData = json_decode(file_get_contents('php://input'), true); + if(!$postData){ + die(json_encode([ + 'error'=>$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/lib/participoLib/participo.php b/homepage/participo/lib/participoLib/participo.php index 42fca1d..00de3a1 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; diff --git a/homepage/participo/lib/participoLib/shiai.php b/homepage/participo/lib/participoLib/shiai.php index ab59543..1419556 100644 --- a/homepage/participo/lib/participoLib/shiai.php +++ b/homepage/participo/lib/participoLib/shiai.php @@ -21,10 +21,10 @@ class Shiai */ private static $tableName = "wettkampfkalender"; - public function __construct($id, $date, $name, $ageclasses, $place, $announcementUrl, $routeUrl, $galleryUrl, $promoImgUrl) + 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; @@ -35,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; diff --git a/homepage/participo/lib/participoLib/user.php b/homepage/participo/lib/participoLib/user.php index e736c40..17656db 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 diff --git a/homepage/participo/testApi.py b/homepage/participo/testApi.py index b31824e..a43325c 100755 --- a/homepage/participo/testApi.py +++ b/homepage/participo/testApi.py @@ -12,7 +12,10 @@ class TestApi: argParser = argparse.ArgumentParser( "testApi" ) - + argParser.add_argument( + "method", + choices=['GET', 'POST'] + ) argParser.add_argument( "--endpoint", default="shiai" @@ -40,6 +43,11 @@ class TestApi: choices=_LOG_LEVEL, default="WARNING" ) + argParser.add_argument( + "--input", "-i", + type=argparse.FileType("r"), + default="-" + ) return argParser.parse_args() @@ -59,33 +67,47 @@ class TestApi: 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 + headers: dict = None, + input: dict = None, ) -> dict: import requests - r = requests.get( - url=f"http://{host}/{url}", - # @todo The client always awaits this timeout. Even when the - # meaningful body is already received.params= - # - I don't see any of the examples out there do it different from - # me. - # - The browser doesn't seem to have this problem. - timeout=10, - headers=headers - ) + 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() From 49c7d958cb4157fc85596f2b4729850d24cbbafb Mon Sep 17 00:00:00 2001 From: marko Date: Tue, 9 Jan 2024 05:26:08 +0100 Subject: [PATCH 11/16] hotfix double json_decode config --- homepage/participo/lib/participoLib/participo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homepage/participo/lib/participoLib/participo.php b/homepage/participo/lib/participoLib/participo.php index 00de3a1..e0e3861 100644 --- a/homepage/participo/lib/participoLib/participo.php +++ b/homepage/participo/lib/participoLib/participo.php @@ -250,7 +250,7 @@ class participo 'user' => [ 'username' => $user->getLoginName(), 'userId' => $user->getId(), - 'userConfig' => json_decode($user->getConfig(), true) + 'userConfig' => $user->getConfig() ] ]; From 881ea6b05946456c1311d07f1dd479890096eb2a Mon Sep 17 00:00:00 2001 From: marko Date: Sat, 13 Jan 2024 11:46:16 +0100 Subject: [PATCH 12/16] started work on pmelo --- homepage/participo/api/trainees.php | 1 - homepage/participo/index.js | 14 +++++++----- homepage/participo/index.php | 4 +--- homepage/participo/lib/participoLib/user.php | 23 ++++++++++++++++++++ 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/homepage/participo/api/trainees.php b/homepage/participo/api/trainees.php index 358fde3..8bf39de 100644 --- a/homepage/participo/api/trainees.php +++ b/homepage/participo/api/trainees.php @@ -27,7 +27,6 @@ function get() return $wkSqlResponse; } - authorize(); $wkSqlResponse = get(); 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/user.php b/homepage/participo/lib/participoLib/user.php index 17656db..fc0f19c 100644 --- a/homepage/participo/lib/participoLib/user.php +++ b/homepage/participo/lib/participoLib/user.php @@ -325,4 +325,27 @@ 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` = 4". + " ORDER BY `wkParticipo_Users`.`id` ASC;"; + + $response = dbConnector::query($query); + + // 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; + } } From af4024cf259cf06c006ed7fb0cd93a2491c4e3b8 Mon Sep 17 00:00:00 2001 From: marko Date: Sat, 13 Jan 2024 11:46:16 +0100 Subject: [PATCH 13/16] started work on pmelo --- homepage/participo/api/trainees.php | 1 - homepage/participo/index.js | 14 +++-- homepage/participo/index.php | 4 +- homepage/participo/lib/participoLib/user.php | 23 ++++++++ homepage/participo/pmelo.inc.php | 16 ++++++ homepage/participo/pmelo.php | 57 ++++++++++++++++++++ 6 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 homepage/participo/pmelo.inc.php create mode 100644 homepage/participo/pmelo.php diff --git a/homepage/participo/api/trainees.php b/homepage/participo/api/trainees.php index 358fde3..8bf39de 100644 --- a/homepage/participo/api/trainees.php +++ b/homepage/participo/api/trainees.php @@ -27,7 +27,6 @@ function get() return $wkSqlResponse; } - authorize(); $wkSqlResponse = get(); 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/user.php b/homepage/participo/lib/participoLib/user.php index 17656db..fc0f19c 100644 --- a/homepage/participo/lib/participoLib/user.php +++ b/homepage/participo/lib/participoLib/user.php @@ -325,4 +325,27 @@ 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` = 4". + " ORDER BY `wkParticipo_Users`.`id` ASC;"; + + $response = dbConnector::query($query); + + // 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/pmelo.inc.php b/homepage/participo/pmelo.inc.php new file mode 100644 index 0000000..281ab08 --- /dev/null +++ b/homepage/participo/pmelo.inc.php @@ -0,0 +1,16 @@ + diff --git a/homepage/participo/pmelo.php b/homepage/participo/pmelo.php new file mode 100644 index 0000000..faf1ccf --- /dev/null +++ b/homepage/participo/pmelo.php @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + participo + + + + + + + +
+ + +
+ +
+

pmElo

+ +
+
+ + + +
+
+ +
+ + From d665230ad5c7ceaae3c11e525351054b1ea1612b Mon Sep 17 00:00:00 2001 From: marko Date: Fri, 19 Jan 2024 05:12:42 +0100 Subject: [PATCH 14/16] wip: pmelo --- homepage/participo/lib/participoLib/user.php | 25 +---- homepage/participo/pmelo.inc.php | 97 ++++++++++++++++++-- homepage/participo/pmelo.php | 69 +++++++++++--- 3 files changed, 146 insertions(+), 45 deletions(-) diff --git a/homepage/participo/lib/participoLib/user.php b/homepage/participo/lib/participoLib/user.php index fc0f19c..9f62943 100644 --- a/homepage/participo/lib/participoLib/user.php +++ b/homepage/participo/lib/participoLib/user.php @@ -248,7 +248,7 @@ SQL; public function getConfig() { - return $this->$config; + return $this->config; } // static functions @@ -325,27 +325,4 @@ 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` = 4". - " ORDER BY `wkParticipo_Users`.`id` ASC;"; - - $response = dbConnector::query($query); - - // 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/pmelo.inc.php b/homepage/participo/pmelo.inc.php index 281ab08..7f83ea7 100644 --- a/homepage/participo/pmelo.inc.php +++ b/homepage/participo/pmelo.inc.php @@ -1,16 +1,99 @@ +class PmElo{ + function __construct() + { + // 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)){ + $_SESSION['pmelo']['fighterIds'] = null; + } + + // check for action in post data + if(array_key_exists('pmelo', $_POST)){ + if(array_key_exists('fighterIds', $_POST['pmelo'])){ + $this->fighters = array_map('User::loadFromDb', $_POST['pmelo']['fighterIds']); + } + } + + if(!is_file("pmeloRanking.json")){ + $this->log['info'][] = "Couldn't find `pmeloRanking.json`. Create a new one!"; + file_put_contents("pmeloRanking.json", json_encode([])); + } + + // init members + $this->trainees = self::getTrainees(); + $this->rankings = self::createRankings(); + + } + + public static function getTrainees(){ + $traineeList = array_map('User::fromDbArray', User::dbSelectWithAttribute(4)); + $traineeAssocArray = []; + foreach($traineeList as $trainee){ + $traineeAssocArray[$trainee->getId()] = $trainee; + } + return $traineeAssocArray; + } + public static function loadRankings(){ + return json_decode(file_get_contents("pmeloRanking.json")); + } + public static function saveRankings(array $rankings){ + file_put_contents("pmeloRankings.json", json_encode($rankings)); + } + + public function createRankings(){ + // load the last state of the ranking + $loadedRanking = self::loadRankings(); + + // check if the ranked trainees still are in training + $cleanRanking = []; + $toBeInsertedTrainees = []; + foreach($loadedRanking as $rank=>$id){ + if(array_key_exists($id, $this->trainees)){ + $cleanRanking[] = $id; + continue; + } + // id of the not in the ranking, we have to insert + $toBeInsertedTrainees[$id] = $this->trainees[$id]; + } + + usort($toBeInsertedTrainees, function($lhs, $rhs){return $lhs < $rhs ? -1 : 1;}); + var_dump($toBeInsertedTrainees); + + // insert new trainees in the ranking + // foreach($this->trainees as $trainee){ + // if(empty($this->rankings)){ + + // } + // } + } + + 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; +} \ No newline at end of file diff --git a/homepage/participo/pmelo.php b/homepage/participo/pmelo.php index faf1ccf..f7157ec 100644 --- a/homepage/participo/pmelo.php +++ b/homepage/participo/pmelo.php @@ -37,21 +37,62 @@
-

pmElo

- -
-
- - - -
-
+

pmElo

+
+
+ + + +
+
+ + + + + + + fighters)) foreach($pmelo->fighters as $fighter){ + echo("".PHP_EOL); + } + ?> + +
PlatzNameAufstieg
#".$fighter->getFirstname()." ".$fighter->getName()."^
+ +
    +
  • Logs

  • +log as $logLevel=>$mesages){ + if(!empty($messages)){ +?> +
  • +
      +
    • + +
    • + +
    • + +
    +
  • + + +
From 62bd7cb14b3a61869fe39695eb5d6de4b40830b2 Mon Sep 17 00:00:00 2001 From: marko Date: Sat, 20 Jan 2024 12:40:00 +0100 Subject: [PATCH 15/16] wip: pmelo --- homepage/participo/lib/participoLib/user.php | 38 +++++++++++++++- homepage/participo/pmelo.inc.php | 47 +++++++++++++++----- homepage/participo/pmelo.php | 2 +- 3 files changed, 73 insertions(+), 14 deletions(-) diff --git a/homepage/participo/lib/participoLib/user.php b/homepage/participo/lib/participoLib/user.php index 9f62943..3badb82 100644 --- a/homepage/participo/lib/participoLib/user.php +++ b/homepage/participo/lib/participoLib/user.php @@ -241,14 +241,18 @@ SQL; return $this->name; } - public function getFirstname() + public function getFirstName() { return $this->firstName; } public function getConfig() { - return $this->config; + return $this->$config; + } + + public function getStrBirthday(){ + return $this->dateOfBirth->format("Y-m-d"); } // static functions @@ -325,4 +329,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/pmelo.inc.php b/homepage/participo/pmelo.inc.php index 7f83ea7..1eb4ab4 100644 --- a/homepage/participo/pmelo.inc.php +++ b/homepage/participo/pmelo.inc.php @@ -38,17 +38,20 @@ class PmElo{ } } - if(!is_file("pmeloRanking.json")){ - $this->log['info'][] = "Couldn't find `pmeloRanking.json`. Create a new one!"; - file_put_contents("pmeloRanking.json", json_encode([])); + // 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 = self::createRankings(); } + // load all active trainees into a id=>User assoc array public static function getTrainees(){ $traineeList = array_map('User::fromDbArray', User::dbSelectWithAttribute(4)); $traineeAssocArray = []; @@ -57,31 +60,51 @@ class PmElo{ } return $traineeAssocArray; } + + // load ranking from json file public static function loadRankings(){ - return json_decode(file_get_contents("pmeloRanking.json")); + return json_decode(file_get_contents(self::$pmeloJson)); } + + // save a ranking to json file public static function saveRankings(array $rankings){ - file_put_contents("pmeloRankings.json", json_encode($rankings)); + file_put_contents(self::$pmeloJson, json_encode($rankings)); + } + + 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); } public function createRankings(){ // load the last state of the ranking $loadedRanking = self::loadRankings(); + $this->var_log($loadedRanking,"ranking"); // check if the ranked trainees still are in training $cleanRanking = []; - $toBeInsertedTrainees = []; + $toBeInsertedTrainees = $this->trainees; foreach($loadedRanking as $rank=>$id){ if(array_key_exists($id, $this->trainees)){ $cleanRanking[] = $id; - continue; + // id of the not in the ranking, we have to insert + unset($toBeInsertedTrainees[$id]); } - // id of the not in the ranking, we have to insert - $toBeInsertedTrainees[$id] = $this->trainees[$id]; } - usort($toBeInsertedTrainees, function($lhs, $rhs){return $lhs < $rhs ? -1 : 1;}); - var_dump($toBeInsertedTrainees); + $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();},$newTraineesIds), "newTrainieesIdsByAge"); + $this->var_log($newTraineesIds, "newTrainieesIdsByAge"); + $this->var_log(array_map(function($user){return $user->getFirstName();}, $toBeInsertedTrainees), "newTrainees"); // insert new trainees in the ranking // foreach($this->trainees as $trainee){ @@ -96,4 +119,6 @@ class PmElo{ 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 index f7157ec..253fa36 100644 --- a/homepage/participo/pmelo.php +++ b/homepage/participo/pmelo.php @@ -69,7 +69,7 @@
  • Logs

  • log as $logLevel=>$mesages){ + foreach($pmelo->log as $logLevel=>$messages){ if(!empty($messages)){ ?>
  • From e04de32c567b7e4c56d22e61982b3337d842c908 Mon Sep 17 00:00:00 2001 From: marko Date: Tue, 23 Jan 2024 19:49:41 +0100 Subject: [PATCH 16/16] wip pmelo: still promoting missing --- homepage/participo/lib/participoLib/user.php | 57 ++++++------ homepage/participo/pmelo.inc.php | 95 +++++++++++++++----- homepage/participo/pmelo.php | 13 ++- 3 files changed, 115 insertions(+), 50 deletions(-) diff --git a/homepage/participo/lib/participoLib/user.php b/homepage/participo/lib/participoLib/user.php index 3badb82..a5476f0 100644 --- a/homepage/participo/lib/participoLib/user.php +++ b/homepage/participo/lib/participoLib/user.php @@ -159,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) { @@ -175,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 * @@ -248,9 +248,12 @@ SQL; 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"); } diff --git a/homepage/participo/pmelo.inc.php b/homepage/participo/pmelo.inc.php index 1eb4ab4..5cfaeb6 100644 --- a/homepage/participo/pmelo.inc.php +++ b/homepage/participo/pmelo.inc.php @@ -2,9 +2,6 @@ setlocale(LC_ALL, "de_DE@euro", "de_DE", "de", "ge"); set_include_path(get_include_path() . PATH_SEPARATOR . "./lib/"); -// start a session -session_start(); - // Configs require_once("config/participo.php"); require_once $config['basePath'] . "/config/cwsvJudo.config.php"; @@ -19,6 +16,7 @@ $pmelo = new PmElo(); class PmElo{ function __construct() { + // $this->var_log($_SESSION, "session"); // starting/continuing a session session_start(); @@ -27,15 +25,16 @@ class PmElo{ $_SESSION['pmelo'] = []; } // - data storage for id-s of chosen fighters - if(!array_key_exists('fighterIds', $_SESSION)){ - $_SESSION['pmelo']['fighterIds'] = null; + 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'])){ - $this->fighters = array_map('User::loadFromDb', $_POST['pmelo']['fighterIds']); + $_SESSION['pmelo']['fighterIds']=$_POST['pmelo']['fighterIds']; } + // $this->var_log($_SESSION, "session"); } // load/recreate ranking data @@ -47,10 +46,24 @@ class PmElo{ // init members $this->trainees = self::getTrainees(); $this->var_log(array_map(function($user){return $user->getFirstName();},$this->trainees), "trainees from db"); - $this->rankings = self::createRankings(); + $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)); @@ -71,6 +84,7 @@ class PmElo{ 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'; @@ -79,22 +93,27 @@ class PmElo{ $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($loadedRanking,"ranking"); + $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 $rank=>$id){ + 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; - // id of the not in the ranking, we have to insert + // 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 @@ -102,16 +121,52 @@ class PmElo{ 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();},$newTraineesIds), "newTrainieesIdsByAge"); - $this->var_log($newTraineesIds, "newTrainieesIdsByAge"); - $this->var_log(array_map(function($user){return $user->getFirstName();}, $toBeInsertedTrainees), "newTrainees"); + // $this->var_log( + // array_map( + // function($id){return $this->trainees[$id]->getStrBirthday()." ".$this->trainees[$id]->getFirstName();} + // , $newTraineesIds + // ) + // , "newTraineesBy B-Day" + // ); - // insert new trainees in the ranking - // foreach($this->trainees as $trainee){ - // if(empty($this->rankings)){ - - // } - // } + // 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'=>[]]; @@ -120,5 +175,5 @@ class PmElo{ // list of id-s in the order of the current ranking public $rankings = null; - static $pmeloJson="pmeloRanking.json"; + static $pmeloJson="./pmeloRanking.json"; } \ No newline at end of file diff --git a/homepage/participo/pmelo.php b/homepage/participo/pmelo.php index 253fa36..da60dfb 100644 --- a/homepage/participo/pmelo.php +++ b/homepage/participo/pmelo.php @@ -59,9 +59,16 @@ PlatzNameAufstieg - fighters)) foreach($pmelo->fighters as $fighter){ - echo("#".$fighter->getFirstname()." ".$fighter->getName()."^".PHP_EOL); - } + fighters)){ + foreach($pmelo->rankings as $rank=>$id){ + if(array_key_exists($id, $pmelo->fighters)){ + $fighter = $pmelo->fighters[$id]; + // echo("".$rank."".$fighter->getFirstName()."".PHP_EOL); + echo("".$rank."".$fighter->getFirstName()." ".$fighter->getName()."^".PHP_EOL); + } + } +} ?>