7 Commits

Author SHA1 Message Date
marko
49b49d87a8 Merge branch 'participo/docker-testing' of https://gitea.cwsvjudo.dedyn.io/marko/cwsvJudo into participo/docker-testing 2024-11-29 21:25:01 +01:00
marko
5c3b4af1bd adjusted config paths, WIP: messages handling 2024-11-29 21:18:02 +01:00
marko
6fb6ea9983 refactoring login form, add logout to the tests 2024-11-20 07:47:31 +01:00
marko
41e95d6228 updated submodules 2024-11-16 10:59:13 +01:00
marko
3b31b112a7 added checks for php errors/warnings 2024-11-14 18:17:25 +01:00
marko
6e52d452eb added tests, simple login test 2024-11-14 14:20:18 +01:00
marko
b9b47c069a WIP make it run in docker 2024-11-13 13:28:30 +01:00
33 changed files with 1015 additions and 684 deletions

View File

@@ -0,0 +1,13 @@
MAKE=make
.PHONY: TESTS
TESTS:
$(MAKE) --print-directory --directory ./test
.PHONY: INSTALL
INSTALL:
$(MAKE) --print-directory --directory ./test INSTALL
.PHONY: CLEAN
CLEAN:
$(MAKE) --print-directory --directory ./test CLEAN

View File

@@ -20,7 +20,7 @@ dbConnector::connect(
);
// authentication of the current user
participo::authentificate();
participo::authenticate();
if (!participo::isUserAdmin()) {
header('Location: /participo', true, 301);
}

View File

@@ -14,7 +14,7 @@ dbConnector::connect(
$cwsvJudoConfig['db']['password']
);
participo::authentificate();
participo::authenticate();
$eventId = $_POST['eventId'] ?? null;
$startingTypeId = $_POST['type'] ?? null;

View File

@@ -14,7 +14,7 @@ dbConnector::connect(
$cwsvJudoConfig['db']['password']
);
participo::authentificate();
participo::authenticate();
$starterId = $_POST['starterId'] ?? null;
$returnToUrl = $_POST['returnToUrl'] ?? 'participo/';

View File

@@ -15,7 +15,7 @@ dbConnector::connect(
$cwsvJudoConfig['db']['password']
);
participo::authentificate();
participo::authenticate();
$loginName = $_POST['loginName'] ?? null;
$name = $_POST['name'] ?? null;

View File

@@ -2,7 +2,7 @@
/// @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
/// - extend the include search path for:
set_include_path(implode(
PATH_SEPARATOR,
[

View File

@@ -11,8 +11,8 @@ setlocale(LC_ALL, 'de_DE@euro', 'de_DE', 'de', 'ge');
require_once './lib/participoLib/participo.php';
require_once './lib/participoLib/user.php';
require_once $config['basePath'] . '/config/cwsvJudo.config.php';
require_once $config['basePath'] . '/config/phpcount.config.php';
require_once $config["home"] . "/.local/cwsvJudo.config.php";
// require_once $config['basePath'] . '/.local/phpcount.config.php';
dbConnector::connect(
$cwsvJudoConfig['db']['host'],
@@ -21,7 +21,7 @@ setlocale(LC_ALL, 'de_DE@euro', 'de_DE', 'de', 'ge');
$cwsvJudoConfig['db']['password']
);
participo::authentificate();
participo::authenticate();
$user = participo::sessionUser();
$usersKids = getUsersKids(dbConnector::getDbConnection(), $_SESSION['user']['userId']);
@@ -123,7 +123,7 @@ setlocale(LC_ALL, 'de_DE@euro', 'de_DE', 'de', 'ge');
private static $Types = [
AttendanceType::Training => 'Training', AttendanceType::Excused => 'Entschuldigt', AttendanceType::Ill => 'Krank', AttendanceType::SpecialTraining => 'SonderTraining', AttendanceType::Competition => 'Wettkampf'
];
private static $NameOfMonth = [1 => 'Januar', 2 => 'Februar', 3 => 'März', 4 => 'April', 4 => 'Mai', 6 => 'Juni', 7 => 'Juli', 8 => 'August', 9 => 'September', 10 => 'Oktober', 11 => 'November', 12 => 'Dezember'];
private static $NameOfMonth = [1 => 'Januar', 2 => 'Februar', 3 => 'März', 4 => 'April', 5 => 'Mai', 6 => 'Juni', 7 => 'Juli', 8 => 'August', 9 => 'September', 10 => 'Oktober', 11 => 'November', 12 => 'Dezember'];
/**
* constructor

View File

@@ -1,12 +1,23 @@
<?php
/// @file some variable definitions
$config['basePath'] = '/users/cwsvjudo/www';
$config['baseUrl'] = 'http://cwsvjudo.bplaced.net';
$config['ressourceUrl'] = 'http://cwsvjudo.bplaced.net/ressourcen';
# define variable holding the config
if (!isset($config)) {
$config = [];
}
setlocale(LC_ALL, 'de_DE@euro', 'de_DE', 'de', 'ge');
set_include_path(implode(
PATH_SEPARATOR,
[get_include_path(), $config['basePath'], $config['basePath'] . '/ressourcen', $config['basePath'] . '/ressourcen/phpLib', './lib/']
));
$config["home"] = "/home/cwsvjudo";
$config["basePath"] = "/home/cwsvjudo/httpdocs";
$config["baseUrl"] = "http://cwsvjudo.bplaced.net";
$config["ressourceUrl"] = "http://cwsvjudo.bplaced.net/ressourcen";
setlocale(LC_ALL, "de_DE@euro", "de_DE", "de", "ge");
set_include_path(
implode(PATH_SEPARATOR, [
get_include_path(),
$config["basePath"],
$config["basePath"] . "/ressourcen",
$config["basePath"] . "/ressourcen/phpLib",
"./lib/",
])
);

View File

@@ -6,7 +6,8 @@ require_once 'participoLib/event.php';
// Configs
require_once 'config/participo.php';
require_once $config['basePath'] . '/config/cwsvJudo.config.php';
// @todo Switch to json saved settings
require_once $config['home'] . '/.local/cwsvJudo.config.php';
participo::init($cwsvJudoConfig);
@@ -24,12 +25,12 @@ participo::init($cwsvJudoConfig);
<!-- inits for the materializeCss -->
<script src="events.js"></script>
<title><?php echo($meta['title']); ?></title>
<title><?php echo ($meta['title'] ?? "title missing"); ?></title>
<meta name="description"
content="<?php echo($meta['description']); ?>" />
content="<?php echo ($meta['description'] ?? "description missing"); ?>" />
<link rel="icon" href="<?echo($config['ressourceUrl']);?>/graphiken/icons/cwsv.ico" />
<link rel="apple-touch-icon" href="<?echo($config['baseUrl']);?>/apple-touch-icon.png">
<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>

View File

@@ -1,30 +1,31 @@
<?php
setlocale(LC_ALL, 'de_DE@euro', 'de_DE', 'de', 'ge');
set_include_path(get_include_path() . PATH_SEPARATOR . './lib/');
setlocale(LC_ALL, "de_DE@euro", "de_DE", "de", "ge");
set_include_path(get_include_path() . PATH_SEPARATOR . "./lib/");
require_once 'participoLib/participo.php';
require_once 'participoLib/planer.php';
require_once "participoLib/participo.php";
require_once "participoLib/planer.php";
require_once 'config/participo.php';
require_once "config/participo.php";
require_once './local/dbConf.php';
require_once './local/cwsvJudo.php';
require_once "./local/dbConf.php";
require_once "./local/cwsvJudo.php";
require_once './lib/db.php';
require_once './lib/api.php';
require_once "./lib/db.php";
require_once "./lib/api.php";
require_once $config['basePath'] . '/config/cwsvJudo.config.php';
require_once $config["home"] . "/.local/cwsvJudo.config.php";
dbConnector::connect(
$cwsvJudoConfig['db']['host'],
$cwsvJudoConfig['db']['name'],
$cwsvJudoConfig['db']['user'],
$cwsvJudoConfig['db']['password']
$cwsvJudoConfig["db"]["host"],
$cwsvJudoConfig["db"]["name"],
$cwsvJudoConfig["db"]["user"],
$cwsvJudoConfig["db"]["password"]
);
participo::authentificate();
participo::authenticate();
$meta = [
'title' => 'Event Planer',
'description' => 'Planung von (Nicht-)Teilnahmen an Wettkämpfen und anderen Veranstaltungen'
"title" => "Event Planer",
"description" =>
"Planung von (Nicht-)Teilnahmen an Wettkämpfen und anderen Veranstaltungen",
];

View File

@@ -4,7 +4,7 @@
<div class="nav-wrapper">
<a href="/participo" class="breadcrumb">cwsvJudo-Apps</a>
<a href="/participo/events" class="breadcrumb">
<?php echo($meta['title']); ?>
<?php echo($meta['title'] ?? "missing title"); ?>
</a>
<a class="right top-nav sidenav-trigger waves-effect waves-light hide-on-large-only" href="#"
data-target="nav-mobile">

View File

@@ -32,4 +32,4 @@ dbConnector::connect(
);
// authentication of the current user
participo::authentificate();
participo::authenticate();

View File

@@ -10,11 +10,11 @@
require_once './lib/api.php';
$basePath = $config['basePath'];
require_once $basePath . '/config/cwsvJudo.config.php';
require_once $config["home"] . "/.local/cwsvJudo.config.php";
require_once $basePath . '/ressourcen/phpLib/parsedown/Parsedown.php';
require_once $basePath . '/ressourcen/phpLib/Spyc/Spyc.php';
participo::authentificate();
participo::authenticate();
// get a list of all infoZettel
$fileList = glob($basePath . '/infoZettel/*.md');
@@ -84,10 +84,11 @@ foreach ($years as $year) {?>
<!-- List of Infos -->
<div class="row" id="infoList">
<?php
$currentYear = (int)substr(basename($fileList[0]), 0, 4);
echo('<h2 id="infoZettel-' . $currentYear . '">' . $currentYear . '</h2>');
if (!empty($fileList)){
$currentYear = (int)substr(basename($fileList[0]), 0, 4);
echo('<h2 id="infoZettel-' . $currentYear . '">' . $currentYear . '</h2>');
foreach ($fileList as $file) {
foreach ($fileList as $file) {
$thisYear = (int)substr(basename($file), 0, 4);
if ($thisYear != $currentYear) {
$currentYear = $thisYear;
@@ -112,11 +113,13 @@ foreach ($fileList as $file) {
'description' => Parsedown::instance()->text($infoZettel['mdText']),
])->htmlCode(['extraClass' => 'parsedownCard'])
);
} ?>
}
}
}
else{
echo("Keine Infos gefunden!");
} ?>
</div><!-- End of Infos -->
</main>
<?php
}
?>
</body>
</html>

View File

@@ -24,7 +24,7 @@ class EventPage
public function getHtmlNotFound()
{
return '<div>Der Event "' .
$this->id .
$this->eventId .
'" existiert leider nicht!</div>' .
"<h2>Anstehende Termine</h2>" .
eventPlaner::getHtmlEventTable(eventPlaner::getComingWkEvents());

View File

@@ -1,11 +1,12 @@
<?php
require_once 'participoLib/dbConnector.php';
require_once 'participoLib/user.php';
require_once 'participoLib/event.php';
require_once 'participoLib/eventPage.php';
require_once 'participoLib/starter.php';
require_once 'participoLib/planer.php';
require_once "participoLib/dbConnector.php";
require_once "participoLib/user.php";
require_once "participoLib/event.php";
require_once "participoLib/eventPage.php";
require_once "participoLib/starter.php";
require_once "participoLib/planer.php";
/**
* FrameWork for the participoApp
@@ -26,7 +27,11 @@ class participo
}
private static $db = null;
private static $message = ['error' => null, 'success' => null, 'notice' => null];
private static $message = [
"error" => null,
"success" => null,
"notice" => null,
];
/** id of session user
*
@@ -46,7 +51,7 @@ class participo
public static function getSessionUserId()
{
if (!isset(self::$userId)) {
self::$userId = $_SESSION['user']['userId'] ?? null;
self::$userId = $_SESSION["user"]["userId"] ?? null;
}
self::$userId = filterId(self::$userId);
return self::$userId;
@@ -69,7 +74,9 @@ class participo
*/
public static function isLoginValid()
{
return (isset($_SESSION) && array_key_exists('login', $_SESSION) && $_SESSION['login'] == true);
return isset($_SESSION) &&
array_key_exists("login", $_SESSION) &&
$_SESSION["login"] == true;
}
/** Remove all login data from the session data
@@ -78,7 +85,7 @@ class participo
*/
public static function logout()
{
foreach (['login', 'user'] as $key) {
foreach (["login", "user"] as $key) {
unset($_SESSION[$key]);
}
}
@@ -89,12 +96,15 @@ class participo
*/
public static function htmlLoginStatus()
{
return
'<div style="border: 1px solid black">' .
'Datum: ' . date('Y-m-d') . '<br />' .
'Eingeloggt als <strong>' . htmlspecialchars($_SESSION['user']['username']) . '</strong>.<br />' .
return '<div style="border: 1px solid black">' .
"Datum: " .
date("Y-m-d") .
"<br />" .
"Eingeloggt als <strong>" .
htmlspecialchars($_SESSION["user"]["username"]) .
"</strong>.<br />" .
'<a href="logout.php">Sitzung beenden</a>' .
'</div>';
"</div>";
}
/** Checking if an action is allowed. A present apiKey overrides (and deletes) a present login.
@@ -114,40 +124,81 @@ class participo
*
* @retval void
*/
public static function authentificate($action = 'login')
public static function authenticate($action = "login")
{
// Ensure a session is started
session_start();
// check if an apiKey was received
if (array_key_exists('apiKey', $_GET)) {
if (array_key_exists("apiKey", $_GET)) {
self::logout();
$key = ApiKey::loadFromDb($_GET['apiKey']);
$key = ApiKey::loadFromDb($_GET["apiKey"]);
if (isset($key) && $key->isValidFor($action)) {
$user = User::loadFromDb($key->getUserId());
// case valid login: Set the session data
$_SESSION = [
'login' => true, //false,
'apiKey' => $key->getKey(),
'user' => [
'username' => $user->getLoginName(),
'userId' => $user->getId(),
'userConfig' => $user->getConfig(),
]
"login" => true, //false,
"apiKey" => $key->getKey(),
"user" => [
"username" => $user->getLoginName(),
"userId" => $user->getId(),
"userConfig" => $user->getConfig(),
],
];
logLoginsToJsonFile($user->getLoginName());
// we're not logged in, but authorized for the stuff we want to do. So don't redirect
return;
};
} else {
participo::addMessage("error", "Api key invalid (e.g., deprecated)");
}
}
// if not returned yet: no login, no valid apiKey -> redirect to login page
// if not returned yet: no login, no valid apiKey -> redirect to login page but remove the api key rom the query
if (!self::isLoginValid()) {
header('Location: login?returnToUrl=' . urlencode($_SERVER['REQUEST_URI'] . ($_POST['fragment'] ?? '')), true, 301);
header(
"Location: login?returnToUrl=" .
urlencode(
participo::removeQueryParameter($_SERVER["REQUEST_URI"], "apiKey") . ($_POST["fragment"] ?? "")
),
true,
301
);
exit(); // shouldn't matter
}
}
/**
* remove query parameter from an url
*
* @param [string] $url url to clean of a query parameter
* @param [string] $param query parameter to remove
*
* @return [string] input url with query parameter (key and value) removed
*/
public static function removeQueryParameter(string $url, string $param): string
{
if (str_contains($url, "?")) {
list($baseUrl, $urlQuery) = explode('?', $url, 2);
parse_str($urlQuery, $urlQueryArr);
unset($urlQueryArr[$param]);
if (count($urlQueryArr)) {
return $baseUrl . '?' . http_build_query($urlQueryArr);
}
}
return $url;
}
/**
* Store persistent data in the session data
*/
public static function shutdown(){
$_SESSION["participo"] = [
"messages" => participo::getMessages()
];
}
/** Initialize the participoApp
*
* - validate the login
@@ -158,13 +209,33 @@ class participo
*/
public static function init($config)
{
self::authentificate();
// setup the storing of
register_shutdown_function("participo::shutdown");
// set up a database connection
self::initDb(
$config['db']['host'],
$config['db']['name'],
$config['db']['user'],
$config['db']['password']
$config["db"]["host"],
$config["db"]["name"],
$config["db"]["user"],
$config["db"]["password"]
);
// authenticate the user
self::authenticate();
// init the participo app
// - get stored messages from the session data
self::initMessages();
}
/**
* Move the messages from the session data into the participo app
*
* - move means the source gets deleted after copying
*/
private static function initMessages() : void
{
self::$message = $_SESSION["participo"]["messages"] ?? ["error" => null, "success" => null, "notice" => null];
unset($_SESSION["participo"]["messages"]);
}
private static function initDb($host, $name, $user, $password)
@@ -178,12 +249,12 @@ class participo
* - Params in the request that aren't in given a parsing function aren't parsed and hence not returned.
*
* @param [array(paramName => parseFunction)] $params array of the name of the param and a sanitizer/parsing/input function
* @return array(parsedParam=>paramValue) Associative array of the name of the param and its parsed value
* @return [array(parsedParam=>paramValue)] Associative array of the name of the param and its parsed value
*/
public static function parseParams($params)
{
$method = $_SERVER['REQUEST_METHOD'];
$request = explode('/', substr(@$_SERVER['PATH_INFO'], 1));
$method = $_SERVER["REQUEST_METHOD"];
// $request = explode("/", substr($_SERVER["PATH_INFO"], 1));
$parsedParams = [];
foreach ($params as $paramName => $parseFunction) {
@@ -192,11 +263,15 @@ class participo
// case 'PUT':
// do_something_with_put($request);
// break;
case 'POST':
$parsedParams[$paramName] = $parseFunction($_POST[$paramName]);
case "POST":
$parsedParams[$paramName] = $parseFunction(
$_POST[$paramName] ?? null
);
break;
case 'GET':
$parsedParams[$paramName] = $parseFunction($_GET[$paramName]);
case "GET":
$parsedParams[$paramName] = $parseFunction(
$_GET[$paramName] ?? null
);
break;
default:
// handle_error($request);
@@ -213,9 +288,14 @@ class participo
public static function addMessage($type, $message)
{
self::$message[$type] = (self::$message[$type] ?? '') . $message;
self::$message[$type] = (self::$message[$type] ?? "") . $message;
}
// public static function htmlEchoMessages(){
// echo(htmlRetMessage(participo::getMessages()));
// self::$message = null;
// }
/** check password for user
*
* @param string $loginName user who wants to get in
@@ -230,7 +310,7 @@ class participo
// Check for dbConnection
if (!dbConnector::getDbConnection()) {
self::addMessage('error', '<div>No DbConnection available</div>');
self::addMessage("error", "<div>No DbConnection available</div>");
return false;
}
@@ -239,25 +319,28 @@ class participo
// If there is no such user OR the password isn't valid the login fails
if ($user == null || !$user->verifyPassword($password)) {
sleep(5); // discourage brute force attacks
self::addMessage('error', '<div>Falsches Passwort oder LoginName</div>');
self::addMessage(
"error",
"<div>Falsches Passwort oder LoginName</div>"
);
return false;
}
session_start();
// case valid login: Set the session data
$_SESSION = [
'login' => true,
'user' => [
'username' => $user->getLoginName(),
'userId' => $user->getId(),
'userConfig' => $user->getConfig()
]
"login" => true,
"user" => [
"username" => $user->getLoginName(),
"userId" => $user->getId(),
"userConfig" => $user->getConfig(),
],
];
// Logging Logins
logLoginsToJsonFile($_SESSION['user']['username']);
logLoginsToJsonFile($_SESSION["user"]["username"]);
self::addMessage('success', '<div>Anmeldung erfolgreich</div>');
self::addMessage("success", "<div>Anmeldung erfolgreich</div>");
return true;
}
@@ -269,35 +352,35 @@ class participo
*/
public static function isUserAdmin($userId = null)
{
$userId = $userId ?? $_SESSION['user']['userId'];
return self::hasUserAttribute($userId, 'isAdmin');
$userId = $userId ?? $_SESSION["user"]["userId"];
return self::hasUserAttribute($userId, "isAdmin");
}
public static function getUserId()
{
}
public static function getUserId() {}
/** get current logged in users kids */
public static function getKids($userId = null)
{
$userId = $userId ?? $_SESSION['user']['userId'] ?? null;
$userId = $userId ?? ($_SESSION["user"]["userId"] ?? null);
$query =
'SELECT * FROM `wkParticipo_Users` '
. 'INNER JOIN `vormundschaft` '
. 'ON `wkParticipo_Users`.`id` = `vormundschaft`.`kidId` '
. 'INNER JOIN `wkParticipo_user<=>userAttributes` '
. 'ON `wkParticipo_Users`.`id` = `wkParticipo_user<=>userAttributes`.`userId`'
. 'WHERE `vormundschaft`.`userId` = :userId '
. 'AND `vormundschaft`.`userId` = :userId '
. 'AND `wkParticipo_user<=>userAttributes`.`attributeId` = 4;';
$params = [':userId' => ['value' => $userId, 'data_type' => PDO::PARAM_INT]];
"SELECT * FROM `wkParticipo_Users` " .
"INNER JOIN `vormundschaft` " .
"ON `wkParticipo_Users`.`id` = `vormundschaft`.`kidId` " .
"INNER JOIN `wkParticipo_user<=>userAttributes` " .
"ON `wkParticipo_Users`.`id` = `wkParticipo_user<=>userAttributes`.`userId`" .
"WHERE `vormundschaft`.`userId` = :userId " .
"AND `vormundschaft`.`userId` = :userId " .
"AND `wkParticipo_user<=>userAttributes`.`attributeId` = 4;";
$params = [
":userId" => ["value" => $userId, "data_type" => PDO::PARAM_INT],
];
$response = dbConnector::query($query, $params);
$kids = [];
foreach ($response as $r) {
$kids[] = User::fromDbArray($r, ['id' => 'kidId']);
$kids[] = User::fromDbArray($r, ["id" => "kidId"]);
}
return $kids;
}
@@ -311,17 +394,18 @@ class participo
public static function isWardOf(int $kidId, int $userId = null)
{
// Try to get the Guard from the session data.
$userId = $userId ?? $_SESSION['user']['userId'] ?? null;
$userId = $userId ?? ($_SESSION["user"]["userId"] ?? null);
$query = 'SELECT `kidId` FROM `vormundschaft` WHERE `userId` = :userId AND `kidId` = :kidId;';
$query =
"SELECT `kidId` FROM `vormundschaft` WHERE `userId` = :userId AND `kidId` = :kidId;";
$params = [
':userId' => ['value' => $userId, 'data_type' => PDO::PARAM_INT],
':kidId' => ['value' => $kidId, 'data_type' => PDO::PARAM_INT]
":userId" => ["value" => $userId, "data_type" => PDO::PARAM_INT],
":kidId" => ["value" => $kidId, "data_type" => PDO::PARAM_INT],
];
$response = dbConnector::query($query, $params);
return (count($response) >= 1);
return count($response) >= 1;
}
/** Checks, if a user as a certain attribute
@@ -340,13 +424,16 @@ ON `wkParticipo_user<=>userAttributes`.`attributeId` = `wkParticipo_userAttribut
WHERE `wkParticipo_userAttributes`.name = :attributeName AND userId=:userId;
SQL;
$params = [
':userId' => ['value' => $userId, 'data_type' => PDO::PARAM_INT],
':attributeName' => ['value' => $attributeName, 'data_type' => PDO::PARAM_STR]
":userId" => ["value" => $userId, "data_type" => PDO::PARAM_INT],
":attributeName" => [
"value" => $attributeName,
"data_type" => PDO::PARAM_STR,
],
];
$attributedUsers = dbConnector::query($query, $params);
// Since the id should be unique, there should only be one result this is just for dealing with empty arrays
foreach ($attributedUsers as $u) {
if ($u['userId'] == $userId) {
if ($u["userId"] == $userId) {
return true;
}
}
@@ -355,9 +442,9 @@ SQL;
public static function getEventStarter($sinceDate = null)
{
$userId = $_SESSION['user']['userId'];
$userId = $_SESSION["user"]["userId"];
if (!$sinceDate) {
$sinceDate = 'CURDATE()';
$sinceDate = "CURDATE()";
} else {
$sinceDate = 'DATE("' . $sinceDate . '")';
}
@@ -387,14 +474,14 @@ SQL;
class AppCardAction
{
private $caption = null; //< Caption for the action
private $link = '.'; //< link for the action
private $link = "."; //< link for the action
/** Constructor for the AppAction
*
* @param string $caption caption for the action
* @param string $link link to the action
*/
public function __construct($caption, $link = '.')
public function __construct($caption, $link = ".")
{
//! @todo input sanitation
$this->link = $link;
@@ -407,7 +494,7 @@ class AppCardAction
*/
public function htmlCode()
{
return '<a href="' . $this->link . '">' . $this->caption . '</a>';
return '<a href="' . $this->link . '">' . $this->caption . "</a>";
}
/** Create AppCardAction from assoziative array
@@ -417,8 +504,8 @@ class AppCardAction
*/
public static function fromArray($member)
{
$caption = $member['caption'] ?? null;
$link = $member['link'] ?? '.';
$caption = $member["caption"] ?? null;
$link = $member["link"] ?? ".";
return new AppCardAction($caption, $link);
}
}
@@ -427,8 +514,8 @@ class AppCardAction
*/
class AppCard
{
private $title = ''; //< title of the card
private $description = ''; //< description of the App
private $title = ""; //< title of the card
private $description = ""; //< description of the App
private $link = null; //< link for the card-content
private $imgUrl = null; //< url for an image right under the title
private $actionList = []; //< list of actions for the bottom of the card
@@ -442,8 +529,13 @@ class AppCard
* @param string $imgUrl url for an image right under the title
* @param array $actionList list of actions at the bottom of the card
*/
public function __construct($title, $description, $link = null, $imgUrl = null, $actionList = [])
{
public function __construct(
$title,
$description,
$link = null,
$imgUrl = null,
$actionList = []
) {
//! @todo input sanitation
$this->title = $title;
$this->description = $description;
@@ -459,22 +551,37 @@ class AppCard
*/
public function htmlCode($options = [])
{
$extraClass = $options['extraClass'] ?? '';
$actionListCode = '';
$extraClass = $options["extraClass"] ?? "";
$actionListCode = "";
foreach ($this->actionList as $a) {
$actionListCode .= $a->htmlCode();
}
return
'<div style="padding:1%;" class="col s12 m6 ' . $extraClass . '">' .
return '<div style="padding:1%;" class="col s12 m6 ' .
$extraClass .
'">' .
'<div style="margin:1%;" class="card blue-grey darken-1">' .
'<div class="card-content white-text">' .
(($this->link != null) ? ('<a href="' . $this->link . '">') : ('')) . '<span class="card-title">' . $this->title . '</span>' . (($this->link != null) ? ('</a>') : ('')) .
(($this->imgUrl != null) ? ('<img alt="' . $this->title . '" style="display:block;margin-left:auto;margin-right:auto;max-height:10vh;" class="responsive-img" src="' . $this->imgUrl . '" />') : ('')) .
'<p>' . $this->description . '</p>' .
'</div>' .
'<div class="card-action">' . $actionListCode . '</div>' .
'</div>' .
'</div>';
($this->link != null ? '<a href="' . $this->link . '">' : "") .
'<span class="card-title">' .
$this->title .
"</span>" .
($this->link != null ? "</a>" : "") .
($this->imgUrl != null
? '<img alt="' .
$this->title .
'" style="display:block;margin-left:auto;margin-right:auto;max-height:10vh;" class="responsive-img" src="' .
$this->imgUrl .
'" />'
: "") .
"<p>" .
$this->description .
"</p>" .
"</div>" .
'<div class="card-action">' .
$actionListCode .
"</div>" .
"</div>" .
"</div>";
}
/**
@@ -485,11 +592,11 @@ class AppCard
*/
public static function fromArray($member)
{
$title = $member['title'] ?? '';
$description = $member['description'] ?? '';
$link = $member['link'] ?? null;
$imgUrl = $member['imgUrl'] ?? null;
$actionList = $member['actions'] ?? [];
$title = $member["title"] ?? "";
$description = $member["description"] ?? "";
$link = $member["link"] ?? null;
$imgUrl = $member["imgUrl"] ?? null;
$actionList = $member["actions"] ?? [];
return new AppCard($title, $description, $link, $imgUrl, $actionList);
}
@@ -500,7 +607,7 @@ class AppCard
* @param string $jsonFileName path to the json file with the logged logins
* @return string Html table of users last logins
*/
function lastLoginTable($jsonFileName = 'lastLogins.json')
function lastLoginTable($jsonFileName = "lastLogins.json")
{
// load the jsonfile into an associative array
$lastLogins = json_decode(file_get_contents($jsonFileName), true);
@@ -508,57 +615,55 @@ function lastLoginTable($jsonFileName = 'lastLogins.json')
// collecting the last login of the users ...
$lastLoginRows = [];
foreach ($lastLogins as $userName => $lastLogins) {
$lastLoginRows[$userName] = $lastLogins['lastLogins'][0];
$lastLoginRows[$userName] = $lastLogins["lastLogins"][0];
}
// and sort it so the last login is first in line
arsort($lastLoginRows);
// build the table
$lastLoginsTable =
'<table>' .
'<thead><tr><th>userName</th><th>lastLogin</th></tr></thead>' .
'<tbody>';
"<table>" .
"<thead><tr><th>userName</th><th>lastLogin</th></tr></thead>" .
"<tbody>";
foreach ($lastLoginRows as $userName => $lastLogin) {
$lastLoginsTable .=
'<tr><td>' . $userName . '</td><td>' . $lastLogin . '</td></tr>';
"<tr><td>" . $userName . "</td><td>" . $lastLogin . "</td></tr>";
}
$lastLoginsTable .=
'</tbody>' .
'</table>';
$lastLoginsTable .= "</tbody>" . "</table>";
return $lastLoginsTable;
}
/// Eine Fehler/Warnung/Notiz/Erfolgsmeldung als divBox im String zurückgeben
function htmlRetMessage($anRetMessage)
{
$retHtmlString = '';
$retHtmlString = "";
if (!empty($anRetMessage)) {
$retHtmlString .= '<div style="border: 1px solid;">';
if (!empty($anRetMessage['error'])) {
if (!empty($anRetMessage["error"])) {
$retHtmlString .= '<div style="border: 1px solid;">';
$retHtmlString .= 'ERROR:<br />';
$retHtmlString .= $anRetMessage['error'];
$retHtmlString .= '</div>';
$retHtmlString .= "ERROR:<br />";
$retHtmlString .= $anRetMessage["error"];
$retHtmlString .= "</div>";
}
if (!empty($anRetMessage['warning'])) {
if (!empty($anRetMessage["warning"])) {
$retHtmlString .= '<div style="border: 1px solid;">';
$retHtmlString .= 'WARNING:<br />';
$retHtmlString .= $anRetMessage['warning'];
$retHtmlString .= '</div>';
$retHtmlString .= "WARNING:<br />";
$retHtmlString .= $anRetMessage["warning"];
$retHtmlString .= "</div>";
}
if (!empty($anRetMessage['notice'])) {
if (!empty($anRetMessage["notice"])) {
$retHtmlString .= '<div style="border: 1px solid;">';
$retHtmlString .= 'Info:<br />';
$retHtmlString .= $anRetMessage['notice'];
$retHtmlString .= '</div>';
$retHtmlString .= "Info:<br />";
$retHtmlString .= $anRetMessage["notice"];
$retHtmlString .= "</div>";
}
if (!empty($anRetMessage['success'])) {
if (!empty($anRetMessage["success"])) {
$retHtmlString .= '<div style="border: 1px solid;">';
$retHtmlString .= 'SUCCESS:<br />';
$retHtmlString .= $anRetMessage['success'];
$retHtmlString .= '</div>';
$retHtmlString .= "SUCCESS:<br />";
$retHtmlString .= $anRetMessage["success"];
$retHtmlString .= "</div>";
}
$retHtmlString .= '</div>';
$retHtmlString .= "</div>";
}
return $retHtmlString;
}
@@ -572,39 +677,37 @@ function loadMarkdownFile($fileName)
{
// load the whole file
$fileText = file_get_contents($fileName);
// split at '---' to get ((),yamls,array)
// split at '---' to get ((),yaml,array)
$fileParts = preg_split('/[\n]*[-]{3}[\n]/', $fileText, 3);
// not all mdFiles have a yamlHeader, so the mdText can be at different indices
$yaml = [];
$mdText = '';
switch(count($fileParts)) {
case 1:{
$mdText = "";
switch (count($fileParts)) {
case 1:
$mdText = $fileParts[0];
break;
}
case 3:{
case 3:
$yaml = Spyc::YAMLLoadString($fileParts[1]);
$mdText = $fileParts[2];
break;
}
default:{
default:
$mdText = $fileText;
}
}
// get a title, if none is in the markdown
if (!array_key_exists('title', $yaml)) {
if (!array_key_exists("title", $yaml)) {
// find the first heading, set it as header and remove it from the markdown
if (preg_match('/^#(.*)$/m', $mdText, $matches)) {
$yaml['title'] = $matches[1];
$mdText = preg_replace('/^#(.*)$/m', '', $mdText, 1);
$yaml["title"] = $matches[1];
$mdText = preg_replace('/^#(.*)$/m', "", $mdText, 1);
} else {
// fallback for the title, if not even one heading is found
$yaml['title'] = '<fehlender Titel>';
$yaml["title"] = "<fehlender Titel>";
}
}
return [
'yaml' => $yaml, 'mdText' => $mdText
"yaml" => $yaml,
"mdText" => $mdText,
];
}
@@ -614,7 +717,7 @@ function loadMarkdownFile($fileName)
* @param string $fileName filename to log to
* @return void
*/
function logLoginsToJsonFile($userName, $fileName = 'lastLogins.json')
function logLoginsToJsonFile($userName, $fileName = "lastLogins.json")
{
try {
$lastLogins = json_decode(file_get_contents($fileName), true);
@@ -624,14 +727,16 @@ function logLoginsToJsonFile($userName, $fileName = 'lastLogins.json')
if (!array_key_exists($userName, $lastLogins)) {
$lastLogins[$userName] = [];
}
if (!array_key_exists('lastLogins', $lastLogins[$userName])) {
$lastLogins[$userName]['lastLogins'] = [];
if (!array_key_exists("lastLogins", $lastLogins[$userName])) {
$lastLogins[$userName]["lastLogins"] = [];
}
$usersLastLogins = $lastLogins[$userName]['lastLogins'];
$usersLastLogins = array_merge([date('Y-m-d H:i:s')], $usersLastLogins);
$usersLastLogins = $lastLogins[$userName]["lastLogins"];
$usersLastLogins = array_merge([date("Y-m-d H:i:s")], $usersLastLogins);
$usersLastLogins = array_slice($usersLastLogins, 0, 10);
$lastLogins[$userName]['lastLogins'] = $usersLastLogins;
$lastLogins[$userName]["lastLogins"] = $usersLastLogins;
if (is_writable($fileName)) {
file_put_contents($fileName, json_encode($lastLogins));
}
} catch (Exception $e) {
// silently ignore errors
}
@@ -640,15 +745,19 @@ function logLoginsToJsonFile($userName, $fileName = 'lastLogins.json')
/// @brief Gibt die URL der gerade aufgerufenen Seite zurück
function getCurPagesUrl()
{
$pageURL = 'http';
if ( array_key_exists("HTTPS", $_SERVER) && ($_SERVER['HTTPS'] == 'on')) {
$pageURL .= 's';
$pageURL = "http";
if (array_key_exists("HTTPS", $_SERVER) && $_SERVER["HTTPS"] == "on") {
$pageURL .= "s";
}
$pageURL .= '://';
if ($_SERVER['SERVER_PORT'] != '80') {
$pageURL .= $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['REQUEST_URI'];
$pageURL .= "://";
if ($_SERVER["SERVER_PORT"] != "80") {
$pageURL .=
$_SERVER["SERVER_NAME"] .
":" .
$_SERVER["SERVER_PORT"] .
$_SERVER["REQUEST_URI"];
} else {
$pageURL .= $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
$pageURL .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
}
return $pageURL;
}
@@ -660,20 +769,25 @@ function getCurPagesUrl()
*/
function getHtmlSquareDate($date = null)
{
$date = $date ?? new DateTime;
$date = $date ?? new DateTime();
$year = $date->format('Y');
$month = $date->format('M');
$day = $date->format('d');
$year = $date->format("Y");
$month = $date->format("M");
$day = $date->format("d");
return
'<div>'
. '<div>'
. '<span style="font-size:large">' . $day . '</span>'
. '<span style="writing-mode: sideways-lr">' . $month . '</span>'
. '</div>'
. '<div style="font-size: small">' . $year . '</div>'
. '</div>';
return "<div>" .
"<div>" .
'<span style="font-size:large">' .
$day .
"</span>" .
'<span style="writing-mode: sideways-lr">' .
$month .
"</span>" .
"</div>" .
'<div style="font-size: small">' .
$year .
"</div>" .
"</div>";
}
/** filter_var for a pos int
@@ -686,7 +800,9 @@ function getHtmlSquareDate($date = null)
* */
function filterPosInt($id)
{
return filter_var($id, FILTER_VALIDATE_INT, ['options' => ['default' => null, 'min_range' => 1]]);
return filter_var($id, FILTER_VALIDATE_INT, [
"options" => ["default" => null, "min_range" => 1],
]);
}
/** filter_var for a (db)id
@@ -713,5 +829,7 @@ function filterId($id)
*/
function filterCount($variable, int $min = 0)
{
return filter_var($variable, FILTER_VALIDATE_INT, ['options' => ['default' => null, 'min_range' => 1]]);
return filter_var($variable, FILTER_VALIDATE_INT, [
"options" => ["default" => null, "min_range" => 1],
]);
}

View File

@@ -1,12 +1,10 @@
<?php
require_once 'config/participo.php';
require_once $config['home'] . '/.local/cwsvJudo.config.php';
require_once 'participoLib/participo.php';
require_once 'participoLib/apiKey.php';
require_once './local/dbConf.php';
require_once $config['home'] . '/.local/cwsvJudo.config.php';
$dbConnection = dbConnector::connect(
$cwsvJudoConfig['db']['host'],
@@ -14,9 +12,9 @@ $dbConnection = dbConnector::connect(
$cwsvJudoConfig['db']['user'],
$cwsvJudoConfig['db']['password']
);
// Check, if the login is already set. If so move to the main page (or the returnToUrl)
if (isset($_SESSION['login'])) {
if (isset($_SESSION) && isset($_SESSION['login'])) {
// @todo prevent self redirection
header('Location: http://' . ($_POST['returnToUrl'] ?? '.'), true, 301);
}
@@ -46,53 +44,60 @@ else {
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- includes of neccessary libs -->
<!-- includes of necessary libs -->
<?php readfile('./shared/imports.php'); ?>
<title>cwsvJudo Online Apps</title>
<meta name="description" content="Loginseite der Online-Apps der Judoka des CWSV">
<meta name="description" content="Login-Seite der Online-Apps der Judoka des CWSV">
</head>
<body class="container">
<h1>Loginseite der Online-Apps der Judoka des CWSV</h1>
<body>
<h1>Login-Seite der Online-Apps der Judoka des CWSV</h1>
<?php echo(htmlRetMessage(participo::getMessages())); ?>
<form action="./login.php" method="post">
<fieldset>
<legend>Benutzerdaten</legend>
<div>
<label for="username">Benutzername</label>
<div class="container">
<div class="row">
<div class="col s6 offset-s3 z-depth-1">
<h2 id="title">Benutzerdaten</h2>
<form id="loginForm" action="./login.php" method="post">
<div class="input-field">
<input id="username" type="text" name="f[username]" <?php echo isset($_POST['f']['username']) ? ' value="' . htmlspecialchars($_POST['f']['username']) . '"' : '' ?> />
<label for="username">Benutzername</label>
</div>
<div>
<label for="password">Kennnwort</label>
<div class="input-field">
<input id="password" type="password" name="f[password]" />
<label for="password">Kennwort</label>
</div>
<?php if (isset($_GET['returnToUrl'])) {
<?php # If a return url was given, add it as input to the form
if (isset($_GET['returnToUrl'])) {
echo('<input type="hidden" name="returnToUrl" value="' . htmlspecialchars($_GET['returnToUrl']) . '" />');
} ?>
<?php if (isset($_POST['returnToUrl'])) {
echo('<input type="hidden" name="returnToUrl" value="' . htmlspecialchars($_POST['returnToUrl']) . '" />');
} ?>
}
?>
<input id="fragment" type="hidden" name="fragment" />
<!-- add the fragment to the post data-->
<!-- add the fragment (stuff behind the # in the url) to the post data -->
<script>
if(window.location.hash){
document.getElementById("fragment").value=window.location.hash;
}
</script>
</fieldset>
<fieldset>
<div>
<input type="submit" name="submit" value="Anmelden" />
</div>
</fieldset>
<!-- <p>
<input type="checkbox" id="remember"/>
<label for="remember" id="checkbox" >Remember me</label>
</p> -->
<input type="submit" name="submit" value="Anmelden" class="waves-effect waves-light btn" id="submitButton" />
<fieldset class="notice"><legend>Hinweise</legend>
<ul style="padding-left: inherit;">
<li style="list-style-type: circle;" >Logindaten sollten vom Übungsleiter vergeben worden sein.</li>
<ul><li style="list-style-type: circle;">Verlorene oder vergessene Logins oder Passwörter können über den Übungsleiter neu vergeben werden.</li></ul>
<li style="list-style-type: circle;" >Dieses Projekt ist in mehr oder weniger aktiven Entwicklung. Sollte mal was nicht funktionieren, kann es sein, dass ich gerade daran herumschreibe. Also ruhig zu einem späteren Zeitpunkt noch einmal probieren.</li>
<li style="list-style-type: circle;" >Dieses Projekt ist in mehr oder weniger aktiven Entwicklung. Sollte mal was nicht funktionieren, kann es sein, dass ich gerade daran herum schreibe. Also ruhig zu einem späteren Zeitpunkt noch einmal probieren.</li>
</ul>
</fieldset>
</form>
</div>
</div>
</div>
</body>
</html>

View File

@@ -4,13 +4,13 @@
if (ini_get('session.use_cookies')) {
$params = session_get_cookie_params();
setcookie(
session_name(),
$name=session_name(),
'',
time() - 42000,
$params['path'],
$params['domain'],
$params['secure"'],
$params['httponly']
$expires=(time() - 42000),
$path=$params['path'] ?? "",
$domain=$params['domain'] ?? "",
$params['secure"'] ?? false,
$params['httponly'] ?? false
);
}
session_destroy();

View File

@@ -9,8 +9,8 @@ require_once './lib/participoLib/participo.php';
require_once './lib/db.php';
require_once './lib/api.php';
require_once $config['basePath'] . '/config/cwsvJudo.config.php';
require_once $config['basePath'] . '/config/phpcount.config.php';
require_once $config["home"] . "/.local/cwsvJudo.config.php";
// require_once $config['basePath'] . '/config/phpcount.config.php';
dbConnector::connect(
$cwsvJudoConfig['db']['host'],
@@ -19,7 +19,7 @@ dbConnector::connect(
$cwsvJudoConfig['db']['password']
);
participo::authentificate();
participo::authenticate();
$user = participo::sessionUser();
$usersKids = getUsersKids(dbConnector::getDbConnection(), $_SESSION['user']['userId']);

View File

@@ -16,12 +16,15 @@ services:
# nginx config file
- ./nginx.conf:/etc/nginx/conf.d/nginx.conf
# the app itself
- ./cwsvjudo@bplaced/www/participo:/home/cwsvjudo/httpdocs/participo
- ./cwsvjudo@bplaced/www/participo:/home/cwsvjudo/httpdocs/participo:rw
# the apps config files
- ./config-heliohost/cwsvJudo.config.php:/home/cwsvjudo/.local/cwsvJudo.config.php
# ressourcen
- /home/marko/cwsvJudo/submodules/materialize/dist:/home/cwsvjudo/httpdocs/ressourcen/materializeCss
- /home/marko/cwsvJudo/homepage/cwsvJudo/build/graphiken:/home/cwsvjudo/httpdocs/ressourcen/graphiken
# libs
- /home/marko/cwsvJudo/submodules/parsedown:/home/cwsvjudo/httpdocs/ressourcen/phpLib/parsedown
- /home/marko/cwsvJudo/submodules/spyc:/home/cwsvjudo/httpdocs/ressourcen/phpLib/Spyc
# php and extensions
php:
# use pre-build image from docker..
@@ -37,6 +40,9 @@ services:
- ./cwsvjudo@bplaced/www/participo:/home/cwsvjudo/httpdocs/participo
# the apps config files
- ./config-heliohost/cwsvJudo.config.php:/home/cwsvjudo/.local/cwsvJudo.config.php
# libs
- /home/marko/cwsvJudo/submodules/parsedown/Parsedown.php:/home/cwsvjudo/httpdocs/ressourcen/phpLib/parsedown/Parsedown.php
- /home/marko/cwsvJudo/submodules/spyc/Spyc.php:/home/cwsvjudo/httpdocs/ressourcen/phpLib/Spyc/Spyc.php
# @todo Maybe use postgre instead?
database:
image: mariadb:latest
@@ -45,8 +51,8 @@ services:
# @todo Should credentials be placed here? Even if it is just a test environment
environment:
# MYSQL_TCP_PORT: 1433
MYSQL_USER: 'cwsvjudo'
MYSQL_DATABASE: 'cwsvjudo'
MYSQL_USER: "cwsvjudo"
MYSQL_DATABASE: "cwsvjudo"
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
MYSQL_PASSWORD_FILE: /run/secrets/db_password
volumes:
@@ -64,6 +70,7 @@ services:
restart: always
depends_on:
- database
- php
ports:
- 8080:80
environment:

View File

@@ -0,0 +1,3 @@
.venv
__pycache__

View File

@@ -0,0 +1,15 @@
PY=python
.PHONY: RUN
RUN: INSTALL
. ./run-tests
.PHONY: INSTALL
INSTALL: .venv
.PHONY: CLEAN
CLEAN:
rm -rf .venv
.venv: requirements.txt
. ./init-venv

View File

@@ -0,0 +1,3 @@
[credentials]
user = "____"
password = "****"

View File

@@ -0,0 +1,10 @@
[credentials]
username = "marko"
password = "kodokan"
[url]
home = "http://127.0.0.1/participo"
# home = "http://cwsvjudo.bplaced.net/participo"
[settings]
headless = true

View File

@@ -0,0 +1,86 @@
import logging
from selenium.webdriver.common.by import By
def load_config(config_path: str = "config.toml"):
from tomllib import load
with open(file=config_path, mode="rb") as config_file:
return load(config_file)
class Participo:
def __init__(self) -> None:
from selenium.webdriver import Firefox, FirefoxOptions
self.config = load_config()
options = FirefoxOptions()
if self.config["settings"]["headless"]:
options.add_argument("-headless")
self.driver = Firefox(options=options)
self.delay = 5
def __enter__(self):
self.get_home()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.driver.quit()
def get_home(self):
self.driver.get(url=self.config["url"]["home"])
def load_section(self, section: str):
from urllib3.exceptions import ReadTimeoutError
section_url = "/".join((self.config["url"]["home"], section))
try:
self.driver.get(url=section_url)
except ReadTimeoutError as e:
logging.warning(
"\n".join(
(
f"TimeoutError loading {section} ({e} - {repr(e)})",
f"- Check for missing resources on section/page {section}",
)
)
)
def login(self):
credentials = self.config["credentials"]
self.driver.find_element(by=By.ID, value="username").send_keys(
credentials["username"]
)
self.driver.find_element(by=By.ID, value="password").send_keys(
credentials["password"]
)
self.driver.find_element(by=By.TAG_NAME, value="form").submit()
def check_login(self):
return self.check_for(By.LINK_TEXT, "Logout")
def check_for_xdebug_msgs(self):
classes = ("xdebug-error", "xe-warning")
return any((self.check_for(By.CLASS_NAME, c) for c in classes))
def check_for(self, selector: str, value: str) -> bool:
from selenium.common.exceptions import NoSuchElementException, TimeoutException
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
try:
_ = WebDriverWait(driver=self.driver, timeout=self.delay).until(
EC.presence_of_element_located(locator=(selector, value))
)
return True
except NoSuchElementException:
logging.info(f"No such element ({selector}, {value})")
return False
except TimeoutException:
return False

View File

@@ -0,0 +1,8 @@
#! /usr/bin/env bash
PY=python
${PY} -m venv .venv
. .venv/bin/activate
${PY} -m pip install --upgrade pip
${PY} -m pip install --requirement requirements.txt

View File

@@ -0,0 +1 @@
selenium

View File

@@ -0,0 +1,7 @@
#! /usr/bin/env bash
PY=python
. .venv/bin/activate
${PY} test_main.py
deactivate

View File

@@ -0,0 +1,34 @@
#! /usr/bin/env python
# testing the participo app
import unittest
import logging
from helper import Participo
class TestParticipo(unittest.TestCase):
def test_login(self):
with Participo() as participo:
participo.login()
self.assertTrue(participo.check_login(), "Login failed")
def test_sub_pages(self):
with Participo() as participo:
participo.login()
self.assertTrue(participo.check_login())
sections = ("events", "infoZettel", "attendance", "user", "logout")
for section in sections:
with self.subTest(msg=f"- {section}"):
participo.load_section(section=section)
self.assertFalse(
expr=participo.check_for_xdebug_msgs(),
msg=f"php errors on section {section}",
)
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
unittest.main()

View File

@@ -21,3 +21,8 @@ buildMaterialize: updateSubmodules
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
.PHONY: clean
clean:
git submodule foreach git clean -xdf
git submodule foreach git restore .