Compare commits
173 Commits
bd151ab4e6
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| c44f035dcd | |||
|
|
8543ebac7f | ||
|
|
4de6df7175 | ||
|
|
1dabcfbe0b | ||
| d299edd10d | |||
| 9757e58998 | |||
| a0f70c6619 | |||
| 63cbfb3681 | |||
| 1e1617eb53 | |||
| b1dbebf17f | |||
| 4eb299339e | |||
| b6b82cae41 | |||
| 807aa70719 | |||
|
|
53a614c5fd | ||
| bd49027ad6 | |||
| 1b5d515724 | |||
| a22dbd7eaf | |||
| 8de033b58b | |||
| aebe6508d1 | |||
| 9b3d8a18fc | |||
| 5da1fbf71c | |||
| dd962a7cd5 | |||
| d2ebd3d81e | |||
| d9a915bfce | |||
| 0a0b7d4f4e | |||
| e653a6667e | |||
| e4604649cc | |||
| 4742e2a9f8 | |||
| fb3c107e1a | |||
| b00f652283 | |||
|
|
4fc04c2793 | ||
|
|
03a3c03433 | ||
|
|
064180f0a5 | ||
|
|
a7f8efe628 | ||
| 05b56f50ac | |||
| 6371f25a47 | |||
| 86f2adf668 | |||
| 10233f019e | |||
| b9a628bee6 | |||
| f7a47dd91f | |||
| 916429ea72 | |||
| 3b7df5e29d | |||
| 153e5d6305 | |||
|
|
44c0cfcfae | ||
| ffb8e552d2 | |||
| 9b4d159615 | |||
| 949a9dfe62 | |||
| afa288e702 | |||
| a20749d900 | |||
| a67d1eb05b | |||
| 26ec6de1e3 | |||
| 95837394a9 | |||
| cd65cba8c4 | |||
| 1dc90e8e36 | |||
| 41e14cdfa0 | |||
| 8bc91a14f5 | |||
| e944c552ba | |||
| 3d9a948beb | |||
| 9571c10db3 | |||
| 751a764c34 | |||
|
|
5879a462de | ||
|
|
000c964317 | ||
|
|
9f3ca1153f | ||
|
|
503afa3cee | ||
|
|
6ad5deab10 | ||
|
|
9c9dad6efb | ||
|
|
10bf9a8d72 | ||
|
|
4280b6900a | ||
|
|
115fc247c4 | ||
|
|
bdaa417009 | ||
|
|
151e06299d | ||
|
|
99f44c9bb2 | ||
|
|
2f771958d1 | ||
| 0ed5ea12fe | |||
|
|
457dd2efd2 | ||
|
|
7e16ddfa1f | ||
| bb26619858 | |||
| 328633a4b3 | |||
| 19622359f0 | |||
| e03d9ab449 | |||
| 4794f46add | |||
| 46cf4dcd40 | |||
| faacf4ec2d | |||
| a68d94f482 | |||
| 7b79995796 | |||
| af05f1d520 | |||
| 9bded6133e | |||
| 3614ba829c | |||
| e550c42488 | |||
| 4ef26e2b64 | |||
| a19cc42d69 | |||
| d96dc2fae3 | |||
| 9b6e3080c2 | |||
| cca9797f4e | |||
| f54717c798 | |||
| eb50f9f41c | |||
| fa3b3e20fc | |||
| 0126cea6b1 | |||
| 95a564b859 | |||
| 3e26658a38 | |||
| c5615940f1 | |||
| ececc6235c | |||
| 7f7142bcf4 | |||
| 462165e81e | |||
| b4ce0c89ed | |||
| 0d0b69615a | |||
| 6aed7dd976 | |||
| 8508f42216 | |||
| 9c1fd320f7 | |||
| a8e7437eef | |||
| cd0a3005d2 | |||
| 6f0f8041c0 | |||
| 88d1936264 | |||
| ff31a10882 | |||
| e413c7f8fb | |||
| 312c4a1d27 | |||
| 682252503b | |||
| 8f4675ba93 | |||
| a604d2b97d | |||
| 462935bafb | |||
| 33a21003c5 | |||
| dc2fba8dab | |||
| 38f65d6ede | |||
| 604b0fbb74 | |||
| 242cf9583e | |||
| 1909be5314 | |||
| 8656fd5d60 | |||
| 298e8e6cd1 | |||
| eca5c5eab7 | |||
| 0ed8ab9137 | |||
| e9a718ee96 | |||
| 1931547d3c | |||
| 4516486b8e | |||
| fea847afd2 | |||
| 35c496b187 | |||
| cfa964b4c5 | |||
| 460fb6b1ee | |||
| 727a7d3dfb | |||
| 87401267e1 | |||
| 69a4a47b54 | |||
|
|
a63f81eabe | ||
|
|
9d5e02bb01 | ||
| bb51933dd1 | |||
| ef760f0c8e | |||
| 757dca8bf5 | |||
| 40ae06d4b6 | |||
| c720b34c6f | |||
| dc6adf606a | |||
| 9e0d1cfa35 | |||
|
|
34fb71ce07 | ||
| c22b000f46 | |||
| 75b96f4f27 | |||
| 339321a322 | |||
| 5dda6b958d | |||
| ebe969c7de | |||
| b429513ab4 | |||
| 00c2e1ded6 | |||
| 135958c9f0 | |||
| ea4069f8b8 | |||
| ddf13b2413 | |||
|
|
cda6945324 | ||
| 0f13bdea27 | |||
| c3fbb0fc67 | |||
| 12c11b65ba | |||
| 61d7ae9adf | |||
| 916d5c4ac4 | |||
| 7738472559 | |||
| c0b4b08cbb | |||
| 501b893688 | |||
| 9f3aab4033 | |||
| 88ec74af75 | |||
| e343bb8f48 | |||
| 5424eec55d |
48
.gitea/workflows/autoupdate.yml
Normal file
48
.gitea/workflows/autoupdate.yml
Normal file
@@ -0,0 +1,48 @@
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 3 * * 0,1,6' # at 1:01am on Friday, Saturday and Sunday
|
||||
|
||||
# on: [push]
|
||||
|
||||
jobs:
|
||||
update_database:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: All tools we need
|
||||
run: apt update && apt install -y default-jre git php php-dom php-curl php-sqlite3
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: run crawler
|
||||
run: |
|
||||
sed -i "/^error_reporting/c\error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_WARNING & ~E_NOTICE" /etc/php/7.4/cli/php.ini
|
||||
cd crawler
|
||||
php crawler.php
|
||||
git config --global user.email "gitea@haschek.at"
|
||||
git config --global user.name "Gitea"
|
||||
git pull
|
||||
git add data.db
|
||||
git commit -m "update database"
|
||||
git push
|
||||
- name: Configure SSH
|
||||
env:
|
||||
SSH_KEY: ${{ secrets.SSH_KEY }}
|
||||
run: |
|
||||
mkdir -p ~/.ssh/
|
||||
echo "$SSH_KEY" > ~/.ssh/staging.key
|
||||
chmod 600 ~/.ssh/staging.key
|
||||
- name: Run git pull on Server
|
||||
run: |
|
||||
ssh -i ~/.ssh/staging.key -o StrictHostKeyChecking=no -p 22 -o UserKnownHostsFile=/dev/null ${{ secrets.SSH_WEBSERVER_IP }} "cd /var/www/dogstats/ && git pull"
|
||||
|
||||
- name: Prepare
|
||||
id: prep
|
||||
run: |
|
||||
SHORTREF=${GITHUB_SHA::10}
|
||||
|
||||
# Set output parameters.
|
||||
echo ::set-output name=shortref::${SHORTREF}
|
||||
- name: Updating version
|
||||
run: |
|
||||
ssh -i ~/.ssh/staging.key -o StrictHostKeyChecking=no -p 22 -o UserKnownHostsFile=/dev/null ${{ secrets.SSH_WEBSERVER_IP }} "echo v${{ steps.prep.outputs.shortref }} > /var/www/dogstats/web/version.txt"
|
||||
|
||||
|
||||
@@ -19,16 +19,18 @@ jobs:
|
||||
mkdir -p ~/.ssh/
|
||||
echo "$SSH_KEY" > ~/.ssh/staging.key
|
||||
chmod 600 ~/.ssh/staging.key
|
||||
- name: Run docker restart on Server
|
||||
- name: Run git pull on Server
|
||||
run: |
|
||||
ssh -i ~/.ssh/staging.key -o StrictHostKeyChecking=no -p 22 -o UserKnownHostsFile=/dev/null ${{ secrets.SSH_WEBSERVER_IP }} "cd /var/www/dogstats/ && git pull"
|
||||
|
||||
- name: Getting repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: 'dogstats'
|
||||
- name: Building minified CSS
|
||||
run: cd dogstats/tools && ./tailwindcss-linux-x64 -i ../web/css/input.css -o ../web/css/output.css --minify
|
||||
- name: Copying to server
|
||||
run: scp -i ~/.ssh/staging.key -o StrictHostKeyChecking=no -P 22 -o UserKnownHostsFile=/dev/null dogstats/web/css/output.css root@${{ secrets.SSH_WEBSERVER_IP }}:/var/www/dogstats/web/css/.
|
||||
- name: Prepare
|
||||
id: prep
|
||||
run: |
|
||||
SHORTREF=${GITHUB_SHA::10}
|
||||
|
||||
# Set output parameters.
|
||||
echo ::set-output name=shortref::${SHORTREF}
|
||||
- name: Updating version
|
||||
run: |
|
||||
ssh -i ~/.ssh/staging.key -o StrictHostKeyChecking=no -p 22 -o UserKnownHostsFile=/dev/null ${{ secrets.SSH_WEBSERVER_IP }} "echo v${{ steps.prep.outputs.shortref }} > /var/www/dogstats/web/version.txt"
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
web/css/output.css
|
||||
web/version.txt
|
||||
database.sqlite3
|
||||
5
.vscode/extensions.json
vendored
5
.vscode/extensions.json
vendored
@@ -1,12 +1,11 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"zarifprogrammer.tailwind-snippets",
|
||||
"dawhite.mustache",
|
||||
"otovo-oss.htmx-tags",
|
||||
"devsense.phptools-vscode",
|
||||
"bmewburn.vscode-intelephense-client",
|
||||
"github.copilot",
|
||||
"github.copilot-chat",
|
||||
"bradlc.vscode-tailwindcss"
|
||||
"anbuselvanrocky.bootstrap5-vscode",
|
||||
"hansuxdev.bootstrap5-snippets",
|
||||
]
|
||||
}
|
||||
22
.vscode/launch.json
vendored
Normal file
22
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Xdebug server",
|
||||
"type": "php",
|
||||
"request": "launch",
|
||||
"runtimeArgs": [
|
||||
"-S",
|
||||
"localhost:8080",
|
||||
"-t",
|
||||
"web"
|
||||
],
|
||||
"port": 5902,
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "listening on http://localhost:([0-9]+)",
|
||||
"uriFormat": "http://localhost:%s",
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -1,4 +1,8 @@
|
||||
{
|
||||
"html.format.indentInnerHtml": true,
|
||||
"html.format.wrapLineLength": 0
|
||||
"html.format.wrapLineLength": 0,
|
||||
"intelephense.environment.documentRoot": "web/",
|
||||
"terminal.integrated.splitCwd": "workspaceRoot",
|
||||
"phpserver.port": 8080,
|
||||
"phpserver.relativePath": "web/."
|
||||
}
|
||||
29
README.md
29
README.md
@@ -27,6 +27,22 @@ Im Terminal dann Webserver starten
|
||||
2. `php -S localhost:8080`
|
||||
3. Browser auf http://localhost:8080 öffnen
|
||||
|
||||
## oder mit Xdebug
|
||||
|
||||
0. php server vom vorherigen schritt darf nicht laufen
|
||||
1. xdebug installieren (`sudo apt install php-xdebug` oder `sudo apk add php82-pecl-xdebug`)
|
||||
2. So oder so ähnlich muss die config aussehen `/etc/php82/conf.d/50_xdebug.ini`
|
||||
|
||||
```ini
|
||||
[Xdebug]
|
||||
zend_extension=xdebug
|
||||
xdebug.mode=debug,develop
|
||||
xdebug.client_host=host.docker.internal
|
||||
xdebug.client_port=5902 #same port as in launch.json
|
||||
```
|
||||
|
||||
3. Dann im VScode auf debugging -> Grünen pfeil `Xdebug server` drücken
|
||||
|
||||
## Ordnerstruktur
|
||||
|
||||
```
|
||||
@@ -46,3 +62,16 @@ Im Terminal dann Webserver starten
|
||||
└── templates Allgemeine Templates, mal schauen ob benötigt
|
||||
└── partials
|
||||
```
|
||||
|
||||
|
||||
#Colors
|
||||
#041337 - dunkelblau
|
||||
#041337 - hellblau
|
||||
#4c5597 - blau
|
||||
#fefefc - white
|
||||
#c8d2e9 - grau
|
||||
#c9dd55 - hellgrün
|
||||
#c9dd55 - dunkelgrün
|
||||
#f0dcb3 - hellbraun
|
||||
#a98d5d - dunkelbraun
|
||||
#150d05 - schwarz
|
||||
|
||||
1
crawler/README.md
Normal file
1
crawler/README.md
Normal file
@@ -0,0 +1 @@
|
||||
java -jar tabula-1.0.5-jar-with-dependencies.jar --format CSV datei.pdf
|
||||
39
crawler/base.sql
Normal file
39
crawler/base.sql
Normal file
@@ -0,0 +1,39 @@
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE IF NOT EXISTS "events" (
|
||||
"ID" INTEGER UNIQUE,
|
||||
"name" TEXT,
|
||||
"date" TEXT,
|
||||
"organizer" TEXT,
|
||||
PRIMARY KEY("ID")
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "runs" (
|
||||
"id" INTEGER UNIQUE,
|
||||
"event" INTEGER,
|
||||
"name" TEXT,
|
||||
"lk" TEXT,
|
||||
"gk" TEXT,
|
||||
FOREIGN KEY("event") REFERENCES "events"("ID"),
|
||||
PRIMARY KEY("id")
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "results" (
|
||||
"id" INTEGER,
|
||||
"event" INTEGER,
|
||||
"run" INTEGER,
|
||||
"rang" INTEGER,
|
||||
"stnr" INTEGER,
|
||||
"teilnehmer" TEXT,
|
||||
"hund" TEXT,
|
||||
"verein" TEXT,
|
||||
"f" INTEGER,
|
||||
"vw" INTEGER,
|
||||
"zf" INTEGER,
|
||||
"zeit" REAL,
|
||||
"gf" REAL,
|
||||
"msek" REAL,
|
||||
"bew" TEXT,
|
||||
"punkte" TEXT,
|
||||
PRIMARY KEY("id" AUTOINCREMENT),
|
||||
FOREIGN KEY("run") REFERENCES "runs"("id"),
|
||||
FOREIGN KEY("event") REFERENCES "events"("ID")
|
||||
);
|
||||
COMMIT;
|
||||
246
crawler/crawler.php
Normal file
246
crawler/crawler.php
Normal file
@@ -0,0 +1,246 @@
|
||||
<?php
|
||||
|
||||
|
||||
|
||||
$GLOBALS['db'] = new SQLite3('data.db');
|
||||
if(!$GLOBALS['db']) exit("Error loading database");
|
||||
|
||||
// if(!file_exists('tmp/ergebnisse.html'))
|
||||
// {
|
||||
// $ergebnisse = file_get_contents('https://www.dognow.at/ergebnisse/');
|
||||
// file_put_contents('tmp/ergebnisse.html', $ergebnisse);
|
||||
// }
|
||||
|
||||
// $html = file_get_contents('tmp/ergebnisse.html');
|
||||
|
||||
// $dom = new DOMDocument;
|
||||
// $dom->loadHTML($html);
|
||||
|
||||
// $xpath = new DOMXPath($dom);
|
||||
// $query = '//ul[@class="pagination"]/child::*';
|
||||
// $nodes = $xpath->query($query);
|
||||
|
||||
// $GLOBALS['pdfs'] = 0;
|
||||
|
||||
// // Loop through the selected nodes
|
||||
// foreach ($nodes as $node) {
|
||||
// // Do something with each node, for example, echo its content
|
||||
// $url = $node->getElementsByTagName('a')[0]->getAttribute('href');
|
||||
// $number = intval($node->nodeValue);
|
||||
// if($number > $last_page){
|
||||
// $last_page = $number;
|
||||
// }
|
||||
// }
|
||||
|
||||
// echo "[i] Found $last_page pages\n";
|
||||
|
||||
// //create an array with all pages
|
||||
// $pages = range(1,65);
|
||||
|
||||
// foreach($pages as $page)
|
||||
// {
|
||||
// echo "[i] Crawling page $page\n";
|
||||
// scanPage($page);
|
||||
// }
|
||||
|
||||
scanPage(1,false);
|
||||
|
||||
function scanPage($key,$usecache=true)
|
||||
{
|
||||
$page = 'https://www.dognow.at/ergebnisse/?page=' . $key;
|
||||
if(file_exists('tmp/pages/' . ($key) . '.html' && $usecache===true)){
|
||||
$html = file_get_contents($page);
|
||||
}
|
||||
else
|
||||
{
|
||||
$html = file_get_contents($page);
|
||||
file_put_contents('tmp/pages/' . ($key) . '.html', $html);
|
||||
}
|
||||
$dom = new DOMDocument;
|
||||
$dom->loadHTML($html);
|
||||
|
||||
// search for all divs with class "resultboard"
|
||||
$xpath = new DOMXPath($dom);
|
||||
$query = '//div[@class="resultboard info-board info-board-default2"]';
|
||||
$nodes = $xpath->query($query);
|
||||
|
||||
// Loop through the selected nodes
|
||||
foreach ($nodes as $node) {
|
||||
// CUPs
|
||||
$div = $node->getElementsByTagName('div')[0];
|
||||
$id = $div->getAttribute('data-event');
|
||||
$name = trim($div->getElementsByTagName('div')[1]->nodeValue);
|
||||
$organizer = trim($div->getElementsByTagName('div')[2]->nodeValue);
|
||||
$date = trim($div->getElementsByTagName('div')[3]->nodeValue);
|
||||
$db_date = date(DATE_RFC3339, strtotime($date));
|
||||
|
||||
//if not exists, add to db
|
||||
$res = $GLOBALS['db']->query("SELECT * FROM events WHERE id = '$id'");
|
||||
if($res->fetchArray() == false)
|
||||
$GLOBALS['db']->exec("INSERT INTO events (id, name, organizer, date) VALUES ('$id', '$name', '$organizer', '$db_date')");
|
||||
|
||||
crawlRuns($id,$usecache);
|
||||
|
||||
echo " [E] $id - $name - $organizer - $date\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
var_dump($GLOBALS['pdfs']);
|
||||
|
||||
function crawlRuns($eventid,$usecache=true)
|
||||
{
|
||||
if(file_exists('tmp/events/' . $eventid . '.html') && $usecache===true)
|
||||
$data = file_get_contents('tmp/events/' . $eventid . '.html');
|
||||
else
|
||||
{
|
||||
//sleep(1);
|
||||
$data = file_get_contents('https://www.dognow.at/ergebnisse/src/data.php?event='. $eventid .'&lauf=0');
|
||||
file_put_contents('tmp/events/' . $eventid . '.html', $data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//get first table using DOMDocument
|
||||
$dom = new DOMDocument;
|
||||
$dom->loadHTML($data);
|
||||
|
||||
if(strpos($data,"<b>Einzelwertung</b><br>
|
||||
|
||||
Derzeit sind keine Ergebnisse")!==false)
|
||||
{
|
||||
echo " [i] Keine Einzelwertungen\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// when the string "Cup-Wertung" is found
|
||||
if(strpos($data, 'Cup-Wertung') !== false){
|
||||
echo " [i] Found Cup-Wertung, skipping first table\n";
|
||||
$table = $dom->getElementsByTagName('table')[1];
|
||||
}
|
||||
else
|
||||
$table = $dom->getElementsByTagName('table')[0];
|
||||
|
||||
if(!$table) return;
|
||||
|
||||
foreach($table->getElementsByTagName('tr') as $row){
|
||||
if(!$row) continue;
|
||||
$rid = $row->getAttribute('id');
|
||||
if($rid)
|
||||
$rid = explode('_', $rid)[1];
|
||||
|
||||
$tds = $row->getElementsByTagName('td');
|
||||
if(count($tds) == 3) //rally obedience
|
||||
{
|
||||
$runname = trim($tds[0]->nodeValue);
|
||||
$lk = trim($tds[1]->nodeValue);
|
||||
$pdf = $tds[2]->getElementsByTagName('a')[0]->getAttribute('href');
|
||||
}
|
||||
else if(count($tds) == 4) // agility
|
||||
{
|
||||
$runname = trim($tds[0]->nodeValue);
|
||||
$lk = trim($tds[1]->nodeValue);
|
||||
$gk = trim($tds[2]->nodeValue);
|
||||
$pdf = $tds[3]->getElementsByTagName('a')[0]->getAttribute('href');
|
||||
|
||||
//add run to db if not exists
|
||||
$res = $GLOBALS['db']->query("SELECT * FROM runs WHERE id = '$rid'");
|
||||
if($res->fetchArray() == false)
|
||||
$GLOBALS['db']->exec("INSERT INTO runs (id, name, event, lk, gk) VALUES ('$rid', '$runname', '$eventid', '$lk', '$gk')");
|
||||
|
||||
|
||||
getResults($rid,$eventid);
|
||||
}
|
||||
|
||||
if(!$runname || !$lk || !$pdf) continue;
|
||||
|
||||
|
||||
echo " [R-$rid] $runname - $lk - $gk - $pdf\n";
|
||||
}
|
||||
|
||||
|
||||
//exit("Crawling $eventid");
|
||||
}
|
||||
|
||||
function getResults($run,$event)
|
||||
{
|
||||
$GLOBALS['pdfs']++;
|
||||
//return;
|
||||
if(!$run || !$event) return;
|
||||
$url = "https://www.dognow.at/ergebnisse/pdf.php?lauf=$run&event=$event";
|
||||
if(!file_exists('tmp/results/' . $event . '-' . $run . '.pdf'))
|
||||
file_put_contents('tmp/results/' . $event . '-' . $run . '.pdf',file_get_contents($url));
|
||||
/*if($GLOBALS['db']->query("SELECT * FROM runs WHERE id = '$run' AND event = '$event'")->fetchArray() != false)
|
||||
{
|
||||
echo " [i] Skipping run $run in event $event\n";
|
||||
return;
|
||||
}*/
|
||||
convertPDFtoCSV('tmp/results/' . $event . '-' . $run . '.pdf','tmp/csv/' . $event . '-' . $run . '.pdf.csv');
|
||||
analyzeResultCSV('tmp/csv/' . $event . '-' . $run . '.pdf.csv',$run,$event);
|
||||
}
|
||||
|
||||
function analyzeResultCSV($csvfile,$run,$event)
|
||||
{
|
||||
if(!file_exists($csvfile)) die(" ERR: File $csvfile not found");
|
||||
$csv = array_map('str_getcsv', file($csvfile));
|
||||
|
||||
//prepare header for database
|
||||
foreach($csv[0] as $key=>$value){
|
||||
$csv[0][$key] = preg_replace('/[^A-Za-z0-9]/', '', strtolower($value));
|
||||
}
|
||||
|
||||
array_walk($csv, function(&$a) use ($csv) {
|
||||
$a = array_combine($csv[0], $a);
|
||||
});
|
||||
array_shift($csv); # remove column header
|
||||
|
||||
foreach($csv as $row)
|
||||
{
|
||||
$stnr = $row['stnr'];
|
||||
$teilnehmer = $row['teilnehmer'];
|
||||
$hund = $row['hund'];
|
||||
$rang = $row['rang'];
|
||||
$verein = $row['verein'];
|
||||
$f = $row['f'];
|
||||
$vw = $row['vw'];
|
||||
$zf = $row['zf'];
|
||||
$zeit = $row['zeit'];
|
||||
$gf = $row['gf'];
|
||||
$msek = $row['msek'];
|
||||
$punkte = $row['punkte'];
|
||||
$bew = $row['bew'];
|
||||
|
||||
//add result to db if not exists
|
||||
try
|
||||
{
|
||||
$res = $GLOBALS['db']->query("SELECT * FROM results WHERE stnr = '$stnr' AND run = '$run' AND event = '$event'");
|
||||
if($res->fetchArray() == false)
|
||||
$GLOBALS['db']->exec("INSERT INTO results (stnr, rang, run, event, teilnehmer, hund, verein, f, vw, zf, zeit, gf, msek, bew, punkte) VALUES ('$stnr', '$rang', '$run', '$event', '$teilnehmer', '$hund', '$verein', '$f', '$vw', '$zf', '$zeit', '$gf', '$msek', '$bew', '$punkte')");
|
||||
//else echo " [i] Skipping $teilnehmer in run $run in event $event\n";
|
||||
}
|
||||
catch(Exception $ex) {
|
||||
//die( $ex->getMessage() );
|
||||
exit($GLOBALS['db']->lastErrorMsg());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function convertPDFtoCSV($pdf,$targetname)
|
||||
{
|
||||
if(file_exists($targetname)) return;
|
||||
$csv = analyze($pdf);
|
||||
file_put_contents($targetname, $csv);
|
||||
}
|
||||
|
||||
function analyze($pdf) {
|
||||
echo " [i] Analyzing $pdf\n";
|
||||
$cmd = "java -jar tabula-1.0.5-jar-with-dependencies.jar -f CSV $pdf";
|
||||
$output = shell_exec($cmd);
|
||||
//var_dump($output);
|
||||
return $output;
|
||||
}
|
||||
|
||||
?>
|
||||
BIN
crawler/data.db
Normal file
BIN
crawler/data.db
Normal file
Binary file not shown.
19
crawler/parse.php
Normal file
19
crawler/parse.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
require_once('../web/inc/helpers.php');
|
||||
|
||||
//loop all files in results folder
|
||||
$files = scandir('tmp/results');
|
||||
foreach ($files as $file) {
|
||||
if ($file == '.' || $file == '..' || !endsWith($file, '.pdf') || file_exists('tmp/csv/' . $file . '.csv'))
|
||||
continue;
|
||||
$csv = analyze('tmp/results/' . $file);
|
||||
file_put_contents('tmp/csv/' . $file . '.csv', $csv);
|
||||
}
|
||||
|
||||
|
||||
function analyze($pdf) {
|
||||
$cmd = "java -jar tabula-1.0.5-jar-with-dependencies.jar -f CSV $pdf";
|
||||
$output = shell_exec($cmd);
|
||||
return $output;
|
||||
}
|
||||
BIN
crawler/tabula-1.0.5-jar-with-dependencies.jar
Normal file
BIN
crawler/tabula-1.0.5-jar-with-dependencies.jar
Normal file
Binary file not shown.
4
crawler/tmp/.gitattributes
vendored
Normal file
4
crawler/tmp/.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
results/*.pdf filter=lfs diff=lfs merge=lfs -text
|
||||
csv/*.csv filter=lfs diff=lfs merge=lfs -text
|
||||
pages/*.html filter=lfs diff=lfs merge=lfs -text
|
||||
events/*.html filter=lfs diff=lfs merge=lfs -text
|
||||
2
crawler/tmp/.gitignore
vendored
Normal file
2
crawler/tmp/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.html
|
||||
!.gitignore
|
||||
2
crawler/tmp/csv/.gitignore
vendored
Normal file
2
crawler/tmp/csv/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
2
crawler/tmp/results/.gitignore
vendored
Normal file
2
crawler/tmp/results/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -1,9 +0,0 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["../web/**/*.{html,js,php}"],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
157
web/css/dogstats.css
Normal file
157
web/css/dogstats.css
Normal file
@@ -0,0 +1,157 @@
|
||||
|
||||
:root {
|
||||
--white: #fefefd;
|
||||
--lightblue: #47cafe;
|
||||
--blue: #2ca6fc;
|
||||
--darkblue: #021135;
|
||||
--lightgreen: #cadc57;
|
||||
--darkgreen: #788f08;
|
||||
--lightbrown: #eddbb6;
|
||||
--darkbrown: #ab8f5f;
|
||||
--grey: #c5cbe9;
|
||||
--black: #150d05;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Kalam-Light';
|
||||
src: url(../webfonts/kalam/Kalam-Light.woff2) format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Kalam-Regular';
|
||||
src: url(../webfonts/kalam/Kalam-Regular.woff2) format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Kalam-Bold';
|
||||
src: url(../webfonts/kalam/Kalam-Bold.woff2) format('woff2');
|
||||
}
|
||||
|
||||
|
||||
h1, h2, h3 {
|
||||
font-family: 'Kalam-Bold', sans-serif;
|
||||
}
|
||||
h4, h5, h6 {
|
||||
font-family: 'Kalam-Regular', sans-serif;
|
||||
}
|
||||
.btn-primary {
|
||||
--bs-btn-bg: var(--blue);
|
||||
--bs-btn-border-color: var(--blue);
|
||||
--bs-btn-hover-bg: var(--lightblue);
|
||||
--bs-btn-hover-border-color: var(--lightblue);
|
||||
--bs-btn-active-bg: var(--lightblue);
|
||||
--bs-btn-disabled-color: var(--grey);
|
||||
--bs-btn-disabled-bg: var(--blue);
|
||||
--bs-btn-disabled-border-color: var(--blue);
|
||||
}
|
||||
.btn-secondary {
|
||||
--bs-btn-bg: var(--darkgreen);
|
||||
--bs-btn-border-color: var(--darkgreen);
|
||||
--bs-btn-hover-bg: var(--lightgreen);
|
||||
--bs-btn-hover-border-color: var(--lightgreen);
|
||||
--bs-btn-active-bg: var(--lightgreen);
|
||||
--bs-btn-active-border-color: var(--lightgreen);
|
||||
--bs-btn-disabled-bg: var(--darkgreen);
|
||||
--bs-btn-disabled-border-color: var(--darkgreen);
|
||||
}
|
||||
|
||||
main>.container {
|
||||
padding: 60px 15px 0;
|
||||
}
|
||||
|
||||
table {
|
||||
font-size: smaller;
|
||||
}
|
||||
.tooltipp {
|
||||
position: relative;
|
||||
/* making the .tooltipp span a container for the tooltipp text */
|
||||
border-bottom: 1px dashed #000;
|
||||
/* little indicater to indicate it's hoverable */
|
||||
}
|
||||
|
||||
.tooltipp:before {
|
||||
content: attr(data-text);
|
||||
/* here's the magic */
|
||||
position: absolute;
|
||||
|
||||
/* vertically center */
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
|
||||
/* move to right */
|
||||
left: 100%;
|
||||
margin-left: 15px;
|
||||
/* and add a small left margin */
|
||||
|
||||
/* basic styles */
|
||||
width: 200px;
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
background: #000;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
|
||||
display: none;
|
||||
/* hide by default */
|
||||
|
||||
opacity: 0;
|
||||
transition: .3s opacity;
|
||||
}
|
||||
|
||||
.tooltipp:hover:before {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
.tooltipp:after {
|
||||
opacity: 0;
|
||||
transition: .3s;
|
||||
}
|
||||
|
||||
.tooltipp:hover:after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Dropzone overrides */
|
||||
.dropzone {
|
||||
min-height: 150px;
|
||||
border: 2px solid rgba(0,0,0,.3);
|
||||
padding: 20px 20px;
|
||||
}
|
||||
|
||||
/* XDEBUG */
|
||||
.xdebug-error th
|
||||
{
|
||||
font-family:monospace;
|
||||
font-weight:normal;
|
||||
font-size:15px;
|
||||
padding: 6px 6px 6px 6px;
|
||||
border:1px solid black;
|
||||
background: #FFCC99;
|
||||
color:#000000;
|
||||
}
|
||||
.xdebug-error > tr:first-child > th:first-child,
|
||||
.xdebug-error > tbody > tr:first-child > th:first-child
|
||||
{
|
||||
line-height:1.6em;
|
||||
padding: 10px 10px 10px 10px;
|
||||
border:1px solid #000000;
|
||||
background: #000000;
|
||||
color:#FFFFFF;
|
||||
}
|
||||
.xdebug-error td
|
||||
{
|
||||
font-size:14px;
|
||||
padding: 6px 6px 6px 6px;
|
||||
border:1px solid green;
|
||||
background: #D1FFE8;
|
||||
color:#000000;
|
||||
}
|
||||
#dog-data {
|
||||
padding: 1rem 1rem 1rem 6rem;
|
||||
border: 2px solid var(--blue);
|
||||
}
|
||||
#dog-data .dog-image {
|
||||
position: absolute;
|
||||
left: -50px;
|
||||
top: -35px;
|
||||
border: 1px solid var(--grey);
|
||||
}
|
||||
1
web/css/dropzone.min.css
vendored
Normal file
1
web/css/dropzone.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1778
web/css/output.css
Normal file
1778
web/css/output.css
Normal file
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@ class Model {
|
||||
{
|
||||
//redis
|
||||
if ($GLOBALS['redis'])
|
||||
$this->redis = $GLOBALS['redis'];
|
||||
$GLOBALS['redis'] = $GLOBALS['redis'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,18 +55,31 @@ class Model {
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getField($field,$id=false)
|
||||
{
|
||||
if(!$id)
|
||||
$id = $this->id;
|
||||
return $GLOBALS['redis']->hget($this->dbTable.':'.$id,$field);
|
||||
}
|
||||
|
||||
public function save()
|
||||
{
|
||||
$newgen = false;
|
||||
if (!$this->id)
|
||||
{
|
||||
$this->id = gen_ulid();
|
||||
if (!$this->validate())
|
||||
$newgen = true;
|
||||
}
|
||||
if (!$this->validate($newgen))
|
||||
return false;
|
||||
foreach($this->dbFields as $field=>$options)
|
||||
{
|
||||
if(isset($this->data[$field]))
|
||||
{
|
||||
if($options['type']=='array')
|
||||
if($options['type']=='array' && is_array($this->data[$field]))
|
||||
$GLOBALS['redis']->hset($this->dbTable.':'.$this->id,$field,json_encode($this->data[$field]));
|
||||
else if($options['type']=='array' && !is_array($this->data[$field]))
|
||||
$GLOBALS['redis']->hset($this->dbTable.':'.$this->id,$field,json_encode([]));
|
||||
else
|
||||
{
|
||||
$GLOBALS['redis']->hset($this->dbTable.':'.$this->id,$field,$this->data[$field]);
|
||||
@@ -78,9 +91,33 @@ class Model {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function load($id)
|
||||
/**
|
||||
* @param $value The value to search for
|
||||
* @param string $field The field to search in. HAS to be marked as unique otherwise will throw error
|
||||
*/
|
||||
public function load($value=false,$field='id')
|
||||
{
|
||||
$this->id = $id;
|
||||
if(!$value)
|
||||
$value = $this->id;
|
||||
if($field!='id')
|
||||
{
|
||||
//sanity check. Check if $field is marked as unique
|
||||
if(!in_array('unique',$this->dbFields[$field]))
|
||||
throw new Exception($field.' is not unique');
|
||||
//we need to find the id first
|
||||
$keys = $GLOBALS['redis']->keys($this->dbTable.':*');
|
||||
foreach($keys as $key){
|
||||
$id = end(explode(':',$key));
|
||||
$thisval = $GLOBALS['redis']->hget($this->dbTable.':'.$id,$field);
|
||||
if($thisval==$value)
|
||||
{
|
||||
$this->id = $id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
$this->id = $value;
|
||||
if(!$GLOBALS['redis']->exists($this->dbTable.':'.$this->id))
|
||||
throw new Exception($this->dbTable.':'.$this->id.' not found');
|
||||
$keys = array_keys($this->dbFields);
|
||||
@@ -89,7 +126,9 @@ class Model {
|
||||
{
|
||||
$value = $GLOBALS['redis']->hget($this->dbTable.':'.$this->id,$key);
|
||||
|
||||
if($value!==NULL) //we'll leave null values
|
||||
//var_dump("BEFORE[".$this->dbTable.':'.$this->id."] Loading from DB $key: '$value'");
|
||||
|
||||
if($value!==NULL) //we'll leave null values alone
|
||||
switch($this->dbFields[$key]['type'])
|
||||
{
|
||||
case 'int': $value = intval($value);break;
|
||||
@@ -97,11 +136,13 @@ class Model {
|
||||
case 'float': $value = floatval($value);break;
|
||||
case 'double': $value = doubleval($value);break;
|
||||
case 'array':
|
||||
$value = json_decode($value,true);
|
||||
if($value===null)
|
||||
if(!$value)
|
||||
$value = [];
|
||||
else if(is_string($value))
|
||||
$value = json_decode($value,true);
|
||||
break;
|
||||
}
|
||||
//var_dump("AFTER[".$this->dbTable.':'.$this->id."] Loading from DB $key: '$value'");
|
||||
$this->data[$key] = $value;
|
||||
}
|
||||
|
||||
@@ -111,7 +152,7 @@ class Model {
|
||||
/**
|
||||
* @param array $data
|
||||
*/
|
||||
private function validate()
|
||||
private function validate($newgen=false)
|
||||
{
|
||||
if (!$this->dbFields)
|
||||
return true;
|
||||
@@ -133,8 +174,8 @@ class Model {
|
||||
if (is_array($value))
|
||||
continue;
|
||||
|
||||
if (isset($desc[0]))
|
||||
$type = $desc[0];
|
||||
// if (isset($desc[0]))
|
||||
// $type = $desc[0];
|
||||
if (in_array('required',$options))
|
||||
$required = true;
|
||||
|
||||
@@ -149,8 +190,11 @@ class Model {
|
||||
$this->data[$key] = $value;
|
||||
}
|
||||
|
||||
if($options['default']!==null && $value===null)
|
||||
if($options['default']!==null && $newgen === true && $value===null)
|
||||
{
|
||||
$value = $options['default'];
|
||||
$this->data[$key] = $value;
|
||||
}
|
||||
|
||||
if ($required && strlen($value) == 0) {
|
||||
throw new Exception($this->dbTable . "." . $key . " is required");
|
||||
@@ -199,6 +243,16 @@ class Model {
|
||||
return true;
|
||||
}
|
||||
|
||||
function getTable()
|
||||
{
|
||||
return $this->dbTable;
|
||||
}
|
||||
|
||||
function exists($id)
|
||||
{
|
||||
return $GLOBALS['redis']->exists($this->dbTable.':'.$id);
|
||||
}
|
||||
|
||||
function delete()
|
||||
{
|
||||
return $GLOBALS['redis']->del($this->dbTable.':'.$this->id);
|
||||
|
||||
@@ -18,6 +18,7 @@ class Page
|
||||
public $menu_text;
|
||||
public $menu_image;
|
||||
public $menu_priority;
|
||||
public $menu_classes;
|
||||
public $submenu;
|
||||
|
||||
private $r;
|
||||
@@ -46,7 +47,7 @@ class Page
|
||||
$this->menu_priority = 1;
|
||||
}
|
||||
|
||||
function addSubmenuItem($text, $action, $icon = '', $classes = '')
|
||||
function addSubmenuItem($text, $action='', $icon = '', $classes = '')
|
||||
{
|
||||
$active = $GLOBALS['url'][0];
|
||||
if (!$active) $active = 'index';
|
||||
|
||||
@@ -82,14 +82,19 @@ function callHook($url)
|
||||
if (!$dispatch->maySeeThisPage()) {
|
||||
$componentName = 'err';
|
||||
$action = 'notallowed';
|
||||
$dispatch = new $componentName('error', $action, true);
|
||||
$dispatch = new $componentName('err', $action, true);
|
||||
} else
|
||||
$dispatch = new $componentName($component, $action, true, $queryString);
|
||||
|
||||
if (method_exists($componentName, $action)) {
|
||||
if (method_exists($componentName, $action))
|
||||
$response = call_user_func_array(array($dispatch, $action), $queryString);
|
||||
} else if (method_exists($componentName, 'catchAll'))
|
||||
else if (method_exists($componentName, 'catchAll'))
|
||||
$response = call_user_func_array(array($dispatch, 'catchAll'), array($params));
|
||||
else
|
||||
{
|
||||
$dispatch = new Err('err', 'notfound', false);
|
||||
$response = call_user_func_array(array($dispatch, 'notfound'), array($params));
|
||||
}
|
||||
|
||||
if(is_string($response))
|
||||
return $response;
|
||||
@@ -118,7 +123,7 @@ function getMenu()
|
||||
{
|
||||
while($arr[$menu_priority])
|
||||
$menu_priority++;
|
||||
$arr[$menu_priority] = array('text'=>$menu_text,'image'=>$instance->menu_image, 'url'=>$file,'menu_class'=>$instance->menu_class,'submenu'=>$instance->submenu);
|
||||
$arr[$menu_priority] = array('text'=>$menu_text,'image'=>$instance->menu_image, 'url'=>$file,'menu_classes'=>$instance->menu_classes,'submenu'=>$instance->submenu);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,3 +138,35 @@ function getMenu()
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
function autoLoginCheck()
|
||||
{
|
||||
//check if user has a cookie and if so, logg them in and refresh the page
|
||||
if(isset($_COOKIE['token']) && $_COOKIE['token'] != '' && !$_SESSION['user'])
|
||||
{
|
||||
$u = new User();
|
||||
$allusers = $u->getAll(false);
|
||||
foreach($allusers as $user)
|
||||
{
|
||||
if($user['token'] && $user['token'] == $_COOKIE['token'])
|
||||
{
|
||||
$u->id = $user['id'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if($u->id) //valid cookie, users gets logged in
|
||||
{
|
||||
$u->load($u->id);
|
||||
$u->login();
|
||||
$url = '/'.implode('/',$GLOBALS['url']);
|
||||
header("HX-Redirect: ". $url);
|
||||
exit('<meta http-equiv="Refresh" content="seconds; url='. $url.'"> <script>window.location.href="'. $url.'"</script> ');
|
||||
}
|
||||
else //invalid cookie gets deleted
|
||||
{
|
||||
|
||||
setcookie('token', '', time() - 3600, "/");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,3 +210,146 @@ function uuid4($data = null) {
|
||||
// Output the 36 character UUID.
|
||||
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
|
||||
}
|
||||
|
||||
/*
|
||||
* @param $path string Path to the file that should be uploaded
|
||||
* @param $hash string Optional. File name we want on pictshare for the file
|
||||
*/
|
||||
function pictshareUploadImage($path,$hash=false)
|
||||
{
|
||||
if(!file_exists($path)) return false;
|
||||
$request = curl_init('https://i.haschek.at/api/upload.php');
|
||||
|
||||
curl_setopt($request,CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($request, CURLOPT_POST, true);
|
||||
curl_setopt(
|
||||
$request,
|
||||
CURLOPT_POSTFIELDS,
|
||||
array(
|
||||
'file' => curl_file_create($path),
|
||||
'hash'=>$hash
|
||||
));
|
||||
|
||||
// output the response
|
||||
curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
|
||||
$answer = curl_exec($request);
|
||||
if($answer === false) return ['status'=>'error','error'=>curl_error($request)];
|
||||
else
|
||||
$json = json_decode($answer.PHP_EOL,true);
|
||||
|
||||
// close the session
|
||||
curl_close($request);
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
// takes $_FILES['file'] as input and validates, throws error if fails, else returns URL of the image
|
||||
function pictShareFormValidateAndUpload($file,$key=false)
|
||||
{
|
||||
if($key===false)
|
||||
{
|
||||
$photo_name = $file['name'];
|
||||
$photo_tmp_name = $file['tmp_name'];
|
||||
$photo_size = $file['size'];
|
||||
$photo_error = $file['error'];
|
||||
$photo_type = $file['type'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$photo_name = $file['name'][$key];
|
||||
$photo_tmp_name = $file['tmp_name'][$key];
|
||||
$photo_size = $file['size'][$key];
|
||||
$photo_error = $file['error'][$key];
|
||||
$photo_type = $file['type'][$key];
|
||||
}
|
||||
|
||||
$allowed = ['jpg','jpeg','png','gif'];
|
||||
$photo_ext = strtolower(end(explode('.', $photo_name)));
|
||||
|
||||
if(in_array($photo_ext, $allowed))
|
||||
{
|
||||
if($photo_error === 0)
|
||||
{
|
||||
if($photo_size < 10000000)
|
||||
{
|
||||
$answer = pictshareUploadImage($photo_tmp_name);
|
||||
if($answer['status']=='ok' && in_array($answer['filetype'],['jpeg','png','gif']))
|
||||
return $answer['url'];
|
||||
else
|
||||
throw new Exception('Fehler beim CDN Upload: '.json_encode($answer,true));
|
||||
}
|
||||
else
|
||||
throw new Exception('Die Datei ist zu groß. Bitte eine kleinere Datei hochladen');
|
||||
}
|
||||
else
|
||||
throw new Exception('Fehler beim Upload: '.getFileUploadError($photo_error));
|
||||
}
|
||||
else
|
||||
throw new Exception('Dateityp nicht erlaubt. Bitte nur '.implode(', ',$allowed).' hochladen');
|
||||
|
||||
}
|
||||
|
||||
function getFileUploadError($error)
|
||||
{
|
||||
$phpFileUploadErrors = array(
|
||||
0 => 'There is no error, the file uploaded with success',
|
||||
1 => 'The uploaded file exceeds the upload_max_filesize directive in php.ini',
|
||||
2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
|
||||
3 => 'The uploaded file was only partially uploaded',
|
||||
4 => 'No file was uploaded',
|
||||
6 => 'Missing a temporary folder',
|
||||
7 => 'Failed to write file to disk.',
|
||||
8 => 'A PHP extension stopped the file upload.',
|
||||
);
|
||||
|
||||
return $phpFileUploadErrors[$error];
|
||||
}
|
||||
|
||||
function partial($name,$variables=[])
|
||||
{
|
||||
$templatefile = ROOT.DS.'templates'.DS.'partials'.DS.$name;
|
||||
return template($templatefile,$variables);
|
||||
}
|
||||
|
||||
function template($templatefile,$variables=[])
|
||||
{
|
||||
ob_start();
|
||||
if(is_array($variables))
|
||||
extract($variables);
|
||||
if(file_exists($templatefile))
|
||||
include($templatefile);
|
||||
$pagecontent = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
return $pagecontent;
|
||||
}
|
||||
|
||||
function printRelativeTime($timestamp1, $timestamp2)
|
||||
{
|
||||
$diff = abs($timestamp2 - $timestamp1);
|
||||
|
||||
$intervals = array(
|
||||
'year' => 31536000,
|
||||
'month' => 2592000,
|
||||
'week' => 604800,
|
||||
'day' => 86400,
|
||||
'hour' => 3600,
|
||||
'minute' => 60,
|
||||
'second' => 1
|
||||
);
|
||||
|
||||
$output = '';
|
||||
|
||||
foreach ($intervals as $interval => $seconds) {
|
||||
$count = floor($diff / $seconds);
|
||||
|
||||
if ($count > 0) {
|
||||
$output .= $count . ' ' . ($count === 1 ? $interval : $interval . 's') . ', ';
|
||||
$diff -= $count * $seconds;
|
||||
}
|
||||
}
|
||||
|
||||
$output = rtrim($output, ', ');
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ if($url==[] && $_SERVER['HTTP_HX_CURRENT_URL'])
|
||||
$GLOBALS['url'] = $url;
|
||||
//echo print_r(['url'=>$url,'server'=>$_SERVER,'request'=>$_REQUEST,'cookie'=>$_COOKIE,'session'=>$_SESSION],true);
|
||||
|
||||
autoLoginCheck();
|
||||
|
||||
$response = callHook($url);
|
||||
|
||||
if(is_string($response))
|
||||
|
||||
80
web/js/color-modes.js
Normal file
80
web/js/color-modes.js
Normal file
@@ -0,0 +1,80 @@
|
||||
/*!
|
||||
* Color mode toggler for Bootstrap's docs (https://getbootstrap.com/)
|
||||
* Copyright 2011-2023 The Bootstrap Authors
|
||||
* Licensed under the Creative Commons Attribution 3.0 Unported License.
|
||||
*/
|
||||
|
||||
(() => {
|
||||
'use strict'
|
||||
|
||||
const getStoredTheme = () => localStorage.getItem('theme')
|
||||
const setStoredTheme = theme => localStorage.setItem('theme', theme)
|
||||
|
||||
const getPreferredTheme = () => {
|
||||
const storedTheme = getStoredTheme()
|
||||
if (storedTheme) {
|
||||
return storedTheme
|
||||
}
|
||||
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
||||
}
|
||||
|
||||
const setTheme = theme => {
|
||||
if (theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
document.documentElement.setAttribute('data-bs-theme', 'dark')
|
||||
} else {
|
||||
document.documentElement.setAttribute('data-bs-theme', theme)
|
||||
}
|
||||
}
|
||||
|
||||
setTheme(getPreferredTheme())
|
||||
|
||||
const showActiveTheme = (theme, focus = false) => {
|
||||
const themeSwitcher = document.querySelector('#bd-theme')
|
||||
|
||||
if (!themeSwitcher) {
|
||||
return
|
||||
}
|
||||
|
||||
const themeSwitcherText = document.querySelector('#bd-theme-text')
|
||||
const activeThemeIcon = document.querySelector('.theme-icon-active use')
|
||||
const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
|
||||
const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href')
|
||||
|
||||
document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
|
||||
element.classList.remove('active')
|
||||
element.setAttribute('aria-pressed', 'false')
|
||||
})
|
||||
|
||||
btnToActive.classList.add('active')
|
||||
btnToActive.setAttribute('aria-pressed', 'true')
|
||||
activeThemeIcon.setAttribute('href', svgOfActiveBtn)
|
||||
const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`
|
||||
themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)
|
||||
|
||||
if (focus) {
|
||||
themeSwitcher.focus()
|
||||
}
|
||||
}
|
||||
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
||||
const storedTheme = getStoredTheme()
|
||||
if (storedTheme !== 'light' && storedTheme !== 'dark') {
|
||||
setTheme(getPreferredTheme())
|
||||
}
|
||||
})
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
showActiveTheme(getPreferredTheme())
|
||||
|
||||
document.querySelectorAll('[data-bs-theme-value]')
|
||||
.forEach(toggle => {
|
||||
toggle.addEventListener('click', () => {
|
||||
const theme = toggle.getAttribute('data-bs-theme-value')
|
||||
setStoredTheme(theme)
|
||||
setTheme(theme)
|
||||
showActiveTheme(theme, true)
|
||||
})
|
||||
})
|
||||
})
|
||||
})()
|
||||
1
web/js/dropzone.min.js
vendored
Normal file
1
web/js/dropzone.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
45
web/js/echarts.min.js
vendored
Normal file
45
web/js/echarts.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -1,17 +1,66 @@
|
||||
<?php
|
||||
|
||||
class Dog extends Model {
|
||||
class Dog extends Model
|
||||
{
|
||||
protected $dbTable = "dogs";
|
||||
protected $dbFields = Array (
|
||||
'uuid' => ['type'=>'text','required','unique','autoValMethod'=>'gen_ulid'],
|
||||
'registered' => ['type'=>'datetime','required','unique','autoValMethod'=>'getDateTime'],
|
||||
'name' => ['type'=>'text'],
|
||||
'kennel_name' => ['type'=>'text'],
|
||||
'breed' => ['type'=>'text'],
|
||||
'size' => ['type'=>'text'], //in cm
|
||||
'birthday' => ['type'=>'text'],
|
||||
'agility_size' => ['type'=>'text'], //S,M,I,L
|
||||
'active' => ['type'=>'int','default'=>1]
|
||||
protected $dbFields = array(
|
||||
'registered' => ['type' => 'datetime', 'required', 'unique', 'autoValMethod' => 'getDateTime'],
|
||||
'name' => ['type' => 'text'],
|
||||
'kennel_name' => ['type' => 'text'],
|
||||
'breed' => ['type' => 'text'],
|
||||
'size' => ['type' => 'text'], //in cm
|
||||
'birthday' => ['type' => 'text'],
|
||||
'agility_size' => ['type' => 'text'], //S,M,I,L
|
||||
'photo' => ['type' => 'text', 'default' => 'https://pictshare.net/1ch3e5.png'],
|
||||
'active' => ['type' => 'bool', 'default' => 1]
|
||||
);
|
||||
|
||||
function getResults($dogid=false)
|
||||
{
|
||||
if(!$dogid)
|
||||
$dogid = $this->id;
|
||||
$res = new Result();
|
||||
$keys = $GLOBALS['redis']->keys($res->getTable() . ':*');
|
||||
$results = [];
|
||||
foreach ($keys as $key) {
|
||||
$id = end(explode(':', $key));
|
||||
$res = new Result();
|
||||
$res->load($id);
|
||||
if ($res->data['dog'] == $dogid) {
|
||||
$results[] = $res->data;
|
||||
}
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
function getRuns()
|
||||
{
|
||||
$run = new Run();
|
||||
$keys = $GLOBALS['redis']->keys($run->dbTable . ':*');
|
||||
$runs = [];
|
||||
foreach ($keys as $key) {
|
||||
$id = end(explode(':', $key));
|
||||
$run = new Run();
|
||||
$run->load($id);
|
||||
if ($run->data['dog'] == $this->id)
|
||||
$runs[] = $run->data;
|
||||
}
|
||||
return $runs;
|
||||
}
|
||||
|
||||
function isMyDog($dog = false)
|
||||
{
|
||||
if ($dog == false)
|
||||
$dog = $this->id;
|
||||
|
||||
if (!$this->exists($dog))
|
||||
return false;
|
||||
else if(!is_array($_SESSION['user']->data['dogs']))
|
||||
return false;
|
||||
else {
|
||||
if (in_array($dog, $_SESSION['user']->data['dogs']))
|
||||
return true;
|
||||
else return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
web/models/Result.model.php
Normal file
53
web/models/Result.model.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
class Result extends Model
|
||||
{
|
||||
protected $dbTable = "result";
|
||||
protected $dbFields = array(
|
||||
'tournament' => ['type' => 'text', 'required'], //tournament ID
|
||||
'run' => ['type' => 'text', 'required'], //run ID
|
||||
'user' => ['type' => 'text', 'required'], //user ID
|
||||
'dog' => ['type' => 'text', 'required'], //dog ID
|
||||
|
||||
'disqualified' => ['type' => 'bool','default'=>0],
|
||||
'refusals' => ['type' => 'int','default'=>0],
|
||||
'errors' => ['type' => 'int','default'=>0],
|
||||
'timefaults' => ['type' => 'float','default'=>0],
|
||||
'runtime' => ['type' => 'float','default'=>0],
|
||||
'penalties' => ['type' => 'float','default'=>0],
|
||||
'rating' => ['type' => 'text'],
|
||||
'points' => ['type' => 'int','default'=>0],
|
||||
'speed' => ['type' => 'float','default'=>0], //in m/sec
|
||||
'ranking' => ['type' => 'int','default'=>0],
|
||||
'photos' => ['type' => 'array','default'=>[]],
|
||||
'videos' => ['type' => 'array','default'=>[]],
|
||||
'memo' => ['type' => 'text'],
|
||||
'public' => ['type' => 'bool','default'=>1],
|
||||
);
|
||||
|
||||
function getDataOfRun($rid)
|
||||
{
|
||||
$run = new Run();
|
||||
if($run->exists($rid))
|
||||
$run->load($rid);
|
||||
else return false;
|
||||
|
||||
$results = $run->data['results'];
|
||||
if(is_array($results) && count($results)>0)
|
||||
{
|
||||
$res = [];
|
||||
foreach($results as $r)
|
||||
{
|
||||
$result = new Result();
|
||||
if($result->exists($r))
|
||||
{
|
||||
$result->load($r);
|
||||
$res[] = $result->data;
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
else return [];
|
||||
}
|
||||
|
||||
}
|
||||
18
web/models/Run.model.php
Normal file
18
web/models/Run.model.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
class Run extends Model
|
||||
{
|
||||
protected $dbTable = "run";
|
||||
protected $dbFields = array(
|
||||
'tournament' => ['type' => 'text', 'required'],
|
||||
'name' => ['type' => 'text', 'required'],
|
||||
'category' => ['type' => 'text'],
|
||||
'length' => ['type' => 'int'], //in meters
|
||||
'time_standard' => ['type' => 'int'], // in sek
|
||||
'time_max' => ['type' => 'int'], // in sek
|
||||
'referee' => ['type' => 'text'],
|
||||
'photo' => ['type' => 'text'],
|
||||
'results' => ['type' => 'array','default'=>[]],
|
||||
);
|
||||
|
||||
}
|
||||
122
web/models/Tournament.model.php
Normal file
122
web/models/Tournament.model.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
class Tournament extends Model
|
||||
{
|
||||
protected $dbTable = "tournaments";
|
||||
protected $dbFields = array(
|
||||
'registered' => ['type' => 'datetime', 'required', 'unique', 'autoValMethod' => 'getDateTime'],
|
||||
'name' => ['type' => 'text', 'required'],
|
||||
'date' => ['type' => 'datetime','required'],
|
||||
'duration' => ['type' => 'int'], //in days
|
||||
'text' => ['type' => 'text'],
|
||||
'url' => ['type' => 'text'], //if there is one
|
||||
'logo' => ['type' => 'text', 'default' => 'https://pictshare.net/prrnrk.jpg'],
|
||||
'admins' => ['type'=> 'array', 'default'=>[]],
|
||||
'members' => ['type'=> 'array', 'default'=>[]],
|
||||
'runs' => ['type'=> 'array', 'default'=>[]],
|
||||
);
|
||||
|
||||
function joinUser($tournament = false)
|
||||
{
|
||||
if ($tournament == false)
|
||||
$tournament = $this->id;
|
||||
|
||||
if (!$this->exists($tournament))
|
||||
return false;
|
||||
else {
|
||||
if (!in_array($_SESSION['user']->id, $this->data['members']))
|
||||
$this->data['members'][] = $_SESSION['user']->id;
|
||||
if(!in_array($tournament,$_SESSION['user']->data['tournaments']))
|
||||
{
|
||||
$_SESSION['user']->data['tournaments'][] = $tournament;
|
||||
$_SESSION['user']->save();
|
||||
}
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
function removeUser($tournament = false)
|
||||
{
|
||||
if ($tournament == false)
|
||||
$tournament = $this->id;
|
||||
|
||||
if (!$this->exists($tournament))
|
||||
return false;
|
||||
else {
|
||||
if (in_array($_SESSION['user']->id, $this->data['members']))
|
||||
$this->data['members'] = array_diff($this->data['members'],[$_SESSION['user']->id]);
|
||||
if(in_array($tournament,$_SESSION['user']->data['tournaments']))
|
||||
{
|
||||
$_SESSION['user']->data['tournaments'] = array_diff($_SESSION['user']->data['tournaments'],[$tournament]);
|
||||
$_SESSION['user']->save();
|
||||
}
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
function isMyEvent($tournament = false)
|
||||
{
|
||||
if ($tournament == false)
|
||||
$tournament = $this->id;
|
||||
|
||||
if (!$this->exists($tournament))
|
||||
return false;
|
||||
else {
|
||||
if (in_array($tournament, $_SESSION['user']->data['tournaments']))
|
||||
return true;
|
||||
else return false;
|
||||
}
|
||||
}
|
||||
|
||||
function amIAdmin($tournament = false)
|
||||
{
|
||||
if ($tournament == false)
|
||||
$tournament = $this->id;
|
||||
|
||||
if (!$this->exists($tournament))
|
||||
return false;
|
||||
else {
|
||||
if (in_array($_SESSION['user']->id, $this->data['admins']))
|
||||
return true;
|
||||
else return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getAdmins($tournament = false)
|
||||
{
|
||||
if ($tournament == false)
|
||||
$tournament = $this->id;
|
||||
|
||||
if (!$this->exists($tournament))
|
||||
return false;
|
||||
else {
|
||||
$admins = [];
|
||||
foreach($this->data['admins'] as $admin)
|
||||
{
|
||||
$u = new User();
|
||||
$u->load($admin);
|
||||
$admins[] = $u->getDataFiltered();
|
||||
}
|
||||
return $admins;
|
||||
}
|
||||
}
|
||||
|
||||
function getMembers($tournament = false)
|
||||
{
|
||||
if ($tournament == false)
|
||||
$tournament = $this->id;
|
||||
|
||||
if (!$this->exists($tournament))
|
||||
return false;
|
||||
else {
|
||||
$members = [];
|
||||
foreach($this->data['members'] as $member)
|
||||
{
|
||||
$u = new User();
|
||||
$u->load($member);
|
||||
$members[] = $u->getDataFiltered();
|
||||
}
|
||||
return $members;
|
||||
}
|
||||
}
|
||||
}
|
||||
122
web/models/Training.model.php
Normal file
122
web/models/Training.model.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
class Training extends Model
|
||||
{
|
||||
protected $dbTable = "trainings";
|
||||
protected $dbFields = array(
|
||||
'registered' => ['type' => 'datetime', 'required', 'unique', 'autoValMethod' => 'getDateTime'],
|
||||
'name' => ['type' => 'text', 'required'],
|
||||
'date' => ['type' => 'datetime','required'],
|
||||
'duration' => ['type' => 'int'], //in days
|
||||
'text' => ['type' => 'text'],
|
||||
'url' => ['type' => 'text'], //if there is one
|
||||
'logo' => ['type' => 'text', 'default' => 'https://pictshare.net/prrnrk.jpg'],
|
||||
'admins' => ['type'=> 'array', 'default'=>[]],
|
||||
'members' => ['type'=> 'array', 'default'=>[]],
|
||||
'runs' => ['type'=> 'array', 'default'=>[]],
|
||||
);
|
||||
|
||||
function joinUser($training = false)
|
||||
{
|
||||
if ($training == false)
|
||||
$training = $this->id;
|
||||
|
||||
if (!$this->exists($training))
|
||||
return false;
|
||||
else {
|
||||
if (!in_array($_SESSION['user']->id, $this->data['members']))
|
||||
$this->data['members'][] = $_SESSION['user']->id;
|
||||
if(!in_array($training,$_SESSION['user']->data['trainings']))
|
||||
{
|
||||
$_SESSION['user']->data['trainings'][] = $training;
|
||||
$_SESSION['user']->save();
|
||||
}
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
function removeUser($training = false)
|
||||
{
|
||||
if ($training == false)
|
||||
$training = $this->id;
|
||||
|
||||
if (!$this->exists($training))
|
||||
return false;
|
||||
else {
|
||||
if (in_array($_SESSION['user']->id, $this->data['members']))
|
||||
$this->data['members'] = array_diff($this->data['members'],[$_SESSION['user']->id]);
|
||||
if(in_array($training,$_SESSION['user']->data['trainings']))
|
||||
{
|
||||
$_SESSION['user']->data['trainings'] = array_diff($_SESSION['user']->data['trainings'],[$training]);
|
||||
$_SESSION['user']->save();
|
||||
}
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
function isMyEvent($training = false)
|
||||
{
|
||||
if ($training == false)
|
||||
$training = $this->id;
|
||||
|
||||
if (!$this->exists($training))
|
||||
return false;
|
||||
else {
|
||||
if (in_array($training, $_SESSION['user']->data['trainings']))
|
||||
return true;
|
||||
else return false;
|
||||
}
|
||||
}
|
||||
|
||||
function amIAdmin($training = false)
|
||||
{
|
||||
if ($training == false)
|
||||
$training = $this->id;
|
||||
|
||||
if (!$this->exists($training))
|
||||
return false;
|
||||
else {
|
||||
if (in_array($_SESSION['user']->id, $this->data['admins']))
|
||||
return true;
|
||||
else return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getAdmins($training = false)
|
||||
{
|
||||
if ($training == false)
|
||||
$training = $this->id;
|
||||
|
||||
if (!$this->exists($training))
|
||||
return false;
|
||||
else {
|
||||
$admins = [];
|
||||
foreach($this->data['admins'] as $admin)
|
||||
{
|
||||
$u = new User();
|
||||
$u->load($admin);
|
||||
$admins[] = $u->getDataFiltered();
|
||||
}
|
||||
return $admins;
|
||||
}
|
||||
}
|
||||
|
||||
function getMembers($training = false)
|
||||
{
|
||||
if ($training == false)
|
||||
$training = $this->id;
|
||||
|
||||
if (!$this->exists($training))
|
||||
return false;
|
||||
else {
|
||||
$members = [];
|
||||
foreach($this->data['members'] as $member)
|
||||
{
|
||||
$u = new User();
|
||||
$u->load($member);
|
||||
$members[] = $u->getDataFiltered();
|
||||
}
|
||||
return $members;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,26 +5,33 @@ class User extends Model {
|
||||
protected $dbFields = Array (
|
||||
'uuid' => ['type'=>'text','required','unique','autoValMethod'=>'gen_ulid'],
|
||||
'password' => ['type'=>'text'],
|
||||
'registered' => ['type'=>'datetime','required','unique','autoValMethod'=>'getDateTime'],
|
||||
'registered' => ['type'=>'datetime','required','autoValMethod'=>'getDateTime'],
|
||||
'email' => ['type'=>'email','unique'],
|
||||
'firstname' => ['type'=>'text'],
|
||||
'lastname' => ['type'=>'text'],
|
||||
'birthday' => ['type' => 'text'],
|
||||
'club' => ['type'=>'text'],
|
||||
'last_login' => ['type'=>'datetime','required','unique','autoValMethod'=>'getDateTime'],
|
||||
'token' => ['type'=>'text','required','unique','autoValMethod'=>'uuid4'],
|
||||
'timezone' => ['type'=>'int'],
|
||||
'dogs' => ['type'=> 'array','default'=>[]],
|
||||
'active' => ['type'=>'int','default'=>0]
|
||||
'tournaments' =>['type'=> 'array','default'=>[]],
|
||||
'photo' => ['type'=>'text','default'=>'https://pictshare.net/pj7vzx.jpg'],
|
||||
'theme' => ['type'=>'text','default'=>'light'], //light/dark
|
||||
'active' => ['type'=>'int','default'=>0]
|
||||
);
|
||||
protected $hidden = ['password','token'];
|
||||
|
||||
function login()
|
||||
{
|
||||
if(!$this->id) return false;
|
||||
$this->load();
|
||||
$this->last_login = $this->getDateTime();
|
||||
$this->save();
|
||||
|
||||
$_SESSION['user'] = $this;
|
||||
$_SESSION['userid'] = $this->id;
|
||||
|
||||
$_SESSION['user']->save();
|
||||
}
|
||||
|
||||
function logout()
|
||||
@@ -33,14 +40,19 @@ class User extends Model {
|
||||
unset($_SESSION['user']);
|
||||
}
|
||||
|
||||
function exists($id)
|
||||
function removeDog($dogid)
|
||||
{
|
||||
return $this->redis->exists($this->dbTable.':'.$id);
|
||||
if(!$this->id) return false;
|
||||
if (in_array($dogid, $this->data['dogs']))
|
||||
{
|
||||
$this->data['dogs'] = array_diff($this->data['dogs'],[$dogid]);
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
function getAll($filtered = true)
|
||||
{
|
||||
$keys = $this->redis->keys($this->dbTable.':*');
|
||||
$keys = $GLOBALS['redis']->keys($this->dbTable.':*');
|
||||
$users = [];
|
||||
foreach($keys as $key)
|
||||
{
|
||||
@@ -48,9 +60,13 @@ class User extends Model {
|
||||
$u = new User();
|
||||
$u->load($id);
|
||||
if($filtered===true)
|
||||
$users[] = $u->getDataFiltered();
|
||||
$thisdata = $u->getDataFiltered();
|
||||
else
|
||||
$users[] = $u->data;
|
||||
$thisdata = $u->data;
|
||||
|
||||
$thisdata['id'] = $id;
|
||||
|
||||
$users[] = $thisdata;
|
||||
}
|
||||
return $users;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
</div>
|
||||
<!-- Modal footer -->
|
||||
<div class="flex items-center p-6 space-x-2 border-t border-gray-200 rounded-b dark:border-gray-600">
|
||||
<button type="submit" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">Save</button>
|
||||
<button type="submit" class="btn btn-primary">Save</button>
|
||||
<div id="response"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
78
web/pages/demo/controller.php
Normal file
78
web/pages/demo/controller.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
|
||||
class Demo extends Page{
|
||||
function setMenu()
|
||||
{
|
||||
$this->menu_text = 'Demo';
|
||||
$this->menu_image = 'fas fa-do';
|
||||
$this->menu_priority = 5;
|
||||
}
|
||||
|
||||
function setSubmenu()
|
||||
{
|
||||
//$this->addSubmenuItem('Hunde anzeigen','/dogs','far fa-list-alt');
|
||||
//$this->addSubmenuItem('Hund hinzufügen','/dogs/add','fas fa-plus-circle');
|
||||
}
|
||||
|
||||
function test()
|
||||
{
|
||||
$graph1 = partial('graph.html.php', [
|
||||
'id' => 'graph1',
|
||||
'title' => 'Graph 1',
|
||||
'legend' => ['Geschwindigkeit', 'Fehler', 'Verweigerungen', 'Zeit', 'Geschwindigkeit', 'Punkte', 'Platz'],
|
||||
'xaxis' => ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
|
||||
'seriesdata' => [
|
||||
['name' => 'Geschwindigkeit', 'type'=>'line','stack'=>'Total', 'data' => [120, 132, 101, 134, 90, 230, 210]],
|
||||
['name' => 'Fehler', 'type'=>'line','stack'=>'Total', 'data' => [220, 182, 191, 234, 290, 330, 310]],
|
||||
['name' => 'Verweigerungen', 'type'=>'line','stack'=>'Total', 'data' => [150, 232, 201, 154, 190, 330, 410]],
|
||||
['name' => 'Zeit', 'type'=>'line','stack'=>'Total', 'data' => [320, 332, 301, 334, 390, 330, 320]],
|
||||
['name' => 'Punkte', 'type'=>'line','stack'=>'Total', 'data' => [820, 932, 901, 934, 1290, 1330, 1320]],
|
||||
['name' => 'Platz', 'type'=>'line','stack'=>'Total', 'data' => [820, 932, 901, 934, 1290, 1330, 1320]]
|
||||
],
|
||||
]);
|
||||
|
||||
$graph2 = partial('graph.html.php', [
|
||||
'id' => 'graph2',
|
||||
'title' => 'Punkte',
|
||||
'xaxis' => ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
|
||||
'seriesdata' => [
|
||||
['name' => 'Punkte', 'type'=>'line','stack'=>'Total', 'data' => [820, 932, 901, 934, 1290, 1330, 1320]],
|
||||
],
|
||||
]);
|
||||
|
||||
$graph3 = partial('graph.html.php', [
|
||||
'id' => 'graph3',
|
||||
'title' => 'Graph 3',
|
||||
'legend' => ['Punkte'],
|
||||
'xaxis' => ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
|
||||
'seriesdata' => [
|
||||
['name' => 'Punkte', 'type'=>'line','stack'=>'Total', 'data' => [820, 932, 901, 934, 1290, 1330, 1320]],
|
||||
],
|
||||
]);
|
||||
|
||||
return '<div class="container text-center">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
'.$graph1.'
|
||||
</div>
|
||||
<div class="col">
|
||||
'.$graph2.'
|
||||
</div>
|
||||
<div class="col">
|
||||
'.$graph3.'
|
||||
</div>
|
||||
</div>
|
||||
</div>';
|
||||
}
|
||||
|
||||
function index()
|
||||
{
|
||||
$this->set('successTitle','Erfolgreich');
|
||||
$this->set('successMessage','Text davon');
|
||||
|
||||
$this->set('errorMessage','Fehler ohne Titel');
|
||||
|
||||
$this->set('template','demo.html');
|
||||
}
|
||||
}
|
||||
9
web/pages/demo/demo.html
Normal file
9
web/pages/demo/demo.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<?= partial('success.html',['successTitle'=>'Dies ist ein Titel','successMessage'=>'Erfolgreich']); ?>
|
||||
|
||||
<?= partial('error.html',['errorMessage'=>'Fehlernacricht ohne titel']); ?>
|
||||
|
||||
<?= partial('info.html',['infoTitle'=>'Dies ist ein Info titel','infoMessage'=>'InfoNachricht ist so']); ?>
|
||||
|
||||
<?= partial('notice.html',['noticeTitle'=>'Dies ist ein notice titel','noticeMessage'=>'noticeNachricht ist so']); ?>
|
||||
|
||||
<?= partial('../../pages/tournaments/edit.html',[]); ?>
|
||||
@@ -6,13 +6,23 @@ class Dogs extends Page {
|
||||
{
|
||||
$this->menu_text = 'Meine Hunde';
|
||||
$this->menu_image = 'far fa-dog';
|
||||
$this->menu_priority = 0;
|
||||
$this->menu_priority = 1;
|
||||
}
|
||||
|
||||
function setSubmenu()
|
||||
{
|
||||
$this->addSubmenuItem('Hunde anzeigen','/dogs','far fa-list-alt');
|
||||
$this->addSubmenuItem('Hund hinzufügen','/dogs/add','fas fa-plus-circle');
|
||||
if($_SESSION['user']->data['dogs'] && count($_SESSION['user']->data['dogs']) > 0)
|
||||
{
|
||||
$this->addSubmenuItem('divider');
|
||||
foreach($_SESSION['user']->data['dogs'] as $dogid)
|
||||
{
|
||||
$dog = new Dog();
|
||||
$dog->load($dogid);
|
||||
$this->addSubmenuItem($dog->data['name'],'/dogs/overview/'.$dogid,'fas fa-dog');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function index() {
|
||||
@@ -56,6 +66,20 @@ class Dogs extends Page {
|
||||
$this->set('template', 'edit.html');
|
||||
}
|
||||
|
||||
function delete(){
|
||||
$dogid = $this->params[0];
|
||||
$d = new Dog();
|
||||
|
||||
if(!$d->isMyDog($dogid))
|
||||
return 'Not your dog :(';
|
||||
|
||||
$d->load($dogid);
|
||||
$d->delete();
|
||||
|
||||
$_SESSION['user']->removeDog($dogid);
|
||||
$this->redirect('/dogs');
|
||||
}
|
||||
|
||||
function edit() {
|
||||
if($_REQUEST['submit'])
|
||||
{
|
||||
@@ -63,9 +87,45 @@ class Dogs extends Page {
|
||||
$name = $_REQUEST['name'];
|
||||
$kennel_name = $_REQUEST['kennel_name'];
|
||||
$dog_breed = $_REQUEST['dog_breed'];
|
||||
$dog_size = $_REQUEST['dog_size'];
|
||||
$dog_size = intval($_REQUEST['dog_size']);
|
||||
$dog_birthday = $_REQUEST['dog_birthday'];
|
||||
$agi_height_category = $_REQUEST['agi_height_category'];
|
||||
$active = intval($_REQUEST['agi_active']);
|
||||
|
||||
$newphoto = false;
|
||||
if($_FILES['photo'])
|
||||
{
|
||||
$photo = $_FILES['photo'];
|
||||
$photo_name = $photo['name'];
|
||||
$photo_tmp_name = $photo['tmp_name'];
|
||||
$photo_size = $photo['size'];
|
||||
$photo_error = $photo['error'];
|
||||
$photo_type = $photo['type'];
|
||||
|
||||
$allowed = ['jpg','jpeg','png','gif'];
|
||||
$photo_ext = strtolower(end(explode('.', $photo_name)));
|
||||
|
||||
if(in_array($photo_ext, $allowed))
|
||||
{
|
||||
if($photo_error === 0)
|
||||
{
|
||||
if($photo_size < 10000000)
|
||||
{
|
||||
$answer = pictshareUploadImage($photo_tmp_name);
|
||||
if($answer['status']=='ok' && in_array($answer['filetype'],['jpeg','png','gif']))
|
||||
$newphoto = $answer['url'];
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Fehler beim CDN Upload: '.json_encode($answer,true)]);
|
||||
}
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Die Datei ist zu groß. Bitte eine kleinere Datei hochladen']);
|
||||
}
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Beim Upload der Datei ist ein Fehler aufgetreten']);
|
||||
}
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Dieser Dateityp ist nicht erlaubt. Bitte nur jpg, jpeg oder png Dateien hochladen']);
|
||||
}
|
||||
|
||||
$error = false;
|
||||
if(!$name || !$dog_birthday )
|
||||
@@ -90,6 +150,9 @@ class Dogs extends Page {
|
||||
$dog->size = $dog_size;
|
||||
$dog->birthday = $dog_birthday;
|
||||
$dog->agility_size = $agi_height_category;
|
||||
$dog->active = $active;
|
||||
if($newphoto)
|
||||
$dog->photo = $newphoto;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -142,6 +205,22 @@ class Dogs extends Page {
|
||||
}
|
||||
}
|
||||
|
||||
function overview()
|
||||
{
|
||||
$dogid = $this->params[0];
|
||||
$d = new Dog();
|
||||
|
||||
//if(!$d->isMyDog($dogid))
|
||||
// return 'Not your dog :(';
|
||||
|
||||
$d->load($dogid);
|
||||
$this->set('ismydog',$d->isMyDog($dogid));
|
||||
$this->set('results', $d->getResults());
|
||||
$this->set('dogdata', $d->data);
|
||||
$this->set('dogid', $dogid);
|
||||
$this->set('template', 'dog.html.php');
|
||||
}
|
||||
|
||||
function maySeeThisPage() {
|
||||
if($_SESSION['user']) //wenn eingeloggt, kein problem
|
||||
return true;
|
||||
|
||||
245
web/pages/dogs/dog.html.php
Normal file
245
web/pages/dogs/dog.html.php
Normal file
@@ -0,0 +1,245 @@
|
||||
<!-- FILEPATH: /home/chris/git/dogstats/web/pages/dogs/dog.html -->
|
||||
|
||||
<div class="container">
|
||||
<div class="">
|
||||
<div class="row">
|
||||
|
||||
<div id="dog-data" class="col-sm-6 offset-sm-3 position-relative rounded-2 shadow mb-3 mb-md-5">
|
||||
<img src="<?= $dogdata['photo']?:'https://pictshare.net/1ch3e5.png' ?>/120x160/forcesize" width="120" height="160" class="rounded-5 rounded-top-0 dog-image shadow" alt="<?= escape($dogdata['name']); ?>'s profile Picture">
|
||||
|
||||
<h1 class="mb-3">
|
||||
<?= escape($dogdata['name']); ?>
|
||||
</h1>
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Alter:</td>
|
||||
<td><?= date_diff(date_create($dogdata['birthday']), date_create('now'))->y ?></td>
|
||||
</tr>
|
||||
|
||||
<?php if($dogdata['breed']): ?>
|
||||
<tr>
|
||||
<td>Rasse:</td>
|
||||
<td><?= escape($dogdata['breed']); ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if($dogdata['kennel_name']): ?>
|
||||
<tr>
|
||||
<td>Zuchtname:</td>
|
||||
<td><?= escape($dogdata['kennel_name']); ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if($dogdata['size']): ?>
|
||||
<tr>
|
||||
<td>Größe:</td>
|
||||
<td><?= escape($dogdata['size']); ?> cm</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if($dogdata['agility_size']): ?>
|
||||
<tr>
|
||||
<td>Agility Größe:</td>
|
||||
<td><?= escape($dogdata['agility_size']); ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php if($ismydog===true): ?>
|
||||
<div class="d-flex justify-content-end">
|
||||
<button type="button" class="btn btn-secondary" hx-get="/dogs/edit/<?= $dogid; ?>" hx-target="#main">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container pb-4" id="sitemain">
|
||||
<!-- table of all runs of this dog-->
|
||||
<h2>Alle Ergebnisse</h2>
|
||||
|
||||
<div class="accordion" id="accordion-dog-runs">
|
||||
<div class="accordion-item">
|
||||
<h3 class="accordion-header">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
||||
2023
|
||||
</button>
|
||||
</h3>
|
||||
<div id="collapseOne" class="accordion-collapse collapse" data-bs-parent="#accordion-dog-runs">
|
||||
<div class="accordion-body">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Turnier</th>
|
||||
<th>Lauf</th>
|
||||
<th class="text-end">VW</th>
|
||||
<th class="text-end">F</th>
|
||||
<th class="text-end">ZF</th>
|
||||
<th class="text-end">Zeit</th>
|
||||
<th class="text-end">GF</th>
|
||||
<th class="text-end">m/Sek</th>
|
||||
<th class="text-end">Bew.</th>
|
||||
<th class="text-end">Platz</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if(count($results) > 0): ?>
|
||||
<?php foreach($results as $result) : ?>
|
||||
<?php
|
||||
$t = new Tournament();
|
||||
$run = new Run();
|
||||
|
||||
$tname = $t->getField('name',$result['tournament']);
|
||||
$tdate = $t->getField('date',$result['tournament']);
|
||||
$rname = $run->getField('name',$result['run']);
|
||||
|
||||
$sdata['dates'][] = $tdate;
|
||||
|
||||
$sdata['speed'][] = $result['speed'];
|
||||
$sdata['errors'][] = $result['errors'];
|
||||
$sdata['refusals'][] = $result['refusals'];
|
||||
$sdata['time'][] = $result['runtime'];
|
||||
$sdata['points'][] = $result['points'];
|
||||
$sdata['ranking'][] = $result['ranking'];
|
||||
|
||||
//'Geschwindigkeit', 'Fehler', 'Verweigerungen', 'Zeit', 'Punkte','Platz'
|
||||
|
||||
?>
|
||||
<tr>
|
||||
<td><a href="/tournaments/event/<?= $result['tournament']; ?>">
|
||||
<?= $tname; ?>
|
||||
</a></td>
|
||||
<td><a href="/runs/overview/<?= $result['run']; ?>">
|
||||
<?= $rname; ?>
|
||||
</a></td>
|
||||
<td class="text-end">
|
||||
<?= $result['disqualified']?'':escape($result['refusals']); ?>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<?= $result['disqualified']?'':escape($result['errors']); ?>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<?= $result['disqualified']?'':escape($result['timefaults']); ?>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<?= $result['disqualified']?'':escape($result['runtime']); ?>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<?= $result['disqualified']?'':escape($result['penalties']); ?>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<?= $result['disqualified']?'':escape($result['speed']); ?>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<?= $result['disqualified']?'':escape($result['rating']); ?>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<?= $result['disqualified']?'Dis':escape($result['ranking'] . '. Platz'); ?>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<tr>
|
||||
<td colspan="12">
|
||||
<div class="alert alert-info" role="alert">
|
||||
<i class="fas fa-info-circle"></i> <?= escape($dogdata['name']); ?> hat noch keine Ergebnisse
|
||||
</div>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php if(count($results) > 0): ?>
|
||||
<div class="col">
|
||||
<div id="graph" data-bs-theme="light" class="card bg-light text-black" style="min-height: 400px;"></div>
|
||||
<script type="text/javascript">
|
||||
// Initialize the echarts instance based on the prepared dom
|
||||
var myChart = echarts.init(document.getElementById('graph'));
|
||||
|
||||
// Specify the configuration items and data for the chart
|
||||
var option = {
|
||||
title: {
|
||||
text: 'Stacked Line'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
legend: {
|
||||
data: ['Geschwindigkeit', 'Fehler', 'Verweigerungen', 'Zeit', 'Geschwindigkeit','Punkte','Platz']
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
toolbox: {
|
||||
feature: {
|
||||
saveAsImage: {}
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: <?= json_encode($sdata['dates']); ?>
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'Geschwindigkeit',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
data: <?= json_encode($sdata['speed']); ?>
|
||||
},
|
||||
{
|
||||
name: 'Fehler',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
data: <?= json_encode($sdata['errors']); ?>
|
||||
},
|
||||
{
|
||||
name: 'Verweigerungen',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
data: <?= json_encode($sdata['refusals']); ?>
|
||||
},
|
||||
{
|
||||
name: 'Zeit',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
data: <?= json_encode($sdata['time']); ?>
|
||||
},
|
||||
{
|
||||
name: 'Punkte',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
data: <?= json_encode($sdata['points']); ?>
|
||||
},
|
||||
{
|
||||
name: 'Platz',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
data: <?= json_encode($sdata['ranking']); ?>
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// Display the chart using the configuration items and data just specified.
|
||||
myChart.setOption(option);
|
||||
</script>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,38 +1,56 @@
|
||||
<div>
|
||||
<h1>Hund hinzufügen/bearbeiten</h1>
|
||||
<h1>Hund <?= $dogid?'Bearbeiten':'Hinzufügen'; ?></h1>
|
||||
|
||||
<form hx-post="/dogs/edit" hx-target="#response">
|
||||
<form id="dogeditform" hx-post="/dogs/edit" hx-encoding='multipart/form-data' hx-target="#response" class="row row-cols-2">
|
||||
<input type="hidden" name="dog_id" value="<?= $dogid; ?>">
|
||||
<div>
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="name" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Name</label>
|
||||
<input type="text" value="<?= $dogdata['name']; ?>" id="name" name="name" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="Max" required>
|
||||
<input type="text" value="<?= $dogdata['name']; ?>" id="name" name="name" class="form-control" placeholder="Max" required>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="kennel_name" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Zuchtname</label>
|
||||
<input type="text" value="<?= $dogdata['kennel_name']; ?>" id="kennel_name" name="kennel_name" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="Zuchtname">
|
||||
<input type="text" value="<?= $dogdata['kennel_name']; ?>" id="kennel_name" name="kennel_name" class="form-control" placeholder="Zuchtname">
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="dog_breed" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Rasse</label>
|
||||
<input type="text" value="<?= $dogdata['breed']; ?>" id="dog_breed" name="dog_breed" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="Flowbite">
|
||||
<input type="text" value="<?= $dogdata['breed']; ?>" id="dog_breed" name="dog_breed" class="form-control" placeholder="Flowbite">
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="dog_size" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Größe des Hundes (in cm)</label>
|
||||
<input type="number" value="<?= $dogdata['size']; ?>" id="dog_size" name="dog_size" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="">
|
||||
<input type="number" value="<?= $dogdata['size']; ?>" id="dog_size" name="dog_size" class="form-control" placeholder="">
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="dog_birthday" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Geburtstag des Hundes</label>
|
||||
<input type="date" value="<?= $dogdata['birthday']; ?>" id="dog_birthday" name="dog_birthday" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="" required>
|
||||
<input type="date" value="<?= $dogdata['birthday']; ?>" id="dog_birthday" name="dog_birthday" class="form-control" placeholder="" required>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="agi_active" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Hund ist noch aktiv im Sport?</label>
|
||||
<select id="agi_active" name="agi_active" class="form-control">
|
||||
<option value="1" <?= $dogdata['active']=='1'?'selected':''; ?>>Ja</option>
|
||||
<option value="0" <?= $dogdata['active']=='0'?'selected':''; ?>>Nein</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="agi_height_category" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Agility Größenklasse</label>
|
||||
<select id="agi_height_category" name="agi_height_category" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
|
||||
<select id="agi_height_category" name="agi_height_category" class="form-control">
|
||||
<option value="S" <?= $dogdata['agility_size']=='S'?'selected':''; ?>>S</option>
|
||||
<option value="M" <?= $dogdata['agility_size']=='M'?'selected':''; ?>>M</option>
|
||||
<option value="I" <?= $dogdata['agility_size']=='I'?'selected':''; ?>>I</option>
|
||||
<option value="L" <?= $dogdata['agility_size']=='L'?'selected':''; ?>>L</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="photo" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Photo</label>
|
||||
<input type="file" accept="image/png, image/jpeg, image/gif" id="photo" name="photo">
|
||||
</div>
|
||||
<button type="submit" name="submit" value="true" class="btn btn-primary">Submit</button>
|
||||
</form>
|
||||
<progress id='progress' value='0' max='100'></progress>
|
||||
<div id="response"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
htmx.on('#dogeditform', 'htmx:xhr:progress', function(evt) {
|
||||
htmx.find('#progress').setAttribute('value', evt.detail.loaded/evt.detail.total * 100)
|
||||
});
|
||||
</script>
|
||||
@@ -1,42 +1,26 @@
|
||||
<h1">Meine Hunde</h1>
|
||||
|
||||
|
||||
<h1>Meine Hunde</h1>
|
||||
<figure>
|
||||
<table>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<?php foreach (array_keys($doggos[0]) as $key) : ?>
|
||||
<th>
|
||||
<?= $key ?>
|
||||
</th>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<th>
|
||||
Bearbeiten
|
||||
</th>
|
||||
<th>
|
||||
Löschen
|
||||
</th>
|
||||
<th>Foto</th>
|
||||
<th>Name</th>
|
||||
<th>Geburstag</th>
|
||||
<th>Aktiv</th>
|
||||
<th>Bearbeiten</th>
|
||||
<th>Löschen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($doggos as $dog) : ?>
|
||||
|
||||
<tr>
|
||||
<?php foreach (array_keys($dog) as $key) : ?>
|
||||
<td>
|
||||
<?= $dog[$key] ?>
|
||||
</td>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<td>
|
||||
<button hx-get="/dogs/edit/<?= $dog['id'] ?>" hx-push-url="/dogs/edit/<?= $dog['id'] ?>" hx-target="#main" >Bearbeiten</button>
|
||||
</td>
|
||||
<td>
|
||||
<button hx-get="/dogs/delete/<?= $dog['id'] ?>" hx-target="#main" >Löschen</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><img src="<?= $dog['photo'] ?>/50x50/forcesize"></td>
|
||||
<td><?= escape($dog['name']); ?></td>
|
||||
<td><?= escape($dog['birthday']); ?></td>
|
||||
<td><?= escape($dog['active'])?'Ja':'Nein'; ?></td>
|
||||
<td><button hx-get="/dogs/edit/<?= $dog['id'] ?>" hx-push-url="/dogs/edit/<?= $dog['id'] ?>" hx-target="#main" class="btn btn-primary"><i class="fas fa-edit"></i></button></td>
|
||||
<td><button hx-get="/dogs/delete/<?= $dog['id'] ?>" hx-target="#main" hx-confirm="Bist du sicher, dass du <?= escape($dog['name']); ?> löschen willst" class="btn btn-danger"><i class="fas fa-trash"></i></button></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -2,15 +2,17 @@
|
||||
|
||||
class Err extends Page {
|
||||
|
||||
function notfound($params)
|
||||
function notfound($params=false)
|
||||
{
|
||||
$this->set("page",$params[0]);
|
||||
$this->set('template', "notfound.html");
|
||||
|
||||
}
|
||||
|
||||
function notallowed()
|
||||
{
|
||||
return json_encode(['error'=>'not allowed']);
|
||||
$this->set("loggedin",(isset($_SESSION['user']) && $_SESSION['user'] !== false));
|
||||
$this->set('template', "notallowed.html");
|
||||
}
|
||||
|
||||
}
|
||||
13
web/pages/err/notallowed.html
Normal file
13
web/pages/err/notallowed.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<div class="alert alert-danger animate__animated animate__headShake" role="alert">
|
||||
<h4 class="alert-heading">Not allowed</h4>
|
||||
Zugriff nicht erlaubt
|
||||
</div>
|
||||
|
||||
<div class="row justify-content-center align-items-center g-2">
|
||||
<div class="col"></div>
|
||||
<div class="col">
|
||||
<?php if(!$loggedin) : ?>
|
||||
<?= partial('../../pages/login/login.html'); ?>
|
||||
<?php endif; ?></div>
|
||||
<div class="col"></div>
|
||||
</div>
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4" role="alert">
|
||||
<p class="font-bold">404 - Not found</p>
|
||||
<p>I have no memory of <?= escape($page) ?></p>
|
||||
<p>I have no memory of <span class="badge"><?= escape($page) ?></span></p>
|
||||
<img src="https://pictshare.net/4s9gi3.gif" alt="Gandalf: I have no memory of this place"/>
|
||||
</div>
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Features extends Page {
|
||||
|
||||
function index() {
|
||||
$this->set('template', 'features.html');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
|
||||
<section class="text-gray-600 body-font">
|
||||
<div class="container px-5 py-24 mx-auto">
|
||||
<h1 class="sm:text-3xl text-2xl font-medium title-font text-center text-gray-900 mb-20">Raw Denim Heirloom Man Braid
|
||||
<br class="hidden sm:block">Selfies Wayfarers
|
||||
</h1>
|
||||
<div class="flex flex-wrap sm:-m-4 -mx-4 -mb-10 -mt-4 md:space-y-0 space-y-6">
|
||||
<div class="p-4 md:w-1/3 flex">
|
||||
<div class="w-12 h-12 inline-flex items-center justify-center rounded-full bg-indigo-100 text-indigo-500 mb-4 flex-shrink-0">
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-6 h-6" viewBox="0 0 24 24">
|
||||
<path d="M22 12h-4l-3 9L9 3l-3 9H2"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-grow pl-6">
|
||||
<h2 class="text-gray-900 text-lg title-font font-medium mb-2">Shooting Stars</h2>
|
||||
<p class="leading-relaxed text-base">Blue bottle crucifix vinyl post-ironic four dollar toast vegan taxidermy. Gastropub indxgo juice poutine, ramps microdosing banh mi pug VHS try-hard ugh iceland kickstarter tumblr live-edge tilde.</p>
|
||||
<a class="mt-3 text-indigo-500 inline-flex items-center">Learn More
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-4 h-4 ml-2" viewBox="0 0 24 24">
|
||||
<path d="M5 12h14M12 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4 md:w-1/3 flex">
|
||||
<div class="w-12 h-12 inline-flex items-center justify-center rounded-full bg-indigo-100 text-indigo-500 mb-4 flex-shrink-0">
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-6 h-6" viewBox="0 0 24 24">
|
||||
<circle cx="6" cy="6" r="3"></circle>
|
||||
<circle cx="6" cy="18" r="3"></circle>
|
||||
<path d="M20 4L8.12 15.88M14.47 14.48L20 20M8.12 8.12L12 12"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-grow pl-6">
|
||||
<h2 class="text-gray-900 text-lg title-font font-medium mb-2">The Catalyzer</h2>
|
||||
<p class="leading-relaxed text-base">Blue bottle crucifix vinyl post-ironic four dollar toast vegan taxidermy. Gastropub indxgo juice poutine, ramps microdosing banh mi pug VHS try-hard ugh iceland kickstarter tumblr live-edge tilde.</p>
|
||||
<a class="mt-3 text-indigo-500 inline-flex items-center">Learn More
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-4 h-4 ml-2" viewBox="0 0 24 24">
|
||||
<path d="M5 12h14M12 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4 md:w-1/3 flex">
|
||||
<div class="w-12 h-12 inline-flex items-center justify-center rounded-full bg-indigo-100 text-indigo-500 mb-4 flex-shrink-0">
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-6 h-6" viewBox="0 0 24 24">
|
||||
<path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"></path>
|
||||
<circle cx="12" cy="7" r="4"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="flex-grow pl-6">
|
||||
<h2 class="text-gray-900 text-lg title-font font-medium mb-2">Neptune</h2>
|
||||
<p class="leading-relaxed text-base">Blue bottle crucifix vinyl post-ironic four dollar toast vegan taxidermy. Gastropub indxgo juice poutine, ramps microdosing banh mi pug VHS try-hard ugh iceland kickstarter tumblr live-edge tilde.</p>
|
||||
<a class="mt-3 text-indigo-500 inline-flex items-center">Learn More
|
||||
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-4 h-4 ml-2" viewBox="0 0 24 24">
|
||||
<path d="M5 12h14M12 5l7 7-7 7"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -13,8 +13,37 @@ class Home extends Page
|
||||
{
|
||||
$u = new User();
|
||||
$this->set('userdata', $u->getAll());
|
||||
$this->set('template', "home.html");
|
||||
//return $this->renderPagecontent();
|
||||
|
||||
if(!$_SESSION['user'])
|
||||
{
|
||||
$this->set('template', 'home-nouser.html');
|
||||
return;
|
||||
}
|
||||
else {
|
||||
$dogs = $_SESSION['user']->data['dogs'];
|
||||
$doggos = [];
|
||||
|
||||
foreach($dogs as $key => $dogid)
|
||||
{
|
||||
$dog = new Dog();
|
||||
try{
|
||||
$dog->load($dogid);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
error_log("Dog $dogid not found. Deleting from user");
|
||||
unset($_SESSION['user']->data['dogs'][$key]);
|
||||
$_SESSION['user']->save();
|
||||
continue;
|
||||
}
|
||||
if($dog->data)
|
||||
$doggos[] = array_merge($dog->data,['id'=>$dogid]);
|
||||
$this->set('doggos',$doggos);
|
||||
}
|
||||
//var_dump($doggos);
|
||||
$this->set('template', "home.html");
|
||||
}
|
||||
}
|
||||
|
||||
function maySeeThisPage(){return true;}
|
||||
|
||||
56
web/pages/home/home-nouser.html
Normal file
56
web/pages/home/home-nouser.html
Normal file
@@ -0,0 +1,56 @@
|
||||
<div class="text-center mt-3">
|
||||
<h1 class="text-4xl font-bold tracking-tight text-gray-900 sm:text-6xl">Dogstats - der Agilityhelfer</h1>
|
||||
<p class="mt-6 text-lg leading-8 text-gray-600">Steigere deine Leistung mit Dogstats.</p>
|
||||
</div>
|
||||
|
||||
<h1>Admin stuff</h1>
|
||||
|
||||
<div class="container text-center">
|
||||
<div class="row">
|
||||
<?php foreach ($userdata as $user) : ?>
|
||||
<div class="m-3 col">
|
||||
<div class="card">
|
||||
<img src="<?= $user['photo']?:'https://pictshare.net/pj7vzx.jpg' ?>" class="card-img-top" alt="...">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><?= escape($user['firstname'].' '.$user['lastname']) ?></h5>
|
||||
<p class="card-text"><?= escape($user['email']) ?></p>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item">
|
||||
<h6>uuid</h6>
|
||||
<span class="badge rounded-pill text-bg-secondary"><?= escape($user['uuid']); ?></span>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<h6>Registered</h6>
|
||||
<?= escape($user['registered']); ?>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<h6>last_login</h6>
|
||||
<?= escape($user['last_login']); ?>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<h6>Active</h6>
|
||||
<?= $user['active']?'yes':'no'; ?>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<h6>Dogs</h6>
|
||||
<?php foreach($user['dogs'] as $dog): ?>
|
||||
<a href="/dogs/overview/<?= $dog ?>" class="btn btn-secondary"><?= escape((new Dog())->getField('name',$dog)); ?></a>
|
||||
<?php endforeach; ?>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="card-body">
|
||||
<button class="btn btn-primary" name="email" value="<?= $user['email'] ?>" hx-post="/admin/loginas/">Login</button>
|
||||
<button class="btn btn-primary"name="email" value="<?= $user['email'] ?>" hx-post="/admin/edituser/" hx-target="#main">Edit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hidden sm:mb-8 sm:flex sm:justify-center">
|
||||
<div class="relative rounded-full px-3 py-1 text-sm leading-6 text-gray-600 ring-1 ring-gray-900/10 hover:ring-gray-900/20">
|
||||
Currently logged in as:
|
||||
<?= $_SESSION['userid']?:'nobody' ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,58 +1,30 @@
|
||||
<div class="hidden sm:mb-8 sm:flex sm:justify-center">
|
||||
<div class="relative rounded-full px-3 py-1 text-sm leading-6 text-gray-600 ring-1 ring-gray-900/10 hover:ring-gray-900/20">
|
||||
Currently logged in as:
|
||||
<?= $_SESSION['userid']?:'nobody' ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="text-center mt-3">
|
||||
<h1 class="text-4xl font-bold tracking-tight text-gray-900 sm:text-6xl">Dogstats - der Agilityhelfer</h1>
|
||||
<p class="mt-6 text-lg leading-8 text-gray-600">Anim aute id magna aliqua ad ad non deserunt sunt.
|
||||
Qui irure qui lorem cupidatat commodo. Elit sunt amet fugiat veniam occaecat fugiat aliqua.</p>
|
||||
<div class="mt-10 flex items-center justify-center gap-x-6">
|
||||
<a href="#" class="rounded-md bg-indigo-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Get
|
||||
started</a>
|
||||
<a href="#" class="text-sm font-semibold leading-6 text-gray-900">Learn more <span aria-hidden="true">→</span></a>
|
||||
</div>
|
||||
<p class="mt-6 text-lg leading-8 text-gray-600">Steigere deine Leistung mit Dogstats.</p>
|
||||
</div>
|
||||
|
||||
<h1>Admin stuff</h1>
|
||||
<figure>
|
||||
<table role="grid">
|
||||
<thead>
|
||||
<tr>
|
||||
<?php foreach (array_keys($userdata[0]) as $key) : ?>
|
||||
<th>
|
||||
<?= $key ?>
|
||||
</th>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<th>
|
||||
Login
|
||||
</th>
|
||||
<th>
|
||||
Edit
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($userdata as $user) : ?>
|
||||
|
||||
<tr>
|
||||
<?php foreach (array_keys($user) as $key) : ?>
|
||||
<td class="px-6 py-4 text-sm text-gray-500">
|
||||
<?= is_array($user[$key])?json_encode($user[$key]):$user[$key] ?>
|
||||
</td>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<td>
|
||||
<button name="email" value="<?= $user['email'] ?>" hx-post="/admin/loginas/">Login</button>
|
||||
</td>
|
||||
<td>
|
||||
<button name="email" value="<?= $user['email'] ?>" hx-post="/admin/edituser/" hx-target="#main">Edit</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</figure>
|
||||
<div>
|
||||
<h3 class="text-center">Schnellauswahl</h3>
|
||||
<div class="d-sm-flex justify-content-sm-center">
|
||||
<div class="m-sm-2 border p-3 rounded-2 shadow">
|
||||
<a href="/tournaments/add" class="btn btn-secondary mb-2">Turnier hinzufügen</a>
|
||||
</div>
|
||||
<?php if ($doggos) : ?>
|
||||
<?php foreach ($doggos as $dog) : ?>
|
||||
<?php if (!$dog['active']) continue; ?>
|
||||
<div class="m-sm-2 border p-3 rounded-2 shadow">
|
||||
<div class="d-flex mb-2 align-items-center">
|
||||
<img src="<?= $dog['photo'] ?>/100x100/forcesize">
|
||||
<a href="/dogs/overview/<?= $dog['id'] ?>" class="ms-3 link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover"><?= escape($dog['name']); ?></a>
|
||||
</div>
|
||||
<a href="/smart#<?= escape($dog['name']); ?>" class="btn btn-secondary mb-2 d-block">Turnier importieren</a>
|
||||
<a href="#" class="btn btn-secondary mb-2 d-block">Training hinzufügen</a>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php else : ?>
|
||||
<div class="">
|
||||
<a href="/dogs/add" class="btn btn-secondary mb-2 d-block">Hund hinzufügen</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -5,7 +5,9 @@ class Login extends Page {
|
||||
function setMenu()
|
||||
{
|
||||
if($_SESSION['user'])
|
||||
{
|
||||
$this->menu_text = $_SESSION['userid'];
|
||||
}
|
||||
else
|
||||
$this->menu_text = 'Login';
|
||||
$this->menu_image = 'far fa-user';
|
||||
@@ -16,6 +18,7 @@ class Login extends Page {
|
||||
{
|
||||
if($_SESSION['user'])
|
||||
{
|
||||
$this->addSubmenuItem('Profil', '/profile', 'fas fa-user');
|
||||
$this->addSubmenuItem('Settings', '/settings', 'fas fa-cog');
|
||||
$this->addSubmenuItem('Logout', '/login/logout', 'fas fa-sign-out-alt', 'bg-red-500');
|
||||
}
|
||||
@@ -25,7 +28,7 @@ class Login extends Page {
|
||||
|
||||
function index()
|
||||
{
|
||||
$this->set('hello','world');
|
||||
|
||||
$this->set('template', 'login.html');
|
||||
//return print_r($_REQUEST, true);
|
||||
}
|
||||
@@ -41,17 +44,78 @@ class Login extends Page {
|
||||
|
||||
function logout()
|
||||
{
|
||||
//delete cookie
|
||||
setcookie('token', '', time() - 3600, "/");
|
||||
session_destroy();
|
||||
$this->redirect('/');
|
||||
}
|
||||
|
||||
function validate()
|
||||
{
|
||||
$email = $_REQUEST['email'];
|
||||
$password = $_REQUEST['password'];
|
||||
$email = trim($_REQUEST['email']);
|
||||
$password = trim($_REQUEST['password']);
|
||||
$remember = $_REQUEST['remember'];
|
||||
|
||||
return print_r(['email'=>$email,'password'=>$password,'remember'=>$remember], true);
|
||||
$error = false;
|
||||
|
||||
$u = new User();
|
||||
|
||||
if(!$email || !$password)
|
||||
$error = 'Bitte gib deine E-Mail-Adresse und dein Passwort ein';
|
||||
else if(!filter_var($email, FILTER_VALIDATE_EMAIL))
|
||||
$error = 'Bitte gib eine gültige E-Mail-Adresse ein';
|
||||
else if(!$u->exists($email))
|
||||
$error = 'Benutzer nicht gefunden. Schon registriert?';
|
||||
else {
|
||||
|
||||
try{
|
||||
$u->load($email);
|
||||
}
|
||||
catch(Exception $e){
|
||||
$error = $e->getMessage();
|
||||
}
|
||||
if(!password_verify($password, $u->data['password']))
|
||||
$error = 'E-Mail-Adresse oder Passwort falsch';
|
||||
else if($u->data['active'] == 0)
|
||||
$error = 'Dein Account ist noch nicht aktiviert';
|
||||
else
|
||||
{
|
||||
//if $remmeber is true, create and set cookie so the user will be automatically logged in next time
|
||||
if($remember)
|
||||
{
|
||||
//check if user has a valid cookie
|
||||
if(isset($_COOKIE['token']) && $u->token == $_COOKIE['token'])
|
||||
{
|
||||
$token =$u->token;
|
||||
setcookie('token', $token, time() + (86400 * 30), "/");
|
||||
}
|
||||
else
|
||||
{
|
||||
//if no, create a new token
|
||||
$token = uuid4();
|
||||
$u->token = $token;
|
||||
$u->save();
|
||||
setcookie('token', $token, time() + (86400 * 30), "/");
|
||||
}
|
||||
}
|
||||
|
||||
$u->login();
|
||||
if($_SERVER['HTTP_HX_CURRENT_URL'] && !endsWith($_SERVER['HTTP_HX_CURRENT_URL'],'/login'))
|
||||
$this->redirect($_SERVER['HTTP_HX_CURRENT_URL']);
|
||||
else
|
||||
$this->redirect('/');
|
||||
}
|
||||
}
|
||||
|
||||
if($error)
|
||||
{
|
||||
$this->set('template', '/templates/partials/error.html');
|
||||
$this->set('errorTitle', 'Error');
|
||||
$this->set('errorMessage', $error);
|
||||
}
|
||||
|
||||
|
||||
//return print_r(['email'=>$email,'password'=>$password,'remember'=>$remember], true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +1,20 @@
|
||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto lg:py-0">
|
||||
<div class="w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700">
|
||||
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||
<h1 class="text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
|
||||
Sign in to your account
|
||||
</h1>
|
||||
<div id="response" class="text-gray-900 dark:text-white">
|
||||
<?= $hello ?>
|
||||
</div>
|
||||
<form class="space-y-4 md:space-y-6" hx-post="/login/validate" hx-target="#response">
|
||||
<div>
|
||||
<label for="email" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your email</label>
|
||||
<input type="email" name="email" id="email" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="name@company.com" required="">
|
||||
</div>
|
||||
<div>
|
||||
<label for="password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Password</label>
|
||||
<input type="password" name="password" id="password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required="">
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-start">
|
||||
<div class="flex items-center h-5">
|
||||
<input id="remember" name="remember" aria-describedby="remember" type="checkbox" value="true" class="w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-primary-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-primary-600 dark:ring-offset-gray-800">
|
||||
</div>
|
||||
<div class="ml-3 text-sm">
|
||||
<label for="remember" class="text-gray-500 dark:text-gray-300">Remember me</label>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#" class="text-sm font-medium text-primary-600 hover:underline dark:text-primary-500 dark:text-gray-400">Forgot password?</a>
|
||||
</div>
|
||||
<button type="submit" class="bg-sky-500 hover:bg-sky-700 p-2 rounded">
|
||||
Sign in
|
||||
</button>
|
||||
<p class="text-sm font-light text-gray-500 dark:text-gray-400">
|
||||
Don’t have an account yet? <a href="#" hx-get="/register" hx-push-url="/register" hx-target="#main" class="font-medium text-primary-600 hover:underline dark:text-primary-500">Sign up</a>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<form class="space-y-4 md:space-y-6" hx-post="/login/validate" hx-target="#response">
|
||||
<div id="response" class="text-gray-900 dark:text-white"></div>
|
||||
<div class="form-group">
|
||||
<label for="exampleInputEmail1">Email address</label>
|
||||
<input name="email" type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email">
|
||||
<small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="exampleInputPassword1">Password</label>
|
||||
<input name="password" type="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
|
||||
</div>
|
||||
<div class="form-group form-check">
|
||||
<input name="remember" type="checkbox" class="form-check-input" id="exampleCheck1">
|
||||
<label class="form-check-label" for="exampleCheck1">Remember me</label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
<p class="text-sm font-light text-gray-500 dark:text-gray-400">
|
||||
Don't have an account yet? <a href="#" hx-get="/register" hx-push-url="/register" hx-target="#main" class="font-medium text-primary-600 hover:underline dark:text-primary-500">Sign up</a>
|
||||
</p>
|
||||
</form>
|
||||
|
||||
87
web/pages/profile/controller.php
Normal file
87
web/pages/profile/controller.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
class Profile extends Page {
|
||||
|
||||
function index()
|
||||
{
|
||||
$this->set('user', $_SESSION['user']->data);
|
||||
$this->set('template', 'profile.html');
|
||||
}
|
||||
|
||||
function edit()
|
||||
{
|
||||
if($_REQUEST['submit']=='true')
|
||||
{
|
||||
$error = false;
|
||||
|
||||
$_SESSION['user']->load();
|
||||
$_SESSION['user']->data['firstname'] = trim($_REQUEST['firstname']);
|
||||
$_SESSION['user']->data['lastname'] = trim($_REQUEST['lastname']);
|
||||
//$_SESSION['user']->data['email'] = $_REQUEST['email'];
|
||||
$_SESSION['user']->data['birthday'] = $_REQUEST['birthday'];
|
||||
$_SESSION['user']->data['club'] = trim($_REQUEST['club']);
|
||||
//$_SESSION['user']->data['timezone'] = $_REQUEST['timezone'];
|
||||
|
||||
if(!strtotime($_SESSION['user']->data['birthday']))
|
||||
$error = 'Das Geburstdatum ist ungültig. Bitte die Eingabe prüfen';
|
||||
|
||||
$newphoto = false;
|
||||
if($_FILES['photo'])
|
||||
{
|
||||
$photo = $_FILES['photo'];
|
||||
$photo_name = $photo['name'];
|
||||
$photo_tmp_name = $photo['tmp_name'];
|
||||
$photo_size = $photo['size'];
|
||||
$photo_error = $photo['error'];
|
||||
$photo_type = $photo['type'];
|
||||
|
||||
$allowed = ['jpg','jpeg','png','gif'];
|
||||
$photo_ext = strtolower(end(explode('.', $photo_name)));
|
||||
|
||||
if(in_array($photo_ext, $allowed))
|
||||
{
|
||||
if($photo_error === 0)
|
||||
{
|
||||
if($photo_size < 10000000)
|
||||
{
|
||||
$answer = pictshareUploadImage($photo_tmp_name);
|
||||
if($answer['status']=='ok' && in_array($answer['filetype'],['jpeg','png','gif']))
|
||||
$newphoto = $answer['url'];
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Fehler beim CDN Upload: '.json_encode($answer,true)]);
|
||||
}
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Die Datei ist zu groß. Bitte eine kleinere Datei hochladen']);
|
||||
}
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Beim Upload der Datei ist ein Fehler aufgetreten']);
|
||||
}
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Dieser Dateityp ist nicht erlaubt. Bitte nur jpg, jpeg oder png Dateien hochladen']);
|
||||
}
|
||||
|
||||
if($newphoto)
|
||||
$_SESSION['user']->data['photo'] = $newphoto;
|
||||
|
||||
try{
|
||||
$_SESSION['user']->save();
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
return partial('error.html', ['errorMessage' => 'Fehler beim Speichern des Profils: '.$e->getMessage()]);
|
||||
}
|
||||
|
||||
$this->redirect('/profile');
|
||||
}
|
||||
|
||||
$this->set('user', $_SESSION['user']->data);
|
||||
$this->set('template', 'edit_profile.html');
|
||||
}
|
||||
|
||||
function maySeeThisPage() {
|
||||
if($_SESSION['user']) //wenn eingeloggt, kein problem
|
||||
return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
}
|
||||
39
web/pages/profile/edit_profile.html
Normal file
39
web/pages/profile/edit_profile.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<div>
|
||||
<h1>Mein Profil bearbeiten</h1>
|
||||
|
||||
<form id="dogeditform" hx-post="/profile/edit" hx-encoding='multipart/form-data' hx-target="#response" class="row row-cols-2">
|
||||
<div>
|
||||
<label for="firstname">Vorname</label>
|
||||
<input type="text" value="<?= $user['firstname']; ?>" id="firstname" name="firstname" class="form-control" placeholder="Max">
|
||||
</div>
|
||||
<div>
|
||||
<label for="lastname">Nachname</label>
|
||||
<input type="text" value="<?= $user['lastname']; ?>" id="lastname" name="lastname" class="form-control" placeholder="Mustermann">
|
||||
</div>
|
||||
<div>
|
||||
<label for="birthday">Geburtstag</label>
|
||||
<input type="date" value="<?= $user['birthday']; ?>" id="birthday" name="birthday" class="form-control" placeholder="">
|
||||
</div>
|
||||
<div>
|
||||
<label for="email">E-Mail</label>
|
||||
<input type="text" value="<?= $user['email']; ?>" id="email" name="email" class="form-control" placeholder="max@max.com" disabled>
|
||||
</div>
|
||||
<div>
|
||||
<label for="club">Verein</label>
|
||||
<input type="text" value="<?= $user['club']; ?>" id="club" name="club" class="form-control" placeholder="Vereinsname">
|
||||
</div>
|
||||
<div>
|
||||
<label for="photo">Photo</label>
|
||||
<input type="file" accept="image/png, image/jpeg, image/gif" id="photo" name="photo">
|
||||
</div>
|
||||
<button type="submit" name="submit" value="true" class="btn btn-primary">Speichern</button>
|
||||
</form>
|
||||
<progress id='progress' value='0' max='100'></progress>
|
||||
<div id="response"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
htmx.on('#dogeditform', 'htmx:xhr:progress', function(evt) {
|
||||
htmx.find('#progress').setAttribute('value', evt.detail.loaded/evt.detail.total * 100)
|
||||
});
|
||||
</script>
|
||||
29
web/pages/profile/profile.html
Normal file
29
web/pages/profile/profile.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<!-- FILEPATH: /home/chris/git/dogstats/web/pages/dogs/dog.html -->
|
||||
|
||||
<div class="container">
|
||||
<h1>Profil</h1>
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<img src="<?= $user['photo']?:'https://pictshare.net/pj7vzx.jpg' ?>/300x300/forcesize" class="card-img-top" alt="<?= escape($user['name']); ?>'s profile Picture">
|
||||
</div>
|
||||
|
||||
<div class="col-9">
|
||||
<h3 class="card-title"><?= escape($user['firstname'].' '.$user['lastname']); ?></h3>
|
||||
<div>
|
||||
<?php if($user['birthday']): ?><p>Geburstag: <?= $user['birthday'].' ('.date_diff(date_create($user['birthday']), date_create('now'))->y.')' ?></p> <?php endif; ?>
|
||||
<?php if($user['email']): ?><p>Email: <?= escape($user['email']); ?></p> <?php endif; ?>
|
||||
<?php if($user['club']): ?><p>Verein: <?= escape($user['club']); ?></p> <?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
<button type="button" class="btn btn-secondary" hx-get="/profile/edit" hx-target="#main">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-8" id="sitemain">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -47,6 +47,7 @@ class Register extends Page {
|
||||
try
|
||||
{
|
||||
$u->save();
|
||||
$this->redirect('/register/success');
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
@@ -55,7 +56,7 @@ class Register extends Page {
|
||||
$this->set('errorMessage', $e->getMessage());
|
||||
return;
|
||||
}
|
||||
//$this->redirect('/register/success');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,19 @@
|
||||
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto lg:py-0">
|
||||
<div class="w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700">
|
||||
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
|
||||
<h1 class="text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
|
||||
Register
|
||||
</h1>
|
||||
<div id="response" class="text-gray-900 dark:text-white"></div>
|
||||
<form class="space-y-4 md:space-y-6" hx-post="/register/validate" hx-target="#response">
|
||||
<div>
|
||||
<label for="email" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Your email</label>
|
||||
<input type="email" name="email" id="email" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="name@company.com" required="">
|
||||
</div>
|
||||
<div>
|
||||
<label for="password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Password</label>
|
||||
<input type="password" name="password" id="password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required="">
|
||||
</div>
|
||||
<div>
|
||||
<label for="password2" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Repeat Password</label>
|
||||
<input type="password" name="password2" id="password2" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required="">
|
||||
</div>
|
||||
<h1>Registrieren</h1>
|
||||
|
||||
<button type="submit" class="bg-sky-500 hover:bg-sky-700 p-2 rounded">
|
||||
Account erstellen
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<form class="space-y-4 md:space-y-6" hx-post="/register/validate" hx-target="#response">
|
||||
<div id="response"></div>
|
||||
<div class="form-group">
|
||||
<label for="exampleInputEmail1">Email address</label>
|
||||
<input name="email" type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email">
|
||||
<small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="exampleInputPassword1">Passwort</label>
|
||||
<input name="password" type="password" class="form-control" id="exampleInputPassword1" placeholder="Passwort">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="exampleInputPassword2">Passwort wiederholen</label>
|
||||
<input name="password2" type="password" class="form-control" id="exampleInputPassword2" placeholder="Passwort Wiederholen">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</form>
|
||||
|
||||
247
web/pages/runs/controller.php
Normal file
247
web/pages/runs/controller.php
Normal file
@@ -0,0 +1,247 @@
|
||||
<?php
|
||||
|
||||
class Runs extends Page {
|
||||
|
||||
function setMenu()
|
||||
{
|
||||
// $this->menu_text = 'Läufe';
|
||||
// $this->menu_image = 'fas fa-running';
|
||||
// $this->menu_priority = 3;
|
||||
}
|
||||
|
||||
function overview()
|
||||
{
|
||||
$run = new Run();
|
||||
$rid = $this->params[0];
|
||||
if(!$run->exists($rid))
|
||||
return partial('error.html', ['errorMessage' => 'Dieser Lauf existiert nicht']);
|
||||
$run->load($rid);
|
||||
$t = new Tournament();
|
||||
$t->load($run->data['tournament']);
|
||||
|
||||
$res = new Result();
|
||||
$results = $res->getDataOfRun($rid);
|
||||
|
||||
|
||||
$this->set('admin',$t->amIAdmin());
|
||||
$this->set('tournament', $t->data);
|
||||
$this->set('tournament_id', $run->data['tournament']);
|
||||
$this->set('results', $results);
|
||||
$this->set('run', $run->data);
|
||||
$this->set('run_id', $rid);
|
||||
$this->set('template', 'run.html');
|
||||
}
|
||||
|
||||
function addresults()
|
||||
{
|
||||
$rid = $this->params[0];
|
||||
$run = new Run();
|
||||
if(!$run->exists($rid))
|
||||
return partial('error.html', ['errorMessage' => 'Dieser Lauf existiert nicht']);
|
||||
$run->load($rid);
|
||||
$t = new Tournament();
|
||||
$tid = $run->data['tournament'];
|
||||
$t->load($tid);
|
||||
if(!$t->amIAdmin() && !$t->isMyEvent($tid))
|
||||
return partial('error.html', ['errorMessage' => 'Du bist in diesem Turnier nicht angemeldet']);
|
||||
else
|
||||
{
|
||||
$this->set('tournament', $t->data);
|
||||
$this->set('tournament_id', $tid);
|
||||
$this->set('run', $run->data);
|
||||
$this->set('run_id', $rid);
|
||||
$this->set('template', 'edit_result.html');
|
||||
}
|
||||
}
|
||||
|
||||
function validateresults()
|
||||
{
|
||||
$rid = $_REQUEST['run_id'];
|
||||
$run = new Run();
|
||||
if(!$run->exists($rid))
|
||||
return partial('error.html', ['errorMessage' => 'Dieser Lauf existiert nicht']);
|
||||
$run->load($rid);
|
||||
$t = new Tournament();
|
||||
$tid = $run->data['tournament'];
|
||||
$t->load($tid);
|
||||
$res = new Result();
|
||||
if($_REQUEST['result_id'])
|
||||
{
|
||||
if(!$res->exists($_REQUEST['result_id']))
|
||||
return partial('error.html', ['errorMessage' => 'Dieses Ergebnis existiert nicht']);
|
||||
$res->load($_REQUEST['result_id']);
|
||||
if(!$res->data['run']==$rid)
|
||||
return partial('error.html', ['errorMessage' => 'Dieses Ergebnis gehört nicht zu diesem Lauf']);
|
||||
}
|
||||
else
|
||||
$res->id = gen_ulid();
|
||||
if(!$t->amIAdmin() && !$t->isMyEvent($tid))
|
||||
return partial('error.html', ['errorMessage' => 'Du bist in diesem Turnier nicht angemeldet']);
|
||||
else
|
||||
{
|
||||
$dogid = $_REQUEST['dog'];
|
||||
if(!$dogid || $dogid=='false')
|
||||
return partial('error.html', ['errorMessage' => 'Du musst einen Hund auswählen']);
|
||||
$dog = new Dog();
|
||||
if(!$dog->exists($dogid))
|
||||
return partial('error.html', ['errorMessage' => 'Dieser Hund existiert nicht']);
|
||||
else if(!$dog->isMyDog($dogid))
|
||||
return partial('error.html', ['errorMessage' => 'Dieser Hund gehört nicht dir']);
|
||||
|
||||
$res->dog = $dogid;
|
||||
$res->disqualified = $_REQUEST['disqualified'];
|
||||
$res->refusals = $_REQUEST['refusals'];
|
||||
$res->timefaults = $_REQUEST['time_faults'];
|
||||
$res->runtime = $_REQUEST['time'];
|
||||
$res->penalties = $_REQUEST['penalties'];
|
||||
$res->speed = $_REQUEST['time_speed'];
|
||||
$res->rating = $_REQUEST['bewertung'];
|
||||
$res->points = $_REQUEST['points'];
|
||||
$res->ranking = $_REQUEST['rank'];
|
||||
$res->public = $_REQUEST['public'];
|
||||
$res->tournament = $tid;
|
||||
$res->run = $rid;
|
||||
$res->user = $_SESSION['user']->id;
|
||||
|
||||
if($_FILES['photos'])
|
||||
{
|
||||
foreach($_FILES['photos']['tmp_name'] as $key => $tmp_name)
|
||||
{
|
||||
try{
|
||||
$url = pictShareFormValidateAndUpload($_FILES['photos'],$key);
|
||||
$res->data['photos'][] = $url;
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
return partial('error.html', ['errorMessage' => 'Fehler beim Upload des Fotos: '.$e->getMessage()]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//filter out unique values so we don't have double entries
|
||||
$res->data['photos'] = array_unique($res->data['photos']);
|
||||
}
|
||||
|
||||
try{
|
||||
$resid = $res->save();
|
||||
|
||||
if(!in_array($resid, $run->data['results']))
|
||||
{
|
||||
$run->data['results'][] = $resid;
|
||||
$run->save();
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
return partial('error.html', ['errorMessage' => 'Fehler beim Speichern des Ergebnisses: '.$e->getMessage()]);
|
||||
}
|
||||
|
||||
$this->redirect('/runs/overview/'.$rid);
|
||||
}
|
||||
}
|
||||
|
||||
function add()
|
||||
{
|
||||
$tournament = $this->params[0];
|
||||
$t = new Tournament();
|
||||
if(!$t->exists($tournament))
|
||||
return partial('error.html', ['errorMessage' => 'Dieses Turnier existiert nicht']);
|
||||
$t->load($tournament);
|
||||
if(!$t->amIAdmin($tournament))
|
||||
return partial('error.html', ['errorMessage' => 'Du bist kein Admin dieses Turniers']);
|
||||
else
|
||||
{
|
||||
$this->set('tournament', $t->data);
|
||||
$this->set('tournament_id', $tournament);
|
||||
$this->set('template', 'edit_run.html');
|
||||
}
|
||||
}
|
||||
|
||||
function edit()
|
||||
{
|
||||
$rid = $this->params[0];
|
||||
$r = new Run();
|
||||
$t = new Tournament();
|
||||
if(!$r->exists($rid))
|
||||
return partial('error.html', ['errorMessage' => 'Dieser Run existiert nicht']);
|
||||
$r->load($rid);
|
||||
$tournament = $r->data['tournament'];
|
||||
$t->load($tournament);
|
||||
if(!$t->amIAdmin($tournament))
|
||||
return partial('error.html', ['errorMessage' => 'Du bist kein Admin dieses Turniers']);
|
||||
else
|
||||
{
|
||||
$this->set('tournament', $t->data);
|
||||
$this->set('tournament_id', $tournament);
|
||||
$this->set('run_id',$rid);
|
||||
$this->set('run',$r->data);
|
||||
$this->set('template', 'edit_run.html');
|
||||
}
|
||||
}
|
||||
|
||||
function validate()
|
||||
{
|
||||
|
||||
if($_REQUEST['submit'])
|
||||
{
|
||||
$t = new Tournament();
|
||||
|
||||
if(!$t->exists($_REQUEST['tournament_id']))
|
||||
return partial('error.html', ['errorMessage' => 'Dieses Turnier existiert nicht']);
|
||||
$t->load($_REQUEST['tournament_id']);
|
||||
|
||||
if(!$t->amIAdmin($_REQUEST['tournament_id']))
|
||||
return partial('error.html', ['errorMessage' => 'Du bist kein Admin dieses Turniers']);
|
||||
|
||||
$run = new Run();
|
||||
if($_REQUEST['run_id'])
|
||||
{
|
||||
if(!$run->exists($_REQUEST['run_id']))
|
||||
return partial('error.html', ['errorMessage' => 'Dieser Lauf existiert nicht']);
|
||||
$run->load($_REQUEST['run_id']);
|
||||
if(!$run->data['tournament']==$t->id)
|
||||
return partial('error.html', ['errorMessage' => 'Dieser Lauf gehört nicht zu diesem Turnier']);
|
||||
}
|
||||
else
|
||||
$run->id = gen_ulid();
|
||||
|
||||
|
||||
|
||||
$run->data['tournament'] = $_REQUEST['tournament_id'];
|
||||
$run->data['name'] = trim($_REQUEST['name']);
|
||||
$run->data['category'] = $_REQUEST['category'];
|
||||
$run->data['length'] = $_REQUEST['length'];
|
||||
$run->data['time_standard'] = $_REQUEST['time_standard'];
|
||||
$run->data['time_max'] = $_REQUEST['time_max'];
|
||||
$run->data['referee'] = $_REQUEST['referee'];
|
||||
|
||||
try{
|
||||
$runid = $run->save();
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
return partial('error.html', ['errorMessage' => 'Fehler beim Speichern des Laufs: '.$e->getMessage()]);
|
||||
}
|
||||
|
||||
if(!in_array($runid, $t->data['runs']))
|
||||
{
|
||||
$t->data['runs'][] = $runid;
|
||||
$t->save();
|
||||
}
|
||||
|
||||
if($_REQUEST['submit']=='forward')
|
||||
{
|
||||
$this->redirect('/runs/addresults/'.$runid);
|
||||
}
|
||||
else
|
||||
$this->redirect('/tournaments/event/'.$t->id);
|
||||
}
|
||||
else return partial('error.html', ['errorMessage' => 'Fehler beim Speichern des Laufs']);
|
||||
}
|
||||
|
||||
function maySeeThisPage() {
|
||||
if($_SESSION['user']) //wenn eingeloggt, kein problem
|
||||
return true;
|
||||
else return false;
|
||||
}
|
||||
}
|
||||
116
web/pages/runs/edit_result.html
Normal file
116
web/pages/runs/edit_result.html
Normal file
@@ -0,0 +1,116 @@
|
||||
<div class="container">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item">
|
||||
<a href="/tournaments/event/<?= $tournament_id; ?>" hx-push-url="/tournaments/event/<?= $tournament_id; ?>" hx-get="/tournaments/event/<?= $tournament_id; ?>" hx-target="#main">
|
||||
<i class="fas fa-calendar-star"></i>
|
||||
<?= escape($tournament['name']); ?>
|
||||
</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="/runs/overview/<?= $run_id; ?>" hx-push-url="/runs/overview/<?= $run_id; ?>" hx-get="/runs/overview/<?= $run_id; ?>" hx-target="#main">
|
||||
<i class="far fa-running"></i>
|
||||
<?= escape($run['name']); ?>
|
||||
</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">
|
||||
<i class="fas fa-edit"></i>
|
||||
<?= $result_id?'Bearbeiten':'Eintragen'; ?>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<h2>Ergebnis
|
||||
<?= $result_id?'Bearbeiten':'Eintragen'; ?>
|
||||
</h2>
|
||||
<form id="resulteditform" hx-post="/runs/validateresults" hx-encoding='multipart/form-data' hx-target="#response" hx-disabled-elt="#submit">
|
||||
<div class="dropzone-previews"></div>
|
||||
<input type="hidden" name="result_id" value="<?= $result_id; ?>">
|
||||
<input type="hidden" name="run_id" value="<?= $run_id; ?>">
|
||||
<div>
|
||||
<label for="dog">Hund</label>
|
||||
<select id="dog" name="dog" class="form-control">
|
||||
<option value="false" <?=!$result['dog']?'selected':''; ?>>-- Bitte auswählen --</option>
|
||||
<?php foreach($_SESSION['user']->data['dogs'] as $dogid) : ?>
|
||||
<?php
|
||||
$dog = new Dog();
|
||||
$dog->load($dogid);
|
||||
$dd = $dog->data;
|
||||
?>
|
||||
<option value="<?= $dogid ?>" <?=$result['dog']==$dogid ?'selected':''; ?>>
|
||||
<?= escape($dd['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-check form-switch">
|
||||
<label class="form-check-label" for="disqualified">Disqualifiziert</label>
|
||||
<input class="form-control form-check-input" type="checkbox" id="disqualified" name="disqualified" value="1" <?=$result['disqualified']=='1' ?'checked':''; ?>>
|
||||
</div>
|
||||
<div>
|
||||
<label for="refusals">Verweigerungen</label>
|
||||
<input type="number" value="<?= $result['refusals']; ?>" id="refusals" name="refusals" class="form-control">
|
||||
</div>
|
||||
<div>
|
||||
<label for="faults">Fehler</label>
|
||||
<input type="number" value="<?= $result['faults']; ?>" id="faults" name="faults" class="form-control">
|
||||
</div>
|
||||
<div>
|
||||
<label for="time_faults">Zeitfehler</label>
|
||||
<input type="number" step="0.01" value="<?= $result['time_faults']; ?>" id="time_faults" name="time_faults" class="form-control">
|
||||
</div>
|
||||
<div>
|
||||
<label for="time">Zeit</label>
|
||||
<input type="number" step="0.01" value="<?= $result['time']; ?>" id="time" name="time" class="form-control">
|
||||
</div>
|
||||
<div>
|
||||
<label for="penalties">Gesamtfehler</label>
|
||||
<input type="number" step="0.01" value="<?= $result['penalties']; ?>" id="penalties" name="penalties" class="form-control">
|
||||
</div>
|
||||
<div>
|
||||
<label for="time_speed">m/Sek</label>
|
||||
<input type="number" step="0.01" value="<?= $result['time_speed']; ?>" id="time_speed" name="time_speed" class="form-control">
|
||||
</div>
|
||||
<div>
|
||||
<label for="bewertung">Bewertung</label>
|
||||
<select id="bewertung" name="bewertung" class="form-control">
|
||||
<option value="V" <?=$result['bewertung']=='V' ?'selected':''; ?>>V</option>
|
||||
<option value="SG" <?=$result['bewertung']=='SG' ?'selected':''; ?>>SG</option>
|
||||
<option value="G" <?=$result['bewertung']=='G' ?'selected':''; ?>>G</option>
|
||||
<option Galue="B" <?=$result['bewertung']=='B' ?'selected':''; ?>>B</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="points">Punkte</label>
|
||||
<input type="number" value="<?= $result['points']; ?>" id="points" name="points" class="form-control">
|
||||
</div>
|
||||
<div>
|
||||
<label for="rank">Platz</label>
|
||||
<input type="number" value="<?= $result['rank']; ?>" id="rank" name="rank" class="form-control">
|
||||
</div>
|
||||
<div>
|
||||
<label for="uploads">Uploads</label>
|
||||
<input type="file" accept="image/png, image/jpeg, image/gif" id="uploads" class="form-control" name="photos[]" multiple>
|
||||
</div>
|
||||
<div>
|
||||
<label for="video-url">Video Url</label>
|
||||
<input type="text" value="<?= $result['video-url']; ?>" class="form-control" id="video-url" aria-describedby="basic-addon3" placeholder="https://www.youtube.com/...">
|
||||
</div>
|
||||
<div>
|
||||
<label for="memo">Memo</label>
|
||||
<textarea value="<?= $result['memo']; ?>" id="memo" name="memo" class="form-control" placeholder="Deine Gedankengänge"></textarea>
|
||||
</div>
|
||||
<div class="form-check form-switch">
|
||||
<label class="form-check-label" for="public">Daten im Lauf veröffentlichen</label>
|
||||
<input class="form-control form-check-input" type="checkbox" id="public" name="public" value="1" <?=$result['public']!='0' ?'checked':''; ?>>
|
||||
</div>
|
||||
<button type="submit" id="submit" name="submit" value="true" class="btn btn-primary">Speichern</button>
|
||||
<progress id='progress' value='0' max='100'></progress>
|
||||
<div id="response"></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
htmx.on('#resulteditform', 'htmx:xhr:progress', function(evt) {
|
||||
htmx.find('#progress').setAttribute('value', evt.detail.loaded/evt.detail.total * 100)
|
||||
});
|
||||
</script>
|
||||
48
web/pages/runs/edit_run.html
Normal file
48
web/pages/runs/edit_run.html
Normal file
@@ -0,0 +1,48 @@
|
||||
<!-- das hier sollte bei einem Turnier mehrfach hinzugefügt werden können. Auswahl aus Agility & Jumping -->
|
||||
<div>
|
||||
<h1>Lauf <?= $run_id?'Bearbeiten':'Hinzufügen'; ?></h1>
|
||||
|
||||
<form id="tournamenteditform" hx-post="/runs/validate" hx-encoding='multipart/form-data' hx-target="#response">
|
||||
<input type="hidden" name="tournament_id" value="<?= $tournament_id; ?>">
|
||||
<input type="hidden" name="run_id" value="<?= $run_id; ?>">
|
||||
<h2>Parcourdetails</h2>
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="name">Bezeichnung</label>
|
||||
<input type="text" value="<?= $run['name']; ?>" id="name" name="name" class="form-control" placeholder="zb: Oldies Jumping" required>
|
||||
</div>
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="category">Parcourtyp</label>
|
||||
<select id="category" name="category" class="form-control">
|
||||
<option value="Agility" <?= $run['category']=='Agility'?'selected':''; ?>>Agility</option>
|
||||
<option value="Jumping" <?= $run['category']=='Jumping'?'selected':''; ?>>Jumping</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="length">Parcourlänge (in m)</label>
|
||||
<input type="number" min="1" max="1000" value="<?= $run['length']; ?>" id="length" name="length" class="form-control" placeholder="180">
|
||||
</div>
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="time_standard">Normzeit</label>
|
||||
<input type="number" value="<?= $run['time_standard']?:0; ?>" id="time_standard" name="time_standard" class="form-control" placeholder="50.000">
|
||||
</div>
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="time_max">Maxzeit</label>
|
||||
<input type="number" value="<?= $run['time_max']?:0; ?>" id="time_max" name="time_max" class="form-control" placeholder="100.000">
|
||||
</div>
|
||||
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="referee">Richter</label>
|
||||
<input type="text" value="<?= $run['referee']; ?>" id="referee" name="referee" class="form-control" placeholder="Franz Ferdinand" class="form-control">
|
||||
</div>
|
||||
<button type="submit" name="submit" value="true" class="btn btn-primary">Speichern</button>
|
||||
<button type="submit" name="submit" value="forward" class="btn btn-primary">Speichern und Ergebnisse eintragen</button>
|
||||
</form>
|
||||
<progress id='progress' value='0' max='100'></progress>
|
||||
<div id="response"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
htmx.on('#dogeditform', 'htmx:xhr:progress', function(evt) {
|
||||
htmx.find('#progress').setAttribute('value', evt.detail.loaded/evt.detail.total * 100)
|
||||
});
|
||||
</script>
|
||||
154
web/pages/runs/run.html
Normal file
154
web/pages/runs/run.html
Normal file
@@ -0,0 +1,154 @@
|
||||
<div class="container">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item">
|
||||
<i class="fas fa-calendar-star"></i>
|
||||
<a href="/tournaments/event/<?= $tournament_id; ?>" hx-push-url="/tournaments/event/<?= $tournament_id; ?>" hx-get="/tournaments/event/<?= $tournament_id; ?>" hx-target="#main">
|
||||
<?= escape($tournament['name']); ?>
|
||||
</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">
|
||||
<i class="far fa-running"></i>
|
||||
<?= escape($run['name']); ?>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<div class="card">
|
||||
<?php if($run['photo']): ?><img src="<?= $run['photo'] ?>/300x170/fixedsize" class="card-img-top" alt="<?= escape($run['name']); ?>'s profile Picture">
|
||||
<?php endif; ?>
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">
|
||||
<?= escape($run['name']); ?>
|
||||
</h5>
|
||||
<p class="card-text">
|
||||
<ul>
|
||||
|
||||
<li>Gehört zu <a href="/tournaments/event/<?= $tournament_id; ?>" hx-push-url="/tournaments/event/<?= $tournament_id; ?>" hx-get="/tournaments/event/<?= $tournament_id; ?>" hx-target="#main">
|
||||
<?= escape($tournament['name']); ?>
|
||||
</a></li>
|
||||
<?php if($run['category']): ?>
|
||||
<li>Typ:
|
||||
<?= escape($run['category']); ?>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php if($run['length']): ?>
|
||||
<li>Länge:
|
||||
<?= escape($run['length']); ?>m
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php if($run['time_standard']): ?>
|
||||
<li>Normzeit:
|
||||
<?= escape($run['time_standard']); ?>s
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php if($run['time_max']): ?>
|
||||
<li>Maxzeit:
|
||||
<?= escape($run['time_max']); ?>s
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php if($run['referee']): ?>
|
||||
<li>Richter:
|
||||
<?= escape($run['referee']); ?>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
<?php if($admin===true): ?>
|
||||
<button type="button" class="btn btn-secondary" hx-get="/runs/edit/<?= $run_id; ?>" hx-target="#main">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="col" id="sitemain">
|
||||
<div class="card p-2 mb-2">
|
||||
<div class="row">
|
||||
<h3>Fotos</h3>
|
||||
<?php foreach($results as $result) : ?>
|
||||
<?php if($result['photos']): ?>
|
||||
<?php foreach($result['photos'] as $photo) : ?>
|
||||
|
||||
<div class="col-md-4 mt-3 col-lg-3">
|
||||
<a href="<?= $photo; ?>">
|
||||
<img src="<?= $photo; ?>/100x100/forcesize" alt="<?= escape( (new Dog())->getField('name',$result['dog']) ) ?>'s Lauf" class="figure-img rounded">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card p-2">
|
||||
<h4>Ergebnisse</h4>
|
||||
<p class="card-text">
|
||||
<button hx-get="/runs/addresults/<?= $run_id; ?>" hx-push-url="/runs/addresults/<?= $run_id; ?>" hx-target="#main" class="btn btn-primary"><i class="fas fa-plus-circle"></i> Ergebnis Eintragen</button>
|
||||
|
||||
</p>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Platz</th>
|
||||
<th>Disqualifiziert</th>
|
||||
<th>Verweigerungen</th>
|
||||
<th>Fehler</th>
|
||||
<th>Zeitfehler</th>
|
||||
<th>Zeit</th>
|
||||
<th>Gesamtfehler</th>
|
||||
<th>m/Sek</th>
|
||||
<th>Bewertung</th>
|
||||
<th>Teilnehmer</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($results as $result) : ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?= escape($result['ranking']); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?= $result['disqualified']?'Ja':'Nein'; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?= escape($result['refusals']); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?= escape($result['errors']); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?= escape($result['timefaults']); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?= escape($result['runtime']); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?= escape($result['penalties']); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?= escape($result['speed']); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?= escape($result['rating']); ?>
|
||||
</td>
|
||||
<td><a href="/dogs/overview/<?= $result['dog'] ?>">
|
||||
<?= escape( (new Dog())->getField('name',$result['dog']) ); ?>
|
||||
</a></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
34
web/pages/settings/controller.php
Normal file
34
web/pages/settings/controller.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
class Settings extends Page {
|
||||
|
||||
function index()
|
||||
{
|
||||
$this->set('userdata', $_SESSION['user']->data);
|
||||
$this->set('template', "settings.html");
|
||||
}
|
||||
|
||||
function edit()
|
||||
{
|
||||
$theme = $_REQUEST['theme'];
|
||||
switch($theme)
|
||||
{
|
||||
case 'light':
|
||||
case 'dark':
|
||||
$_SESSION['user']->data['theme'] = $theme;
|
||||
$_SESSION['user']->save();
|
||||
$this->redirect('/settings');
|
||||
break;
|
||||
default:
|
||||
return partial('error.html', ['errorMessage' => 'Dieses Theme existiert nicht']);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function maySeeThisPage(){
|
||||
if($_SESSION['user'])
|
||||
return true;
|
||||
else return false;
|
||||
}
|
||||
}
|
||||
13
web/pages/settings/settings.html
Normal file
13
web/pages/settings/settings.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<form hx-post="/settings/edit" hx-target="#response">
|
||||
<div>
|
||||
<label for="theme">Farbschema</label>
|
||||
<select name="theme">
|
||||
<option value="light" <?= $_SESSION['user']->data['theme']=='light'?'selected':''; ?>>Hell</option>
|
||||
<option value="dark" <?= $_SESSION['user']->data['theme']=='dark'?'selected':''; ?>>Dunkel</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="response"></div>
|
||||
|
||||
<button type="submit" name="submit" value="true" class="btn btn-primary">Speichern</button>
|
||||
</form>
|
||||
65
web/pages/smart/controller.php
Normal file
65
web/pages/smart/controller.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
|
||||
class Smart extends Page {
|
||||
function setMenu()
|
||||
{
|
||||
$this->menu_text = 'Smart';
|
||||
$this->menu_image = 'fas fa-robot';
|
||||
$this->menu_priority = 1;
|
||||
}
|
||||
|
||||
function index()
|
||||
{
|
||||
$this->set('user', $_SESSION['user']->data);
|
||||
$this->set('template', "smart.html.php");
|
||||
}
|
||||
|
||||
function search()
|
||||
{
|
||||
$db = new SQLite3(ROOT.DS.'../crawler/data.db', SQLITE3_OPEN_READONLY);
|
||||
$q = $_REQUEST['q'];
|
||||
if(!$q || strlen($q) < 3 || strpos($q, ' ') === false)
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Error: Bitte Nachname und Vorname eingeben.']);
|
||||
|
||||
$stmt = $db->prepare("SELECT DISTINCT(hund) FROM results WHERE teilnehmer LIKE :q");
|
||||
$stmt->bindValue(':q', $q, SQLITE3_TEXT);
|
||||
|
||||
$res = $stmt->execute();
|
||||
$results = [];
|
||||
$dogs = [];
|
||||
|
||||
while($row = $res->fetchArray())
|
||||
{
|
||||
$dogs[] = $row['hund'];
|
||||
}
|
||||
|
||||
if(count($dogs) == 0)
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Error: Keine Ergebnisse gefunden. Bitte Nachname und Vorname prüfen.']);
|
||||
|
||||
foreach($dogs as $dog)
|
||||
{
|
||||
$res = $db->query("SELECT * FROM results WHERE teilnehmer LIKE '$q' AND hund LIKE '$dog'");
|
||||
while($row = $res->fetchArray())
|
||||
{
|
||||
$row['date'] = $db->querySingle("SELECT date FROM events WHERE id = ".$row['event']);
|
||||
$row['event'] = $db->querySingle("SELECT name FROM events WHERE id = ".$row['event']);
|
||||
$row['unixtimestamp'] = strtotime($row['date']);
|
||||
$row['run'] = $db->querySingle("SELECT name FROM runs WHERE id = ".$row['run']);
|
||||
$row['ago'] = printRelativeTime(time(),$row['unixtimestamp']);
|
||||
$results[$dog][] = $row;
|
||||
}
|
||||
|
||||
//sort results by date
|
||||
usort($results[$dog], function($a, $b) {
|
||||
return $a['unixtimestamp'] <=> $b['unixtimestamp'];
|
||||
});
|
||||
}
|
||||
|
||||
$this->set('results_dogs', $results);
|
||||
$this->set('dogs', $dogs);
|
||||
$this->set('template', 'search.html.php');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
165
web/pages/smart/search.html.php
Normal file
165
web/pages/smart/search.html.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<h2>Hunde:</h2>
|
||||
<ul>
|
||||
<?php foreach ($dogs as $dog) : ?>
|
||||
<li><a href="#<?= $dog ?>"><?= $dog ?></a></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
||||
|
||||
<?php foreach ($dogs as $dog) :
|
||||
|
||||
$dogid=preg_replace("/[^A-Za-z0-9]/", '', $dog);
|
||||
$results = $results_dogs[$dog];
|
||||
$sdata = [];
|
||||
?>
|
||||
|
||||
<h1 id="<?= $dogid; ?>"><?= $dog; ?></h1>
|
||||
|
||||
<button onClick="getElementById('table_<?= $dogid ?>').style.display='table'">Tabelle anzeigen</button>
|
||||
<table id="table_<?= $dogid ?>" class="table" style="display:none">
|
||||
<tr>
|
||||
<th>event</th>
|
||||
<th>Wann wars</th>
|
||||
<th>run</th>
|
||||
<th>rang</th>
|
||||
<th>stnr</th>
|
||||
<th>teilnehmer</th>
|
||||
<th>hund</th>
|
||||
<th>verein</th>
|
||||
<th>f</th>
|
||||
<th>vw</th>
|
||||
<th>zf</th>
|
||||
<th>zeit</th>
|
||||
<th>gf</th>
|
||||
<th>msek</th>
|
||||
<th>bew</th>
|
||||
<th>punkte</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
<?php foreach ($results as $res) :
|
||||
// graph data preparation
|
||||
|
||||
if ($res['bew'] != 'DIS' && $res['punkte'] != 'DIS') {
|
||||
$sdata['dates'][] = date("d.m.Y", strtotime($res['date']));
|
||||
$sdata['speed'][] = $res['msek'] ?: 0;
|
||||
$sdata['errors'][] = $res['f'] ?: 0;
|
||||
$sdata['refusals'][] = $res['vw'] ?: 0;
|
||||
$sdata['time'][] = $res['zeit'] ?: 0;
|
||||
$sdata['points'][] = $res['punkte'];
|
||||
$sdata['ranking'][] = $res['rang'];
|
||||
|
||||
$a = array_filter($sdata['speed']);
|
||||
if(count($a)>0)
|
||||
$averagespeed = round(array_sum($a)/count($a),2);
|
||||
|
||||
$a = $sdata['errors'];
|
||||
if(count($a)>0)
|
||||
$averageerrors = round(array_sum($a)/count($a),2);
|
||||
|
||||
$a = $sdata['refusals'];
|
||||
if(count($a)>0)
|
||||
$averagerefusals = round(array_sum($a)/count($a),2);
|
||||
|
||||
$a = array_filter($sdata['ranking']);
|
||||
if(count($a)>0)
|
||||
$averageranking = round(array_sum($a)/count($a),2);
|
||||
}
|
||||
|
||||
?>
|
||||
<tr>
|
||||
<td><?= $res['event'] ?></td>
|
||||
<td><?= date("d.m.Y", strtotime($res['date'])) ?></td>
|
||||
<td><?= $res['run'] ?></td>
|
||||
<td><?= $res['rang'] ?></td>
|
||||
<td><?= $res['stnr'] ?></td>
|
||||
<td><?= $res['teilnehmer'] ?></td>
|
||||
<td><?= $res['hund'] ?></td>
|
||||
<td><?= $res['verein'] ?></td>
|
||||
<td><?= $res['f'] ?></td>
|
||||
<td><?= $res['vw'] ?></td>
|
||||
<td><?= $res['zf'] ?></td>
|
||||
<td><?= $res['zeit'] ?></td>
|
||||
<td><?= $res['gf'] ?></td>
|
||||
<td><?= $res['msek'] ?></td>
|
||||
<td><?= $res['bew'] ?></td>
|
||||
<td><?= $res['punkte'] ?></td>
|
||||
<td>
|
||||
<form id="tournament_import" hx-post="/tournaments/add" hx-encoding="multipart/form-data" hx-target="#main">
|
||||
<input type="hidden" name="tournament_name" value="<?= $res['event'] ?>">
|
||||
<input type="hidden" name="tournament_date" value="<?= date("d.m.Y", strtotime($res['date'])) ?>">
|
||||
<input type="hidden" name="tournament_run" value="<?= $res['run'] ?>">
|
||||
<input type="hidden" name="tournament_ranking" value="<?= $res['rang'] ?>">
|
||||
<input type="hidden" name="tournament_number" value="<?= $res['stnr'] ?>">
|
||||
<input type="hidden" name="tournament_participant" value="<?= $res['teilnehmer'] ?>">
|
||||
<input type="hidden" name="tournament_dog" value="<?= $res['hund'] ?>">
|
||||
<input type="hidden" name="tournament_club" value="<?= $res['verein'] ?>">
|
||||
<input type="hidden" name="tournament_faults" value="<?= $res['f'] ?>">
|
||||
<input type="hidden" name="tournament_refusals" value="<?= $res['vw'] ?>">
|
||||
<input type="hidden" name="tournament_time" value="<?= $res['zeit'] ?>">
|
||||
<input type="hidden" name="tournament_speed" value="<?= $res['msek'] ?>">
|
||||
<input type="hidden" name="tournament_points" value="<?= $res['punkte'] ?>">
|
||||
<button type="submit">Importieren</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
|
||||
<h4>Statistik</h4>
|
||||
|
||||
<div class="card" style="width: 25rem;">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item"><i class="fas fa-rabbit-fast"></i> Durchschnittsgeschwinigkeit: <span class="badge bg-primary" style="float:right;"><?= $averagespeed ?> m/s</span></li>
|
||||
<li class="list-group-item"><i class="fas fa-exclamation-triangle"></i> Fehler pro Lauf: <span class="badge bg-primary" style="float:right;"><?= $averageerrors ?></span></li>
|
||||
<li class="list-group-item"><i class="fas fa-do-not-enter"></i> Verweigerungen pro Lauf: <span class="badge bg-primary" style="float:right;"><?= $averagerefusals ?></span></li>
|
||||
<li class="list-group-item"><i class="fas fa-trophy-alt"></i> Durchschnittliche Platzierung: <span class="badge bg-primary" style="float:right;"><?= $averageranking ?></span></li>
|
||||
</ul>
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
<div class="row">
|
||||
<?php if (count($results) > 0) : ?>
|
||||
<div class="col">
|
||||
<?= partial('graph.html.php', [
|
||||
'id' => 'graph1'.$dogid,
|
||||
'title' => 'Fehler und Verweigerungen',
|
||||
'xaxis' => $sdata['dates'],
|
||||
'seriesdata' => [
|
||||
['name' => 'Fehler', 'type' => 'line', 'stack' => 'Total', 'data' => $sdata['errors']],
|
||||
['name' => 'Verweigerungen', 'type' => 'line', 'stack' => 'Total', 'data' => $sdata['refusals']],
|
||||
],
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<?= partial('graph.html.php', [
|
||||
'id' => 'graph2'.$dogid,
|
||||
'title' => 'Geschwindigkeit',
|
||||
'xaxis' => $sdata['dates'],
|
||||
'seriesdata' => [
|
||||
['name' => 'Geschwindigkeit', 'type' => 'line', 'stack' => 'Total', 'data' => $sdata['speed']],
|
||||
],
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<?= partial('graph.html.php', [
|
||||
'id' => 'graph3'.$dogid,
|
||||
'title' => 'Platzierung',
|
||||
'xaxis' => $sdata['dates'],
|
||||
'seriesdata' => [
|
||||
['name' => 'Platzierung', 'type' => 'line', 'stack' => 'Total', 'data' => $sdata['ranking']],
|
||||
],
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<?php endforeach; ?>
|
||||
23
web/pages/smart/smart.html.php
Normal file
23
web/pages/smart/smart.html.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<h2>Dein Name wie der auf Teilnahmelisten zu finden ist</h2>
|
||||
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="basic-url" class="form-label">Dein Name wie der auf Teilnahmelisten zu finden ist (Nachname Vorname)</label>
|
||||
<div class="input-group">
|
||||
<input type="text" name="q"
|
||||
hx-post="/smart/search"
|
||||
hx-trigger="keyup changed delay:500ms"
|
||||
hx-target="#search-results"
|
||||
placeholder="Suchen..."
|
||||
hx-indicator="#indicator"
|
||||
class="form-control" id="basic-url"
|
||||
value="<?= escape($user['lastname'].' '.$user['firstname']); ?>"
|
||||
>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<i id="indicator" class="fad fa-spinner-third fa-spin htmx-indicator"></i>
|
||||
|
||||
<div id="search-results"></div>
|
||||
|
||||
296
web/pages/tournaments/controller.php
Normal file
296
web/pages/tournaments/controller.php
Normal file
@@ -0,0 +1,296 @@
|
||||
<?php
|
||||
|
||||
class Tournaments extends Page {
|
||||
|
||||
function setMenu()
|
||||
{
|
||||
$this->menu_text = 'Turniere';
|
||||
$this->menu_image = 'far fa-medal';
|
||||
$this->menu_priority = 1;
|
||||
}
|
||||
|
||||
function setSubmenu()
|
||||
{
|
||||
$this->addSubmenuItem('Übersicht','/tournaments','far fa-list-alt');
|
||||
$this->addSubmenuItem('Turnier anlegen','/tournaments/add','fas fa-calendar-plus');
|
||||
if($_SESSION['user']->data['tournaments'] && count($_SESSION['user']->data['tournaments']) > 0)
|
||||
{
|
||||
$this->addSubmenuItem('divider');
|
||||
$counter = 0;
|
||||
foreach($_SESSION['user']->data['tournaments'] as $tid)
|
||||
{
|
||||
$t = new Tournament();
|
||||
$t->load($tid);
|
||||
$this->addSubmenuItem($t->data['name'],'/tournaments/event/'.$tid,'fas fa-calendar-star');
|
||||
$counter++;
|
||||
if ($counter === 5) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function add()
|
||||
{
|
||||
|
||||
$t = new Tournament();
|
||||
$t->name = $_REQUEST['tournament_name'];
|
||||
$t->date = date("d.m.Y", strtotime($_REQUEST['tournament_date']));
|
||||
$t->duration = intval($_REQUEST['tournament_duration']);
|
||||
$t->referee = $_REQUEST['tournament_referee'];
|
||||
$t->text = $_REQUEST['tournament_text'];
|
||||
$t->url = $_REQUEST['tournament_url'];
|
||||
$t->logo = $_REQUEST['tournament_logo'];
|
||||
$t->run = $_REQUEST['tournament_run'];
|
||||
$t->run = $_REQUEST['tournament_run'];
|
||||
$t->ranking = $_REQUEST['tournament_ranking'];
|
||||
$t->number = $_REQUEST['tournament_number'];
|
||||
$t->participant = $_REQUEST['tournament_participant'];
|
||||
$t->dog = $_REQUEST['tournament_dog'];
|
||||
$t->club = $_REQUEST['tournament_club'];
|
||||
$t->faults = $_REQUEST['tournament_faults'];
|
||||
$t->refusals = $_REQUEST['tournament_refusals'];
|
||||
$t->time = $_REQUEST['tournament_time'];
|
||||
$t->points = $_REQUEST['tournament_points'];
|
||||
$t->speed = $_REQUEST['tournament_speed'];
|
||||
var_dump($t->data);
|
||||
$this->set('tournamentdata',$t->data);
|
||||
$this->set('template','edit_tournament.html');
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function index() {
|
||||
$events = $_SESSION['user']->data['tournaments'];
|
||||
$tournaments = [];
|
||||
|
||||
foreach($events as $key => $eventid)
|
||||
{
|
||||
//var_dump($dogid);
|
||||
$event = new Tournament();
|
||||
try{
|
||||
$event->load($eventid);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
error_log("Event $eventid not found. Deleting from user");
|
||||
unset($_SESSION['user']->data['tournament'][$key]);
|
||||
$_SESSION['user']->save();
|
||||
continue;
|
||||
}
|
||||
if($event->data)
|
||||
$tournaments[] = array_merge($event->data,['id'=>$eventid]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(count($_SESSION['user']->data['tournaments']) > 0)
|
||||
{
|
||||
$this->set('tournaments',$tournaments);
|
||||
$this->set('template', 'tournaments.html');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function manage()
|
||||
{
|
||||
$action = $this->params[0];
|
||||
$tid = $this->params[1];
|
||||
$t = new Tournament();
|
||||
if($t->exists($tid))
|
||||
$t->load($tid);
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Dieses Turnier existiert nicht']);
|
||||
|
||||
switch($action)
|
||||
{
|
||||
case 'join':
|
||||
if(in_array($tid, $_SESSION['user']->data['tournaments']))
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Du bist bereits für dieses Turnier angemeldet']);
|
||||
else
|
||||
{
|
||||
$t->joinUser($tid);
|
||||
return partial('success.html', ['successTitle' => 'Erfolgreich', 'successMessage' => 'Du wurdest erfolgreich für dieses Turnier angemeldet']);
|
||||
}
|
||||
case 'leave':
|
||||
if(!in_array($tid, $_SESSION['user']->data['tournaments']))
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Du bist für dieses Turnier nicht angemeldet']);
|
||||
else
|
||||
{
|
||||
$t->removeUser($tid);
|
||||
return partial('success.html', ['successTitle' => 'Erfolgreich', 'successMessage' => 'Du wurdest erfolgreich für dieses Turnier abgemeldet']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function leave()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
function event()
|
||||
{
|
||||
$tid = $this->params[0];
|
||||
$t = new Tournament();
|
||||
if($t->exists($tid))
|
||||
$t->load($tid);
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Dieses Turnier existiert nicht']);
|
||||
|
||||
$this->set('admin',$t->amIAdmin($tid));
|
||||
$this->set('joined',$t->isMyEvent($tid));
|
||||
$this->set('tournament_id',$tid);
|
||||
$this->set('admins',$t->getAdmins($tid));
|
||||
$this->set('members',$t->getMembers($tid));
|
||||
$this->set('tdata',$t->data);
|
||||
$this->set('template','event.html');
|
||||
}
|
||||
|
||||
function edit()
|
||||
{
|
||||
if($_REQUEST['submit'])
|
||||
{
|
||||
var_dump($_REQUEST);
|
||||
$id = $_REQUEST['tournament_id'];
|
||||
$name = $_REQUEST['tournament_name'];
|
||||
$date = $_REQUEST['tournament_date'];
|
||||
$tournament_referee = $_REQUEST['tournament_referee'];
|
||||
$tournament_duration = intval($_REQUEST['tournament_duration']);
|
||||
$tournament_url = $_REQUEST['tournament_url'];
|
||||
$tournament_text = $_REQUEST['tournament_text'];
|
||||
$newlogo = false;
|
||||
|
||||
if($_FILES['logo'])
|
||||
{
|
||||
$logo = $_FILES['logo'];
|
||||
$logo_name = $logo['name'];
|
||||
$logo_tmp_name = $logo['tmp_name'];
|
||||
$logo_size = $logo['size'];
|
||||
$logo_error = $logo['error'];
|
||||
$logo_type = $logo['type'];
|
||||
|
||||
$allowed = ['jpg','jpeg','png','gif'];
|
||||
$logo_ext = strtolower(end(explode('.', $logo_name)));
|
||||
$logo_name = $name.'.'.$logo_ext;
|
||||
$logo_path = 'uploads/'.$logo_name;
|
||||
|
||||
if(in_array($logo_ext, $allowed))
|
||||
{
|
||||
if($logo_error === 0)
|
||||
{
|
||||
if($logo_size < 10000000)
|
||||
{
|
||||
$answer = pictshareUploadImage($logo_tmp_name);
|
||||
if($answer['status']=='ok' && in_array($answer['filetype'],['jpeg','png','gif']))
|
||||
$newlogo = $answer['url'];
|
||||
}
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Die Datei ist zu groß. Bitte eine kleinere Datei hochladen']);
|
||||
}
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Beim Upload der Datei ist ein Fehler aufgetreten']);
|
||||
}
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Dieser Dateityp ist nicht erlaubt. Bitte nur jpg, jpeg oder png Dateien hochladen']);
|
||||
}
|
||||
|
||||
$error = false;
|
||||
if(!$name || !$date )
|
||||
$error = 'Bitte zumindest Name und Datum angeben';
|
||||
else if(!strtotime($date))
|
||||
$error = 'Das Datumm ist ungültig. Bitte die Eingabe prüfen';
|
||||
|
||||
if($error){
|
||||
$this->set('errorMessage', $error);
|
||||
$this->set('template', '/templates/partials/error.html');
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
$t = new Tournament();
|
||||
|
||||
|
||||
if($id)
|
||||
{
|
||||
if($t->exists($id))
|
||||
$t->load($id);
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Dieses Turnier existiert nicht']);
|
||||
if(!in_array($_SESSION['user']->id, $t->data['admins']))
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Du bist nicht berechtigt, dieses Turnier zu bearbeiten']);
|
||||
else
|
||||
$t->load($id);
|
||||
}
|
||||
|
||||
$t->name = $name;
|
||||
$t->date = $date;
|
||||
$t->duration = $tournament_duration;
|
||||
$t->referee = $tournament_referee;
|
||||
$t->text = $tournament_text;
|
||||
$t->url = $tournament_url;
|
||||
if(!$t->data['admins'] || !is_array($t->data['admins'] || count($t->data['admins']) == 0))
|
||||
$t->data['admins'] = [];
|
||||
if(!in_array($_SESSION['user']->id, $t->data['admins']))
|
||||
$t->data['admins'][] = $_SESSION['user']->id;
|
||||
if($newlogo)
|
||||
$t->logo = $newlogo;
|
||||
|
||||
try
|
||||
{
|
||||
$tid = $t->save();
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$this->set('template', '/templates/partials/error.html');
|
||||
$this->set('errorTitle', 'Error');
|
||||
$this->set('errorMessage', $e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
//var_dump($_SESSION['user']->data['tournaments']);
|
||||
|
||||
if(!is_array($_SESSION['user']->data['tournaments']) || !in_array($tid, $_SESSION['user']->data['tournaments'])) // new t!
|
||||
{
|
||||
$_SESSION['user']->data['tournaments'][] = $tid;
|
||||
try
|
||||
{
|
||||
$_SESSION['user']->save();
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$this->set('template', '/templates/partials/error.html');
|
||||
$this->set('errorTitle', 'Error');
|
||||
$this->set('errorMessage', $e->getMessage());
|
||||
return;
|
||||
}
|
||||
$this->redirect('/tournaments/event/'.$tid);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->set('template', '/templates/partials/success.html');
|
||||
$this->set('successMessage', "Daten erfolgreich gespeichert");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$id = $this->params[0];
|
||||
$t = new Tournament();
|
||||
$t->load($id);
|
||||
$this->set('tournamentdata',$t->data);
|
||||
$this->set('tournamentid',$t->id);
|
||||
$this->set('template', 'edit_tournament.html');
|
||||
}
|
||||
}
|
||||
|
||||
function maySeeThisPage() {
|
||||
if($_SESSION['user']) //wenn eingeloggt, kein problem
|
||||
return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
}
|
||||
38
web/pages/tournaments/edit_tournament.html
Normal file
38
web/pages/tournaments/edit_tournament.html
Normal file
@@ -0,0 +1,38 @@
|
||||
<div>
|
||||
<h1>Turnier <?= $tournamentid?'Bearbeiten':'Hinzufügen'; ?></h1>
|
||||
|
||||
<form id="tournamenteditform" hx-post="/tournaments/edit" hx-encoding='multipart/form-data' hx-target="#response">
|
||||
<input type="hidden" name="tournament_id" value="<?= $tournamentid; ?>">
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="tournament_name">Veranstaltungsname</label>
|
||||
<input type="text" value="<?= $tournamentdata['name']; ?>" id="tournament_name" name="tournament_name" placeholder="Event" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="tournament_date">Datum</label>
|
||||
<input type="date" value="<?= $tournamentdata['date']; ?>" id="date" name="tournament_date" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="tournament_duration">Dauer der Veranstaltung in Tagen</label>
|
||||
<input type="number" min="1" max="7" value="<?= $tournamentdata['duration']; ?>" id="tournament_duration" name="tournament_duration" value="1" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="tournament_url">Weblink</label>
|
||||
<input type="text" value="<?= $tournamentdata['url']; ?>" id="tournament_url" name="tournament_url" placeholder="https://www.dognow.at/..." class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="logo">Logo des Events</label>
|
||||
<input type="file" accept="image/png, image/jpeg, image/gif" id="logo" name="logo" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="tournament_text">Beschreibungstext</label>
|
||||
<textarea id="tournament_text" name="tournament_text" class="form-control"><?= $tournamentdata['text']; ?></textarea>
|
||||
</div>
|
||||
<button type="submit" name="submit" value="true" class="btn btn-primary">Weiter</button> <!-- Submit Button führt auf eine neue Seite wo man die Laufinfo eingibt -->
|
||||
</form>
|
||||
<div id="response"></div>
|
||||
</div>
|
||||
111
web/pages/tournaments/event.html
Normal file
111
web/pages/tournaments/event.html
Normal file
@@ -0,0 +1,111 @@
|
||||
<!-- FILEPATH: /home/chris/git/tournamentstats/web/pages/tournaments/dog.html -->
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<div class="card">
|
||||
<img src="<?= $tdata['logo'] ?>/300x170/fixedsize" class="card-img-top" alt="<?= escape($tdata['name']); ?>'s profile Picture">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><?= escape($tdata['name']); ?></h5>
|
||||
<p class="card-text">
|
||||
<ul>
|
||||
<li>Datum: <?= escape($tdata['date']) ?></li>
|
||||
|
||||
<?php if($tdata['duration']): ?><li>Dauer: <?= escape($tdata['duration']); ?> Tag/e</li> <?php endif; ?>
|
||||
<?php if($tdata['referee']): ?><li>Richter: <?= escape($tdata['referee']); ?></li> <?php endif; ?>
|
||||
<?php if($tdata['size']): ?><li>Größe: <?= escape($tdata['size']); ?> cm</li> <?php endif; ?>
|
||||
<?php if($tdata['url']): ?><li>Webseite: <a href="<?= $tdata['url']; ?>"><?= escape($tdata['url']); ?></a></li> <?php endif; ?>
|
||||
</ul>
|
||||
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
<?php if($admin===true): ?>
|
||||
<button type="button" class="btn btn-secondary" hx-get="/tournaments/edit/<?= $tournament_id; ?>" hx-target="#main">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if($joined===false): ?>
|
||||
<button type="button" class="btn btn-secondary" hx-get="/tournaments/manage/join/<?= $tournament_id; ?>" hx-swap="outerHTML">
|
||||
<i class="fas fa-plus-circle"></i> Diesem Event beitreten
|
||||
</button>
|
||||
<?php elseif($admin===false): ?>
|
||||
<button type="button" class="btn btn-danger" hx-get="/tournaments/manage/leave/<?= $tournament_id; ?>" hx-swap="outerHTML" hx-confirm="Möchtest du dieses Event wirklich verlassen?">
|
||||
<i class="fas fa-minus-circle"></i> Event verlassen
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if(($admins && count($admins)>1) || ($members && count($members)>0)): ?>
|
||||
<div class="card p-2">
|
||||
<?php if($admins && count($admins)>0): ?> <h6>Admins</h6> <?php endif; ?>
|
||||
<?php foreach($admins as $adm) : ?>
|
||||
<img src="https://pictshare.net/identicon/<?= $adm['email']?>" height="50" width="50" class="rounded-circle" alt="<?= escape($adm['name']); ?>" title="<?= escape($adm['firstname'].' '.$adm['lastname']); ?>">
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?php if($members && count($members)>0): ?> <hr/> <h6>Mitglieder</h6> <?php endif; ?>
|
||||
<?php foreach($members as $member) : ?>
|
||||
<img src="https://pictshare.net/identicon/<?= $member['email']?>" height="50" width="50" class="rounded-circle" alt="<?= escape($member['name']); ?>" title="<?= escape($member['firstname'].' '.$member['lastname']); ?>">
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="col-8" id="sitemain">
|
||||
<?php if($tdata['text']): ?>
|
||||
<div class="card p-2 mb-4">
|
||||
<h4>Beschreibungstext</h4>
|
||||
<p class="card-text">
|
||||
<pre><?= escape($tdata['text']); ?></pre>
|
||||
</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card p-2">
|
||||
<h4>Läufe</h4>
|
||||
<p class="card-text">
|
||||
<?php if($admin===true): ?>
|
||||
<button hx-get="/runs/add/<?= $tournament_id; ?>" hx-push-url="/runs/add/<?= $tournament_id; ?>" hx-target="#main" class="btn btn-primary"><i class="fas fa-plus-circle"></i> Lauf hinzufügen</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Bezeichnung</th>
|
||||
<th>Lauf</th>
|
||||
<th>Parcourlänge</th>
|
||||
<th>Normzeit</th>
|
||||
<th>Maxzeit</th>
|
||||
<th>Richter</th>
|
||||
<th>Hund</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($tdata['runs'] as $rid) : ?>
|
||||
<?php
|
||||
$run = new Run();
|
||||
$run->load($rid);
|
||||
?>
|
||||
<tr>
|
||||
<td><a href="/runs/overview/<?= $rid; ?>" hx-get="/runs/overview/<?= $rid; ?>" hx-push-url="/runs/overview/<?= $rid; ?>" hx-target="#main"><?= escape($run->data['name']); ?></a></td>
|
||||
<td><?= escape($run->data['category']); ?></td>
|
||||
<td><?= escape($run->data['length']); ?>m</td>
|
||||
<td><?= escape($run->data['time_standard']); ?>s</td>
|
||||
<td><?= escape($run->data['time_max']); ?>s</td>
|
||||
<td><?= escape($run->data['referee']); ?></td>
|
||||
<td><?= escape($run->data['dog']); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
21
web/pages/tournaments/tournaments.html
Normal file
21
web/pages/tournaments/tournaments.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<!-- FILEPATH: /home/chris/git/dogstats/web/pages/dogs/dog.html -->
|
||||
<h1>Turnier Veranstaltungen</h1>
|
||||
<p>Hier kannst du alle Veranstaltungen einsehen.</p>
|
||||
<div class="tournaments-list row row-cols-sm-2">
|
||||
<?php foreach ($tournaments as $tournament) : ?>
|
||||
<div class="p-2">
|
||||
<div class="d-flex border">
|
||||
<img src="<?= $tournament['photo']?:'https://pictshare.net/prrnrk.jpg' ?>/130x100/forcesize" class="" alt="<?= escape($tournament['name']); ?>'s event Picture">
|
||||
<div class="m-3">
|
||||
<h3 class="h5"><a href="/tournaments/event/<?= $tournament['id'] ?>" class="text-body link-underline link-underline-opacity-0"><?= escape($tournament['name']); ?></a></h3>
|
||||
<p><?= date("d.m.y",strtotime($tournament['date'])); ?></p>
|
||||
</div>
|
||||
<div class="m-3 ms-auto">
|
||||
<button hx-get="/tournament/edit/<?= $tournament['id'] ?>" hx-push-url="/tournament/edit/<?= $tournament['id'] ?>" hx-target="#main" class="btn btn-primary"><i class="fas fa-edit"></i></button>
|
||||
<button hx-get="/tournament/delete/<?= $tournament['id'] ?>" hx-target="#main" hx-confirm="Bist du sicher, dass du <?= escape($tournament['name']); ?> löschen willst" class="btn btn-danger"><i class="fas fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
269
web/pages/trainings/controller.php
Normal file
269
web/pages/trainings/controller.php
Normal file
@@ -0,0 +1,269 @@
|
||||
<?php
|
||||
|
||||
class Trainings extends Page {
|
||||
|
||||
function setMenu()
|
||||
{
|
||||
$this->menu_text = 'Trainings';
|
||||
$this->menu_image = 'fas fa-running';
|
||||
$this->menu_priority = 1;
|
||||
}
|
||||
|
||||
function setSubmenu()
|
||||
{
|
||||
$this->addSubmenuItem('Übersicht','/trainings','far fa-list-alt');
|
||||
$this->addSubmenuItem('Training hinzufügen','/trainings/add','fas fa-calendar-plus');
|
||||
if($_SESSION['user']->data['trainings'] && count($_SESSION['user']->data['trainings']) > 0)
|
||||
{
|
||||
$this->addSubmenuItem('divider');
|
||||
$counter = 0;
|
||||
foreach($_SESSION['user']->data['trainings'] as $tid)
|
||||
{
|
||||
$t = new Training();
|
||||
$t->load($tid);
|
||||
$this->addSubmenuItem($t->data['name'],'/trainings/event/'.$tid,'fas fa-calendar-star');
|
||||
$counter++;
|
||||
if ($counter === 5) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function add()
|
||||
{
|
||||
$this->set('template','edit_training.html');
|
||||
}
|
||||
|
||||
function index() {
|
||||
$events = $_SESSION['user']->data['trainings'];
|
||||
$trainings = [];
|
||||
|
||||
foreach($events as $key => $eventid)
|
||||
{
|
||||
//var_dump($dogid);
|
||||
$event = new Training();
|
||||
try{
|
||||
$event->load($eventid);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
error_log("Event $eventid not found. Deleting from user");
|
||||
unset($_SESSION['user']->data['training'][$key]);
|
||||
$_SESSION['user']->save();
|
||||
continue;
|
||||
}
|
||||
if($event->data)
|
||||
$trainings[] = array_merge($event->data,['id'=>$eventid]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(count($_SESSION['user']->data['trainings']) > 0)
|
||||
{
|
||||
$this->set('trainings',$trainings);
|
||||
$this->set('template', 'trainings.html');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function manage()
|
||||
{
|
||||
$action = $this->params[0];
|
||||
$tid = $this->params[1];
|
||||
$t = new Training();
|
||||
if($t->exists($tid))
|
||||
$t->load($tid);
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Dieses Turnier existiert nicht']);
|
||||
|
||||
switch($action)
|
||||
{
|
||||
case 'join':
|
||||
if(in_array($tid, $_SESSION['user']->data['trainings']))
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Du bist bereits für dieses Turnier angemeldet']);
|
||||
else
|
||||
{
|
||||
$t->joinUser($tid);
|
||||
return partial('success.html', ['successTitle' => 'Erfolgreich', 'successMessage' => 'Du wurdest erfolgreich für dieses Turnier angemeldet']);
|
||||
}
|
||||
case 'leave':
|
||||
if(!in_array($tid, $_SESSION['user']->data['trainings']))
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Du bist für dieses Turnier nicht angemeldet']);
|
||||
else
|
||||
{
|
||||
$t->removeUser($tid);
|
||||
return partial('success.html', ['successTitle' => 'Erfolgreich', 'successMessage' => 'Du wurdest erfolgreich für dieses Turnier abgemeldet']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function leave()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
function event()
|
||||
{
|
||||
$tid = $this->params[0];
|
||||
$t = new Training();
|
||||
if($t->exists($tid))
|
||||
$t->load($tid);
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Dieses Turnier existiert nicht']);
|
||||
|
||||
$this->set('admin',$t->amIAdmin($tid));
|
||||
$this->set('joined',$t->isMyEvent($tid));
|
||||
$this->set('training_id',$tid);
|
||||
$this->set('admins',$t->getAdmins($tid));
|
||||
$this->set('members',$t->getMembers($tid));
|
||||
$this->set('tdata',$t->data);
|
||||
$this->set('template','event.html');
|
||||
}
|
||||
|
||||
function edit()
|
||||
{
|
||||
if($_REQUEST['submit'])
|
||||
{
|
||||
$id = $_REQUEST['training_id'];
|
||||
$name = $_REQUEST['training_name'];
|
||||
$date = $_REQUEST['training_date'];
|
||||
$training_referee = $_REQUEST['training_referee'];
|
||||
$training_duration = intval($_REQUEST['training_duration']);
|
||||
$training_url = $_REQUEST['training_url'];
|
||||
$training_text = $_REQUEST['training_text'];
|
||||
$newlogo = false;
|
||||
|
||||
if($_FILES['logo'])
|
||||
{
|
||||
$logo = $_FILES['logo'];
|
||||
$logo_name = $logo['name'];
|
||||
$logo_tmp_name = $logo['tmp_name'];
|
||||
$logo_size = $logo['size'];
|
||||
$logo_error = $logo['error'];
|
||||
$logo_type = $logo['type'];
|
||||
|
||||
$allowed = ['jpg','jpeg','png','gif'];
|
||||
$logo_ext = strtolower(end(explode('.', $logo_name)));
|
||||
$logo_name = $name.'.'.$logo_ext;
|
||||
$logo_path = 'uploads/'.$logo_name;
|
||||
|
||||
if(in_array($logo_ext, $allowed))
|
||||
{
|
||||
if($logo_error === 0)
|
||||
{
|
||||
if($logo_size < 10000000)
|
||||
{
|
||||
$answer = pictshareUploadImage($logo_tmp_name);
|
||||
if($answer['status']=='ok' && in_array($answer['filetype'],['jpeg','png','gif']))
|
||||
$newlogo = $answer['url'];
|
||||
}
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Die Datei ist zu groß. Bitte eine kleinere Datei hochladen']);
|
||||
}
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Beim Upload der Datei ist ein Fehler aufgetreten']);
|
||||
}
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Dieser Dateityp ist nicht erlaubt. Bitte nur jpg, jpeg oder png Dateien hochladen']);
|
||||
}
|
||||
|
||||
$error = false;
|
||||
if(!$name || !$date )
|
||||
$error = 'Bitte zumindest Name und Datum angeben';
|
||||
else if(!strtotime($date))
|
||||
$error = 'Das Datumm ist ungültig. Bitte die Eingabe prüfen';
|
||||
|
||||
if($error){
|
||||
$this->set('errorMessage', $error);
|
||||
$this->set('template', '/templates/partials/error.html');
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
$t = new Training();
|
||||
|
||||
|
||||
if($id)
|
||||
{
|
||||
if($t->exists($id))
|
||||
$t->load($id);
|
||||
else
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Dieses Turnier existiert nicht']);
|
||||
if(!in_array($_SESSION['user']->id, $t->data['admins']))
|
||||
return partial('error.html', ['errorTitle' => 'Error', 'errorMessage' => 'Du bist nicht berechtigt, dieses Turnier zu bearbeiten']);
|
||||
else
|
||||
$t->load($id);
|
||||
}
|
||||
|
||||
$t->name = $name;
|
||||
$t->date = $date;
|
||||
$t->duration = $training_duration;
|
||||
$t->referee = $training_referee;
|
||||
$t->text = $training_text;
|
||||
$t->url = $training_url;
|
||||
if(!$t->data['admins'] || !is_array($t->data['admins'] || count($t->data['admins']) == 0))
|
||||
$t->data['admins'] = [];
|
||||
if(!in_array($_SESSION['user']->id, $t->data['admins']))
|
||||
$t->data['admins'][] = $_SESSION['user']->id;
|
||||
if($newlogo)
|
||||
$t->logo = $newlogo;
|
||||
|
||||
try
|
||||
{
|
||||
$tid = $t->save();
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$this->set('template', '/templates/partials/error.html');
|
||||
$this->set('errorTitle', 'Error');
|
||||
$this->set('errorMessage', $e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
//var_dump($_SESSION['user']->data['trainings']);
|
||||
|
||||
if(!is_array($_SESSION['user']->data['trainings']) || !in_array($tid, $_SESSION['user']->data['trainings'])) // new t!
|
||||
{
|
||||
$_SESSION['user']->data['trainings'][] = $tid;
|
||||
try
|
||||
{
|
||||
$_SESSION['user']->save();
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$this->set('template', '/templates/partials/error.html');
|
||||
$this->set('errorTitle', 'Error');
|
||||
$this->set('errorMessage', $e->getMessage());
|
||||
return;
|
||||
}
|
||||
$this->redirect('/trainings/event/'.$tid);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->set('template', '/templates/partials/success.html');
|
||||
$this->set('successMessage', "Daten erfolgreich gespeichert");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$id = $this->params[0];
|
||||
$t = new Training();
|
||||
$t->load($id);
|
||||
$this->set('trainingdata',$t->data);
|
||||
$this->set('trainingid',$t->id);
|
||||
$this->set('template', 'edit_training.html');
|
||||
}
|
||||
}
|
||||
|
||||
function maySeeThisPage() {
|
||||
if($_SESSION['user']) //wenn eingeloggt, kein problem
|
||||
return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
}
|
||||
82
web/pages/trainings/edit_training.html
Normal file
82
web/pages/trainings/edit_training.html
Normal file
@@ -0,0 +1,82 @@
|
||||
<div>
|
||||
<h1>Training <?= $trainingid?'Bearbeiten':'Hinzufügen'; ?></h1>
|
||||
|
||||
<form id="trainingeditform" hx-post="/trainings/edit" hx-encoding='multipart/form-data' hx-target="#response" class="container">
|
||||
<input type="hidden" name="training_id" value="<?= $trainingid; ?>">
|
||||
<div class="row">
|
||||
<div class="col-md">
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="training_date">Datum</label>
|
||||
<input type="date" value="<?= $trainingdata['date']; ?>" id="date" name="training_date" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="training_focus">Trainingsfokus</label>
|
||||
<select class="form-select" aria-label="Trainingsfokus" id="training_focus" name="training_focus">
|
||||
<option value="_none">- None -</option>
|
||||
<option value="1">Parcourlauf</option>
|
||||
<option value="2">Distanzarbeit</option>
|
||||
<option value="3">Führtechnik</option>
|
||||
<option value="4">Einzelgeräte</option>
|
||||
<option value="5">Geräteunterscheidung</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="training_url">Video</label>
|
||||
<input type="text" value="<?= $trainingdata['url']; ?>" id="training_url" name="training_url" placeholder="https://www.youtube.com/..." class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="training_mood_barometer_human">Stimmungsbarometer Mensch</label>
|
||||
<select class="form-select" aria-label="Stimmungsbarometer Mensch" id="training_mood_barometer_human" name="training_mood_barometer_human">
|
||||
<option value="_none">- None -</option>
|
||||
<option value="1">😕</option>
|
||||
<option value="2">🙁</option>
|
||||
<option value="3">😐</option>
|
||||
<option value="4">😊</option>
|
||||
<option value="5">🤩</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="training_mood_barometer_dog">Stimmungsbarometer Hund</label>
|
||||
<select class="form-select" aria-label="Stimmungsbarometer Hund" id="training_mood_barometer_dog" name="training_mood_barometer_dog">
|
||||
<option value="_none">- None -</option>
|
||||
<option value="1">😕</option>
|
||||
<option value="2">🙁</option>
|
||||
<option value="3">😐</option>
|
||||
<option value="4">😊</option>
|
||||
<option value="5">🤩</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="uploads">Uploads</label>
|
||||
<input type="file" accept="image/png, image/jpeg, image/gif" id="uploads" class="form-control" name="photos[]" multiple>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md">
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="training_that_worked">Das hat gut geklappt</label>
|
||||
<textarea id="training_that_worked" name="training_that_worked" class="form-control" rows="4"><?= $trainingdata['text']; ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="training_more_excercise">Das müssen wir intensiver üben</label>
|
||||
<textarea id="training_more_excercise" name="training_more_excercise" class="form-control" rows="4"><?= $trainingdata['text']; ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 mb-md-4">
|
||||
<label for="training_text">Notizen</label>
|
||||
<textarea id="training_text" name="training_text" class="form-control" rows="4"><?= $trainingdata['text']; ?></textarea>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<button type="submit" name="submit" value="true" class="btn btn-primary text-end d-inline-block">Hinzufügen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div id="response"></div>
|
||||
</div>
|
||||
111
web/pages/trainings/training.html
Normal file
111
web/pages/trainings/training.html
Normal file
@@ -0,0 +1,111 @@
|
||||
<!-- FILEPATH: /home/chris/git/trainingstats/web/pages/trainings/dog.html -->
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<div class="card">
|
||||
<img src="<?= $tdata['logo'] ?>/300x170/fixedsize" class="card-img-top" alt="<?= escape($tdata['name']); ?>'s profile Picture">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><?= escape($tdata['name']); ?></h5>
|
||||
<p class="card-text">
|
||||
<ul>
|
||||
<li>Datum: <?= escape($tdata['date']) ?></li>
|
||||
|
||||
<?php if($tdata['duration']): ?><li>Dauer: <?= escape($tdata['duration']); ?> Tag/e</li> <?php endif; ?>
|
||||
<?php if($tdata['referee']): ?><li>Richter: <?= escape($tdata['referee']); ?></li> <?php endif; ?>
|
||||
<?php if($tdata['size']): ?><li>Größe: <?= escape($tdata['size']); ?> cm</li> <?php endif; ?>
|
||||
<?php if($tdata['url']): ?><li>Webseite: <a href="<?= $tdata['url']; ?>"><?= escape($tdata['url']); ?></a></li> <?php endif; ?>
|
||||
</ul>
|
||||
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
<?php if($admin===true): ?>
|
||||
<button type="button" class="btn btn-secondary" hx-get="/trainings/edit/<?= $training_id; ?>" hx-target="#main">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if($joined===false): ?>
|
||||
<button type="button" class="btn btn-secondary" hx-get="/trainings/manage/join/<?= $training_id; ?>" hx-swap="outerHTML">
|
||||
<i class="fas fa-plus-circle"></i> Diesem Event beitreten
|
||||
</button>
|
||||
<?php elseif($admin===false): ?>
|
||||
<button type="button" class="btn btn-danger" hx-get="/trainings/manage/leave/<?= $training_id; ?>" hx-swap="outerHTML" hx-confirm="Möchtest du dieses Event wirklich verlassen?">
|
||||
<i class="fas fa-minus-circle"></i> Event verlassen
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if(($admins && count($admins)>1) || ($members && count($members)>0)): ?>
|
||||
<div class="card p-2">
|
||||
<?php if($admins && count($admins)>0): ?> <h6>Admins</h6> <?php endif; ?>
|
||||
<?php foreach($admins as $adm) : ?>
|
||||
<img src="https://pictshare.net/identicon/<?= $adm['email']?>" height="50" width="50" class="rounded-circle" alt="<?= escape($adm['name']); ?>" title="<?= escape($adm['firstname'].' '.$adm['lastname']); ?>">
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?php if($members && count($members)>0): ?> <hr/> <h6>Mitglieder</h6> <?php endif; ?>
|
||||
<?php foreach($members as $member) : ?>
|
||||
<img src="https://pictshare.net/identicon/<?= $member['email']?>" height="50" width="50" class="rounded-circle" alt="<?= escape($member['name']); ?>" title="<?= escape($member['firstname'].' '.$member['lastname']); ?>">
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="col-8" id="sitemain">
|
||||
<?php if($tdata['text']): ?>
|
||||
<div class="card p-2 mb-4">
|
||||
<h4>Beschreibungstext</h4>
|
||||
<p class="card-text">
|
||||
<pre><?= escape($tdata['text']); ?></pre>
|
||||
</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card p-2">
|
||||
<h4>Läufe</h4>
|
||||
<p class="card-text">
|
||||
<?php if($admin===true): ?>
|
||||
<button hx-get="/runs/add/<?= $training_id; ?>" hx-push-url="/runs/add/<?= $training_id; ?>" hx-target="#main" class="btn btn-primary"><i class="fas fa-plus-circle"></i> Lauf hinzufügen</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Bezeichnung</th>
|
||||
<th>Lauf</th>
|
||||
<th>Parcourlänge</th>
|
||||
<th>Normzeit</th>
|
||||
<th>Maxzeit</th>
|
||||
<th>Richter</th>
|
||||
<th>Hund</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($tdata['runs'] as $rid) : ?>
|
||||
<?php
|
||||
$run = new Run();
|
||||
$run->load($rid);
|
||||
?>
|
||||
<tr>
|
||||
<td><a href="/runs/overview/<?= $rid; ?>" hx-get="/runs/overview/<?= $rid; ?>" hx-push-url="/runs/overview/<?= $rid; ?>" hx-target="#main"><?= escape($run->data['name']); ?></a></td>
|
||||
<td><?= escape($run->data['category']); ?></td>
|
||||
<td><?= escape($run->data['length']); ?>m</td>
|
||||
<td><?= escape($run->data['time_standard']); ?>s</td>
|
||||
<td><?= escape($run->data['time_max']); ?>s</td>
|
||||
<td><?= escape($run->data['referee']); ?></td>
|
||||
<td><?= escape($run->data['dog']); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
21
web/pages/trainings/trainings.html
Normal file
21
web/pages/trainings/trainings.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<!-- FILEPATH: /home/chris/git/dogstats/web/pages/dogs/dog.html -->
|
||||
<h1>Turnier Veranstaltungen</h1>
|
||||
<p>Hier kannst du alle Veranstaltungen einsehen.</p>
|
||||
<div class="trainings-list row row-cols-sm-2">
|
||||
<?php foreach ($trainings as $training) : ?>
|
||||
<div class="p-2">
|
||||
<div class="d-flex border">
|
||||
<img src="<?= $training['photo']?:'https://pictshare.net/prrnrk.jpg' ?>/130x100/forcesize" class="" alt="<?= escape($training['name']); ?>'s event Picture">
|
||||
<div class="m-3">
|
||||
<h3 class="h5"><a href="/trainings/event/<?= $training['id'] ?>" class="text-body link-underline link-underline-opacity-0"><?= escape($training['name']); ?></a></h3>
|
||||
<p><?= date("d.m.y",strtotime($training['date'])); ?></p>
|
||||
</div>
|
||||
<div class="m-3 ms-auto">
|
||||
<button hx-get="/training/edit/<?= $training['id'] ?>" hx-push-url="/training/edit/<?= $training['id'] ?>" hx-target="#main" class="btn btn-primary"><i class="fas fa-edit"></i></button>
|
||||
<button hx-get="/training/delete/<?= $training['id'] ?>" hx-target="#main" hx-confirm="Bist du sicher, dass du <?= escape($training['name']); ?> löschen willst" class="btn btn-danger"><i class="fas fa-trash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="en" class="h-100" data-bs-theme="<?= ($_SESSION['user'] && $_SESSION['user']->theme)?$_SESSION['user']->theme:'autoy' ?>">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
@@ -8,20 +8,39 @@
|
||||
<link href="/css/animate.min.css" rel="stylesheet">
|
||||
<link href="/css/fontawesome.min.css" rel="stylesheet">
|
||||
<link href="/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="/css/style.css" rel="stylesheet">
|
||||
|
||||
<link href="/css/dogstats.css" rel="stylesheet">
|
||||
|
||||
|
||||
<script src="/js/echarts.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<body class="d-flex flex-column h-100">
|
||||
<?php include(ROOT."/templates/menu.html") ?>
|
||||
|
||||
<main id="main" class="container" hx-get="/" hx-trigger="load" hx-indicator="#spinner">
|
||||
<i id="spinner" class="fa-solid fa-spinner"></i>
|
||||
<main id="main" class="container" hx-get="/" hx-trigger="load">
|
||||
|
||||
</main>
|
||||
|
||||
<footer class="footer mt-auto py-3 bg-body-tertiary ">
|
||||
<!-- <ul class="nav justify-content-center border-bottom pb-3 mb-3">
|
||||
<li class="nav-item"><a href="#" class="nav-link px-2 text-muted">Home</a></li>
|
||||
<li class="nav-item"><a href="#" class="nav-link px-2 text-muted">Features</a></li>
|
||||
<li class="nav-item"><a href="#" class="nav-link px-2 text-muted">Pricing</a></li>
|
||||
<li class="nav-item"><a href="#" class="nav-link px-2 text-muted">FAQs</a></li>
|
||||
<li class="nav-item"><a href="#" class="nav-link px-2 text-muted">About</a></li>
|
||||
</ul> -->
|
||||
<p class="text-center text-muted">
|
||||
© 2023 Crispi
|
||||
<br/>
|
||||
<small hx-get="/version.txt" hx-trigger="load"></small>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
<script src="/js/htmx.min.js"></script>
|
||||
<script src="/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<script src="/js/dropzone.min.js"></script>
|
||||
<?php if((!$_SESSION['user'] || !$_SESSION['user']->theme)): ?><script src="/js/color-modes.js"></script><?php endif; ?>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -15,26 +15,31 @@
|
||||
<li <?php if (count($item['submenu'])) : ?>
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<a class="nav-link dropdown-toggle <?= $item['menu_classes'] ?>" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="<?= $item['image'] ?>"></i>
|
||||
<?= $item['text']?>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<?php foreach($item['submenu'] as $sub) : ?>
|
||||
<li>
|
||||
<a href="<?= $sub['action'] ?>" hx-push-url="<?= $sub['action'] ?>" hx-get="<?= $sub['action'] ?>" hx-target="#main" class="dropdown-item <?= $sub['classes']?:'' ?>">
|
||||
<?php if($sub['icon']) : ?>
|
||||
<i class="<?= $sub['icon'] ?>"></i>
|
||||
<?php endif; ?>
|
||||
<?php if($sub['text']=='divider') : ?>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<?php else : ?>
|
||||
<li>
|
||||
<a href="<?= $sub['action'] ?>" hx-push-url="<?= $sub['action'] ?>" hx-get="<?= $sub['action'] ?>" hx-target="#main" class="dropdown-item <?= $sub['classes']?:'' ?>">
|
||||
<?php if($sub['icon']) : ?>
|
||||
<i class="<?= $sub['icon'] ?>"></i>
|
||||
<?php endif; ?>
|
||||
|
||||
<?= $sub['text'] ?>
|
||||
</a>
|
||||
</li>
|
||||
<?= $sub['text'] ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</li>
|
||||
<?php else : ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" aria-current="page" href="/<?= $item['url'] ?>" hx-push-url="/<?= $item['url'] ?>" hx-get="/<?= $item['url'] ?>" hx-target="#main">
|
||||
<a class="nav-link <?= $item['menu_classes'] ?>" aria-current="page" href="/<?= $item['url'] ?>" hx-push-url="/<?= $item['url'] ?>" hx-get="/<?= $item['url'] ?>" hx-target="#main">
|
||||
<i class="<?= $item['image'] ?>"></i>
|
||||
<?= $item['text'] ?>
|
||||
</a>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 animate__animated animate__fadeInDown" role="alert">
|
||||
<p class="font-bold"><?= $errorTitle ?></p>
|
||||
<p><?= $errorMessage ?></p>
|
||||
</div>
|
||||
<div class="alert alert-danger animate__animated animate__headShake" role="alert">
|
||||
<?php if($errorTitle) : ?>
|
||||
<h4 class="alert-heading"><?= $errorTitle ?></h4>
|
||||
<?php endif; ?>
|
||||
<?= $errorMessage ?>
|
||||
</div>
|
||||
73
web/templates/partials/graph.html.php
Normal file
73
web/templates/partials/graph.html.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/*
|
||||
usage:
|
||||
|
||||
partial('graph.html.php', [
|
||||
'id' => 'graph1',
|
||||
'title' => 'Graph 1',
|
||||
'gclass' => '', // classes for the graph div
|
||||
'legend' => ['Geschwindigkeit', 'Fehler', 'Verweigerungen', 'Zeit', 'Geschwindigkeit', 'Punkte', 'Platz'],
|
||||
'xaxis' => ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
|
||||
'seriesdata' => [
|
||||
['name' => 'Geschwindigkeit', 'type'=>'line','stack'=>'Total', 'data' => [120, 132, 101, 134, 90, 230, 210]],
|
||||
['name' => 'Fehler', 'type'=>'line','stack'=>'Total', 'data' => [220, 182, 191, 234, 290, 330, 310]],
|
||||
['name' => 'Verweigerungen', 'type'=>'line','stack'=>'Total', 'data' => [150, 232, 201, 154, 190, 330, 410]],
|
||||
['name' => 'Zeit', 'type'=>'line','stack'=>'Total', 'data' => [320, 332, 301, 334, 390, 330, 320]],
|
||||
['name' => 'Punkte', 'type'=>'line','stack'=>'Total', 'data' => [820, 932, 901, 934, 1290, 1330, 1320]],
|
||||
['name' => 'Platz', 'type'=>'line','stack'=>'Total', 'data' => [820, 932, 901, 934, 1290, 1330, 1320]]
|
||||
],
|
||||
])
|
||||
*/
|
||||
|
||||
?>
|
||||
|
||||
<div id="graph<?= $id ?>" data-bs-theme="light" class="card bg-light text-black <?= $gclass ?>" style="min-height: 200px;"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
// Initialize the echarts instance based on the prepared dom
|
||||
var myChart<?= $id ?> = echarts.init(document.getElementById('graph<?= $id ?>'));
|
||||
|
||||
// Specify the configuration items and data for the chart
|
||||
var option = {
|
||||
title: {
|
||||
text: '<?= $title ?>'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
<?php if(isset($legend)): ?>
|
||||
legend: {
|
||||
data: <?= json_encode($legend); ?>
|
||||
},
|
||||
<?php endif; ?>
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
toolbox: {
|
||||
feature: {
|
||||
saveAsImage: {}
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: <?= json_encode($xaxis); ?>
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: <?= json_encode($seriesdata, JSON_PRETTY_PRINT); ?>
|
||||
};
|
||||
|
||||
// Display the chart using the configuration items and data just specified.
|
||||
myChart<?= $id ?>.setOption(option);
|
||||
|
||||
window.addEventListener('resize', function(event) {
|
||||
if(myChart<?= $id ?> != null && myChart<?= $id ?> != undefined){
|
||||
myChart<?= $id ?>.resize();
|
||||
}
|
||||
}, true);
|
||||
</script>
|
||||
@@ -1,4 +1,6 @@
|
||||
<div class="bg-blue-100 border-l-4 border-blue-500 text-blue-700 p-4 animate__animated animate__fadeInDown" role="alert">
|
||||
<p class="font-bold"><?= $infoTitle ?></p>
|
||||
<p><?= $infoMessage ?></p>
|
||||
</div>
|
||||
<div class="alert alert-info animate__animated animate__flash" role="alert">
|
||||
<?php if($infoTitle) : ?>
|
||||
<h4 class="alert-heading"><?= $infoTitle ?></h4>
|
||||
<?php endif; ?>
|
||||
<?= $infoMessage ?>
|
||||
</div>
|
||||
@@ -1,4 +1,6 @@
|
||||
<div class="bg-orange-100 border-l-4 border-orange-500 text-orange-700 p-4 animate__animated animate__fadeInDown" role="alert">
|
||||
<p class="font-bold"><?= $title ?></p>
|
||||
<p><?= $message ?></p>
|
||||
</div>
|
||||
<div class="alert alert-warning animate__animated animate__jello" role="alert">
|
||||
<?php if($noticeTitle) : ?>
|
||||
<h4 class="alert-heading"><?= $noticeTitle ?></h4>
|
||||
<?php endif; ?>
|
||||
<?= $noticeMessage ?>
|
||||
</div>
|
||||
@@ -1,4 +1,6 @@
|
||||
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-4 animate__animated animate__fadeInDown" role="alert">
|
||||
<p class="font-bold"><?= $successTitle ?></p>
|
||||
<p><?= $successMessage ?></p>
|
||||
</div>
|
||||
<div class="alert alert-success animate__animated animate__fadeInDown" role="alert">
|
||||
<?php if($successTitle) : ?>
|
||||
<h4 class="alert-heading"><?= $successTitle ?></h4>
|
||||
<?php endif; ?>
|
||||
<?= $successMessage ?>
|
||||
</div>
|
||||
BIN
web/webfonts/kalam/Kalam-Bold.ttf
Normal file
BIN
web/webfonts/kalam/Kalam-Bold.ttf
Normal file
Binary file not shown.
BIN
web/webfonts/kalam/Kalam-Bold.woff2
Normal file
BIN
web/webfonts/kalam/Kalam-Bold.woff2
Normal file
Binary file not shown.
BIN
web/webfonts/kalam/Kalam-Light.ttf
Normal file
BIN
web/webfonts/kalam/Kalam-Light.ttf
Normal file
Binary file not shown.
BIN
web/webfonts/kalam/Kalam-Light.woff2
Normal file
BIN
web/webfonts/kalam/Kalam-Light.woff2
Normal file
Binary file not shown.
BIN
web/webfonts/kalam/Kalam-Regular.ttf
Normal file
BIN
web/webfonts/kalam/Kalam-Regular.ttf
Normal file
Binary file not shown.
BIN
web/webfonts/kalam/Kalam-Regular.woff2
Normal file
BIN
web/webfonts/kalam/Kalam-Regular.woff2
Normal file
Binary file not shown.
93
web/webfonts/kalam/OFL.txt
Normal file
93
web/webfonts/kalam/OFL.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
Copyright (c) 2014, Indian Type Foundry (info@indiantypefoundry.com).
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Reference in New Issue
Block a user