Merge branch 'homepage' into infoZettel

This commit is contained in:
marko
2024-01-23 20:16:18 +01:00
31 changed files with 968 additions and 60 deletions

View File

@@ -1 +1,3 @@
local/*.php local/*.php
node_modules/*
testApi.config.yaml

20
homepage/participo/.vscode/launch.json vendored Normal file
View File

@@ -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"
]
}
]
}

View File

@@ -1,7 +1,16 @@
{ {
"cSpell.language": "en,de-de",
"cSpell.words": [ "cSpell.words": [
"CURDATE",
"cwsv",
"cwsvjudo",
"participo", "participo",
"retval", "retval",
"shiai" "shiai",
"vormundschaft",
"wettkampfkalender"
],
"prettier.documentSelectors": [
"**/*.{js,jsx,ts,tsx,vue,html,css,scss,less,json,md,mdx,graphql,yaml,yml,php}"
] ]
} }

View File

@@ -7,7 +7,10 @@
"remotePath": "/www/participo", "remotePath": "/www/participo",
"ignore": [ "ignore": [
".vscode", ".vscode",
"*.py" "*.py",
"*.config.yaml",
"package.json", "package-lock.json"
, "node-modules"
], ],
"uploadOnSave": true "uploadOnSave": true
} }

View File

@@ -0,0 +1 @@
Deny from all

View File

@@ -0,0 +1,52 @@
<?php
/// @file common settings and includes for the participo api
/// - set locale to german
setlocale(LC_ALL, "de_DE@euro", "de_DE", "de", "ge");
/// - extend the include search path for
set_include_path(implode(
PATH_SEPARATOR,
[
get_include_path(),
/// - user defined libs (e.g. participo)
"../lib",
/// - config files (we reuse the participo-wide configuration)
".."
]
));
/// - participo configuration
require_once("config/participo.php");
/// - data base credentials
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"],
$cwsvJudoConfig["db"]["name"],
$cwsvJudoConfig["db"]["user"],
$cwsvJudoConfig["db"]["password"]
);

View File

@@ -0,0 +1,13 @@
<?php
header('Content-Type: application/json');
// $endpoint = $_SERVER['REQUEST_URI'];
// switch ($endpoint){
// case '/':
// echo json_encode([
// 'message' => 'Welcome to the API'
// ]);
// break;
// }
?>

View File

@@ -0,0 +1,54 @@
<?php
require_once("inc/bootstrap.php");
require_once("participoLib/shiai.php");
$method = $_SERVER['REQUEST_METHOD'];
// Sending Response
// - we send a json-formatted response
header("Content-Type: application/json");
// - 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."
]));
}
?>

View File

@@ -0,0 +1,37 @@
<?php
require_once("inc/bootstrap.php");
require_once 'participoLib/apiKey.php';
function get()
{
$wkSqlQuery =
"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;";
$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);

View File

@@ -0,0 +1,81 @@
<?php
setlocale(LC_ALL, "de_DE@euro", "de_DE", "de", "ge");
set_include_path(
get_include_path() . PATH_SEPARATOR . "../lib/" . PATH_SEPARATOR . ".."
);
require_once "config/participo.php";
require_once "local/cwsvJudo.php";
require_once "participoLib/participo.php";
function init($config)
{
dbConnector::connect(
$config["db"]["host"],
$config["db"]["name"],
$config["db"]["user"],
$config["db"]["password"]
);
}
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",
])
);
}
}
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);
?>

View File

@@ -3,8 +3,6 @@ setlocale(LC_ALL, 'de_DE@euro', 'de_DE', 'de', 'ge');
set_include_path(get_include_path() . PATH_SEPARATOR . './lib/'); set_include_path(get_include_path() . PATH_SEPARATOR . './lib/');
require_once 'participoLib/event.php'; require_once 'participoLib/event.php';
// require_once 'participoLib/starter.php';
// require_once 'participoLib/planer.php';
// Configs // Configs
require_once 'config/participo.php'; require_once 'config/participo.php';
@@ -46,4 +44,4 @@ participo::init($cwsvJudoConfig);
</main> </main>
</body> </body>
</html> </html>

View File

@@ -1,9 +1,13 @@
// What to do when the document is loaded. // What to do when the document is loaded.
document.addEventListener('DOMContentLoaded', function () { document.addEventListener(
// init materialize elements 'DOMContentLoaded'
initModals(); , function () {
initSidenav(); // init materialize elements
}); initModals();
initSidenav();
initSelects();
}
);
function initSidenav() { function initSidenav() {
var sidenavElements = document.querySelectorAll('.sidenav'); var sidenavElements = document.querySelectorAll('.sidenav');

View File

@@ -1,6 +1,4 @@
<?php <?php require_once 'index.inc.php'; ?>
require_once 'index.inc.php';
?>
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>

View File

@@ -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) // @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) private static function fromDbArray(array $apiKey)
{ {
return new ApiKey( return new ApiKey(

View File

@@ -28,7 +28,7 @@ class dbConnector
public static function query($aQueryString, $aBindArray = [], $someOptions = []) public static function query($aQueryString, $aBindArray = [], $someOptions = [])
{ {
// var_dump($aQueryString, $aBindArray); // var_dump($aQueryString, $aBindArray);
// Standardbelegungen // Standardbelegungen
if (empty($someOptions['dbCharset'])) { if (empty($someOptions['dbCharset'])) {
$someOptions['dbCharset'] = 'ISO-8859-1'; $someOptions['dbCharset'] = 'ISO-8859-1';
} }
@@ -65,7 +65,7 @@ class dbConnector
); );
} }
$pdoResult = $pdoStatement->execute(); $pdoResult = $pdoStatement->execute();
if (!$ignoreErrors && !$pdoResult) { if (!$ignoreErrors && !$pdoResult) {
echo("Error during dbQuery!\n"); echo("Error during dbQuery!\n");
echo("DB-Error:\n"); echo("DB-Error:\n");
var_dump(self::$db->errorInfo()); var_dump(self::$db->errorInfo());
@@ -128,6 +128,7 @@ class dbConnector
} else { } else {
self::$db = null; self::$db = null;
} }
return $success;
} }
public static function debugEchoQuery($query, $params) public static function debugEchoQuery($query, $params)

View File

@@ -87,6 +87,9 @@ class Event
if ((!isset($this->shiai) || $forceLoading) && isset($this->shiaiId)) { if ((!isset($this->shiai) || $forceLoading) && isset($this->shiaiId)) {
$this->shiai = Shiai::loadFromDb($this->shiaiId); $this->shiai = Shiai::loadFromDb($this->shiaiId);
} }
if ($this->shiai == null){
$this->shiai = Shiai::fromDbArray(json_decode($this->remarks, true));
}
return $this->shiai; return $this->shiai;
} }

View File

@@ -55,7 +55,7 @@ class participo
/** lazy loading of the session user */ /** lazy loading of the session user */
public static function sessionUser(bool $forceLoading = true) public static function sessionUser(bool $forceLoading = true)
{ {
if (is_null($sessionUser) || $forceLoading) { if (is_null(self::$sessionUser) || $forceLoading) {
self::$sessionUser = User::loadFromDb(self::getSessionUserId()); self::$sessionUser = User::loadFromDb(self::getSessionUserId());
} }
return self::$sessionUser; return self::$sessionUser;
@@ -250,7 +250,7 @@ class participo
'user' => [ 'user' => [
'username' => $user->getLoginName(), 'username' => $user->getLoginName(),
'userId' => $user->getId(), 'userId' => $user->getId(),
'userConfig' => json_decode($user->getConfig(), true) 'userConfig' => $user->getConfig()
] ]
]; ];

View File

@@ -15,10 +15,16 @@ class Shiai
private $galleryUrl = null; //< url of the gallery to a gallery of the shiai private $galleryUrl = null; //< url of the gallery to a gallery of the shiai
private $promoImgUrl = null; //< promotional image for the shiai (as url) 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 //! @todo input validation and sanitation
$this->id = (int) $id; $this->id = filterId($id);
$this->date = DateTime::createFromFormat('Y-m-d', $date); $this->date = DateTime::createFromFormat('Y-m-d', $date);
$this->name = $name; $this->name = $name;
$this->ageclasses = $ageclasses ? self::akListString2jgArray($ageclasses) : null; $this->ageclasses = $ageclasses ? self::akListString2jgArray($ageclasses) : null;
@@ -29,6 +35,32 @@ class Shiai
$this->promoImgUrl = $promoImgUrl; $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() public function getId()
{ {
return $this->id; return $this->id;
@@ -83,6 +115,17 @@ class Shiai
return self::fromDbArray($response[0]); 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) public static function fromDbArray($member)
{ {
return new shiai( return new shiai(

View File

@@ -75,6 +75,26 @@ class User
return dbConnector::getLastInsertId(); 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 /** Name of the table with all the Users
* *
* @var string * @var string
@@ -139,13 +159,13 @@ class User
/** List of users kids */ /** List of users kids */
private $kids = null; private $kids = null;
public function kidIds(bool $forceLoading = false) // public function kidIds(bool $forceLoading = false)
{ // {
if (is_null($this->kidIds) || $forceLoading) { // if (is_null($this->kidIds) || $forceLoading) {
$this->kidIds = self::getKidIds($id); // $this->kidIds = self::getKidIds($id);
} // }
return self::$kidIds; // return self::$kidIds;
} // }
public function kids(bool $forceLoading = false) public function kids(bool $forceLoading = false)
{ {
@@ -155,26 +175,26 @@ class User
return $this->kids; return $this->kids;
} }
private static function getKidIds(int $id) // private static function getKidIds(int $id)
{ // {
$response = dbConnector::query( // $response = dbConnector::query(
'SELECT * FROM `wkParticipo_Users` WHERE `' . $name . '` = :' . $name, // 'SELECT * FROM `wkParticipo_Users` WHERE `' . $name . '` = :' . $name,
[$name => ['value' => $value, 'data_type' => self::$dbColumns[$name]]] // [$name => ['value' => $value, 'data_type' => self::$dbColumns[$name]]]
); // );
$query = <<<SQL // $query = <<<SQL
SELECT * // SELECT *
FROM `wkParticipo_Users` // FROM `wkParticipo_Users`
JOIN `vormundschaft` // JOIN `vormundschaft`
ON `wkParticipo_Users`.`id` = `vormundschaft`.`kidId` // ON `wkParticipo_Users`.`id` = `vormundschaft`.`kidId`
WHERE `vormundschaft`.`userId` = :userId; // WHERE `vormundschaft`.`userId` = :userId;
SQL; // SQL;
$params = [ // $params = [
':userId' => ['value' => $userId, 'data_type' => PDO::PARAM_INT] // ':userId' => ['value' => $userId, 'data_type' => PDO::PARAM_INT]
]; // ];
$response = dbConnector::query($query, $params); // $response = dbConnector::query($query, $params);
return $response; // return $response;
} // }
/** Export the User data into an associative array /** Export the User data into an associative array
* *
@@ -221,14 +241,21 @@ SQL;
return $this->name; return $this->name;
} }
public function getFirstname() public function getFirstName()
{ {
return $this->firstName; return $this->firstName;
} }
public function getConfig() 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 // static functions
@@ -305,4 +332,34 @@ SQL;
} }
return User::fromDbArray($response[0]); 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;
}
} }

103
homepage/participo/package-lock.json generated Normal file
View File

@@ -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"
}
}
}
}

View File

@@ -0,0 +1,10 @@
{
"devDependencies": {
"@prettier/plugin-php": "^0.22.1",
"prettier": "^3.1.1"
},
"prettier":{
"parser": "php",
"plugins": ["@prettier/plugin-php"]
}
}

View File

@@ -0,0 +1,179 @@
<?php
setlocale(LC_ALL, "de_DE@euro", "de_DE", "de", "ge");
set_include_path(get_include_path() . PATH_SEPARATOR . "./lib/");
// Configs
require_once("config/participo.php");
require_once $config['basePath'] . "/config/cwsvJudo.config.php";
// Libs
require_once("participoLib/user.php");
participo::init($cwsvJudoConfig);
$pmelo = new PmElo();
class PmElo{
function __construct()
{
// $this->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";
}

View File

@@ -0,0 +1,105 @@
<?php require_once("pmelo.inc.php");?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- shared imports (common css, MaterializeCss) -->
<?php readfile('shared/imports.php'); ?>
<!-- inits for the materializeCss -->
<script src="index.js"></script>
<title>participo</title>
<meta name="description" content="pmelo">
<link rel="icon" href="<?echo($config['ressourceUrl']);?>/graphiken/icons/cwsv.ico" />
<link rel="apple-touch-icon" href="<?echo($config['baseUrl']);?>/apple-touch-icon.png">
</head>
<body>
<header>
<nav class="indigo darken-4">
<h1 style="display:inline;">cwsvJudo Apps</h1>
<a class="right top-nav sidenav-trigger waves-effect waves-light hide-on-large-only" href="#" data-target="nav-mobile">
<i class="material-icons">menu</i>
</a>
</nav>
<ul class="sidenav sidenav-fixed sidenav-close" id="nav-mobile">
<li class="logo">
<a style="height:auto;" class="brand-logo" id="logo-container" href="/participo/">
<img alt="cwsvJudoApps" style="max-width:100%;height:12vh;" class="responsive-img" src="http://cwsvjudo.bplaced.net/ressourcen/graphiken/logos/cwsvJudoLogoWappen.x256.png" />
</a>
</li>
<?php require_once 'sidenav/loginStatus.php'; ?><!-- brings its own li -->
</ul>
</header>
<main>
<h2><a href="pmelo">pmElo</a></h2>
<form id="pmelo-form-fighters" action="pmelo.php" method="post">
<div class="input-field col s12">
<select name ="pmelo[fighterIds][]" id="pmelo-form-fighters-select" multiple>
<option value="" disabled selected>Kämpfer auswählen</option>
<?php
foreach($pmelo->trainees as $trainee){
echo("<option value=\"".$trainee->getId()."\">".$trainee->getFirstname()." ".$trainee->getName()."</option>".PHP_EOL);
}
?>
</select>
<label for="form-select-2">Kämpfer auswählen</label>
<input type="submit" value="Liste erstellen">
</div>
</form>
<table>
<thead>
<tr><th>Platz</th><th>Name</th><th>Aufstieg</th></tr>
</thead>
<tbody>
<?php
if(!empty($pmelo->fighters)){
foreach($pmelo->rankings as $rank=>$id){
if(array_key_exists($id, $pmelo->fighters)){
$fighter = $pmelo->fighters[$id];
// echo("<tr><td>".$rank."</td><td>".$fighter->getFirstName()."</td></tr>".PHP_EOL);
echo("<tr><td>".$rank."</td><td>".$fighter->getFirstName()." ".$fighter->getName()."</td><td>^</td></tr>".PHP_EOL);
}
}
}
?>
</tbody>
</table>
<ul class="collection with-header">
<li class="collection-header"><h3>Logs</h3></li>
<?php
foreach($pmelo->log as $logLevel=>$messages){
if(!empty($messages)){
?>
<li class="collection-item">
<ul class="collection with-header">
<li class="collection-header"><?php echo($logLevel);?></li>
<?php
foreach($messages as $message){
?>
<li>
<?php echo($message); ?>
</li>
<?php
}
?>
</ul>
</li>
<?php
}
?>
<?php
}
?>
</ul>
</main>
</body>
</html>

132
homepage/participo/testApi.py Executable file
View File

@@ -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:")

View File

@@ -13,7 +13,6 @@ $db = dbConnector::connect(
$cwsvJudoConfig['db']['user'], $cwsvJudoConfig['db']['user'],
$cwsvJudoConfig['db']['password'] $cwsvJudoConfig['db']['password']
); );
echo($db);
$wkSqlQuery = 'SELECT * FROM `wettkampfkalender` WHERE `Datum` >= CURDATE();'; $wkSqlQuery = 'SELECT * FROM `wettkampfkalender` WHERE `Datum` >= CURDATE();';
$wkSqlResponse = dbConnector::query($wkSqlQuery); $wkSqlResponse = dbConnector::query($wkSqlQuery);
@@ -22,3 +21,4 @@ header('Access-Control-Allow-Headers: *');
header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Origin: *');
echo(json_encode($wkSqlResponse)); echo(json_encode($wkSqlResponse));
?>

View File

@@ -2,6 +2,7 @@ include Makefile.private
infoZettel=$(patsubst %.md,%.pdf,$(wildcard *.md)) infoZettel=$(patsubst %.md,%.pdf,$(wildcard *.md))
infoZettel-2x2=$(patsubst %.md,%-2x2.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=$(patsubst %.md,%.pdf,$(wildcard wkZettel/*.md))
wkZettel-2x2=$(patsubst %.md,%-2x2.pdf,$(wildcard wkZettel/*.md)) wkZettel-2x2=$(patsubst %.md,%-2x2.pdf,$(wildcard wkZettel/*.md))
kyuZettel=$(patsubst %.md,%.pdf,$(wildcard kyuZettel/*.md)) kyuZettel=$(patsubst %.md,%.pdf,$(wildcard kyuZettel/*.md))
@@ -37,7 +38,7 @@ aushaenge: $(aushaenge)
--variable classoption="twoside=true" \ --variable classoption="twoside=true" \
--variable classoption="DIV=28" \ --variable classoption="DIV=28" \
--variable classoption="BCOR=0mm" \ --variable classoption="BCOR=0mm" \
--variable classoption="paper=A6" \ --variable classoption="paper=A5" \
--variable classoption="fontsize=10pt" \ --variable classoption="fontsize=10pt" \
--variable classoption="parskip=never" \ --variable classoption="parskip=never" \
--variable classoption="headsepline=true" \ --variable classoption="headsepline=true" \
@@ -48,7 +49,10 @@ aushaenge: $(aushaenge)
$^ $^
%-2x2.pdf: %.pdf %-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 aushang/%.pdf: aushang/%.md
pandoc \ pandoc \

View File

@@ -4,7 +4,7 @@ include passwords
.PHONY: updateSubmodules .PHONY: updateSubmodules
updateSubmodules: checkoutSubmodulesDefaultBranches updateSubmodules: checkoutSubmodulesDefaultBranches
git submodule foreach git pull git submodule foreach git pull
.PHONY: .PHONY:
checkoutSubmodulesDefaultBranches: checkoutSubmodulesDefaultBranches:
git -C lite-youtube-embed checkout master git -C lite-youtube-embed checkout master
@@ -13,12 +13,11 @@ checkoutSubmodulesDefaultBranches:
git -C spyc checkout master git -C spyc checkout master
git -C zopfli checkout master git -C zopfli checkout master
.PHONY: buildMaterialize .PHONY: buildMaterialize
buildMaterialize: updateSubmodules buildMaterialize: updateSubmodules
./buildMaterialize.sh ./buildMaterialize.sh
.PHONY: deployMaterialize .PHONY: deployMaterialize
# deployMaterialize: buildMaterialize deployMaterialize: buildMaterialize
deployMaterialize: $(materialiceCssDist) # @todo correctly check the cert
cd materialize/dist/ && find . -type f -exec curl --verbose -u cwsvjudo:$(ftpPassword) --ftp-create-dirs -T {} ftp://cwsvjudo.bplaced.net/www/ressourcen/materializeCss/{} \; lftp -e "set ftp:ssl-allow no; mirror -R 'materialize/dist' 'www/ressourcen/materializeCss'; bye;" -u cwsvjudo,$(ftpPassword) cwsvjudo.bplaced.net