Initial Code commit

This commit is contained in:
nisch.codes 2025-07-21 22:02:38 +02:00
parent 96d9bbb934
commit e016b9de22
15 changed files with 593 additions and 0 deletions

12
.editorconfig Normal file
View File

@ -0,0 +1,12 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = false

6
.gitignore vendored
View File

@ -2,6 +2,12 @@
composer.phar composer.phar
/vendor/ /vendor/
# ignore every .env file
.env
# ignore .test folders
.test
# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control # Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
# composer.lock # composer.lock

View File

@ -0,0 +1,24 @@
<?php declare(strict_types=1);
namespace Nischcodes\Shiftcalc\App\Controller;
/**
* Controller
*
* main controller for this application
*
* PHP version 8.4 or higher
*
* LICENSE: GPL-3
*
* @package ShiftCalc
* @author nisch.codes <nischcodes@noreply.projects.nisch.codes>
* @copyright 2021 nisch.codes
* @license https://projects.nisch.codes/nischcodes/shiftcalc/src/branch/main/LICENSE GPL-3
* @version 1.0.0
* @link https://projects.nisch.codes/nischcodes/shiftcalc
*/
class Controller extends Nischcodes\ShiftCalc\Controller {
//TODO
}

24
app/model/Repository.php Normal file
View File

@ -0,0 +1,24 @@
<?php declare(strict_types=1);
namespace Nischcodes\Shiftcalc\App\Model;
/**
* Repository
*
* main model for this application
*
* PHP version 8.4 or higher
*
* LICENSE: GPL-3
*
* @package ShiftCalc
* @author nisch.codes <nischcodes@noreply.projects.nisch.codes>
* @copyright 2021 nisch.codes
* @license https://projects.nisch.codes/nischcodes/shiftcalc/src/branch/main/LICENSE GPL-3
* @version 1.0.0
* @link https://projects.nisch.codes/nischcodes/shiftcalc
*/
class Repository extends Nischcodes\ShiftCalc\Controller {
//TODO
}

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Shift Calc</title>
<style>
html, body { margin:0; padding: 0; }
body { padding: 1rem; }
table { border-collapse: collapse; }
table, td, th { border: solid 1px #000000; }
tr.vacation { background-color: #ffffe0; }
tr.homeoffice { background-color: #fff5ee;}
tr.office { background-color: #f0ffff; }
tr.sickday { background-color: #ffe4e1;}
tr.businesstrip { background-color: #e6e6fa; }
tr.holiday { background-color: #f0fff0; }
tr.current { background-color: #008080; }
</style>
</head>
<body>
<!-- CONTENT -->
</body>
</html>

View File

18
composer.json Normal file
View File

@ -0,0 +1,18 @@
{
"name": "nischcodes/shiftcalc",
"description": "A small quick and dirty script to connect to a next cloud instance and read my registered working ours and display thema as a sheet and calculate the worked hours.",
"type": "project",
"license": "GPL-3.0",
"autoload": {
"psr-4": {
"Nischcodes\\Shiftcalc\\": "src/"
}
},
"authors": [
{
"name": "nisch.codes",
"email": "nischcodes@noreply.projects.nisch.codes"
}
],
"require": {}
}

11
config/config.php Normal file
View File

@ -0,0 +1,11 @@
<?php
// define constant for merging all configurations
define('SC_MERGECONFIG', true);
// define constantc for loading .env files
define('SC_LOADDOTENV', true);
// default config schema
$appConfig = [];

4
example.env Normal file
View File

@ -0,0 +1,4 @@
APP_CONTEXT="Production"
HOLIDAY_SERVER="https://get.api-feiertage.de?years=$currentYear&states=nw"
SERVER="https://your.next.cloud/apps/tables/api/1/tables/[$yourTableId]/rows"
LOGIN="yourlogin@next.cloud:YOURPASSWORD"

241
public/index.php Normal file
View File

@ -0,0 +1,241 @@
<html><head><meta name="viewport" content="width=device-width, initial-scale=1"><title>Shift Calc</title><style>html, body { margin:0; padding: 0; } body { padding: 1rem; } table { border-collapse: collapse; } table, td, th { border: solid 1px #000000; } tr.vacation { background-color: #ffffe0; } tr.homeoffice { background-color: #fff5ee;} tr.office { background-color: #f0ffff; } tr.sickday { background-color: #ffe4e1;} tr.businesstrip { background-color: #e6e6fa; } tr.holiday { background-color: #f0fff0; }
tr.current { background-color: #008080; } </style></head><body><?php
// require the vendor autoload file
require '../vendor/autoload.php';
// define working context to prevent data breaching
define("SHIFTCALC", 1);
// use the application namespace
use Nischcodes\Shiftcalc\Application;
use Nischcodes\Shiftcalc\HTTP;
//ini_set('display_errors', '1');
//ini_set('display_startup_errors', '1');
//error_reporting(E_ALL);
// initilize the application
Application::init();
// run the application
Application::run();
function transferHoursToDecimal($time) {
$parts = explode(':', $time);
//var_dump($parts);
return round(($parts[0] + ($parts[1] / 60)), 2);
}
// load login data and encode it
$encodedLogin = base64_encode($_ENV['LOGIN']);
$breakSmall = 0.5;
$breakLarge = 0.75;
$breakLimit = 9;
//print_r($login);
//print_r($encodedLogin);
$currentYear = date("Y");
$holidays = HTTP::fetchJSON(str_replace('$currentYear', $currentYear, $_ENV['HOLIDAY_SERVER']));
//print_r($holidays);
// create a connection via curl
$respData = HTTP::fetchJSON($_ENV['SERVER'], [
"Authorization: Basic [$encodedLogin]",
"Content-Type: application/json",
"OCS-APIRequest: true"
]);
// convert data to json
$respData = json_decode($response, true);
//print_r($respData);
$dates = [];
// add holidays
foreach($holidays['feiertage'] as $holyday) {
//print_r($holyday['date']);
$date = $holyday['date'];
$description = $holyday['fname'];
$dates[] = ['date' => $date, 'start' => '', 'end' => '', 'sdec' => 0, 'edec' => 0, 'worktime' => 8, 'break' => 0, 'worktime_total' => 8, 'info' => 'Holiday', 'desc' => $description];
}
// convert all entries to date/start/end-arrays
foreach($respData as $rpentry) {
$edate = '';
$etime = '';
$etype = 0;
$homeoffice = false;
// extract date, time and type
foreach($rpentry['data'] as $i=>$rpdata) {
if($rpdata['columnId'] == 9) $edate = $rpdata['value'];
else if ($rpdata['columnId'] == 10) $etime = $rpdata['value'];
else if ($rpdata['columnId'] == 12) $etype = $rpdata['value'];
else if ($rpdata['columnId'] == 13) $homeoffice = $rpdata['value'];
}
//print_r($edate);
//print_r($etime);
//print_r($etype);
//print_r($homeoffice);
$found = false;
foreach($dates as $index=>$date) {
//var_dump($date['date']);
//var_dump($edate);
//var_dump($date['date'] == $edate);
if($date['date'] == $edate) {
//var_dump($date);
if($etype == 0) $dates[$index]['start'] = $etime;
else if($etype == 1) {
// add end time to entry
$dates[$index]['end'] = $etime;
// calc shift in decimal
$dates[$index]['sdec'] = transferHoursToDecimal($dates[$index]['start']);
$dates[$index]['edec'] = transferHoursToDecimal($dates[$index]['end']);
$dates[$index]['worktime'] = $dates[$index]['edec'] - $dates[$index]['sdec'];
$dates[$index]['break'] = ($dates[$index]['worktime'] > $breakLimit ? $breakLarge : $breakSmall);
$dates[$index]['worktime_total'] = $dates[$index]['worktime'] - $dates[$index]['break'];
}
$found = true;
break;
}
}
if(!$found) {
if($etype == 0) $dates[] = ['date' => $edate, 'start' => $etime, 'end' => '', 'sdec' => 0, 'edec' => 0, 'worktime' => 0, 'break' => 0.5, 'worktime_total' => 0, 'info' => ($homeoffice ? 'Homeoffice' : 'Office'), 'desc' => ''];
if($etype == 2) $dates[] = ['date' => $edate, 'start' => '', 'end' => '', 'sdec' => 0, 'edec' => 0, 'worktime' => 8, 'break' => 0, 'worktime_total' => 8, 'info' => 'Vacation', 'desc' => ''];
if($etype == 3) $dates[] = ['date' => $edate, 'start' => '', 'end' => '', 'sdec' => 0, 'edec' => 0, 'worktime' => 8, 'break' => 0, 'worktime_total' => 8, 'info' => 'Sickday', 'desc' => ''];
if($etype == 4) $dates[] = ['date' => $edate, 'start' => '', 'end' => '', 'sdec' => 0, 'edec' => 0, 'worktime' => 8, 'break' => 0, 'worktime_total' => 8, 'info' => 'Businesstrip', 'desc' => ''];
}
}
// sort all dates
usort($dates, function($a, $b) {
return strcmp($a['date'], $b['date']);
});
// print_r($dates);
$groupedDates = [];
// group dates by week
foreach($dates as $entry) {
$date = new DateTime($entry['date']);
$year = $date->format('o');
$week = $date->format('W');
$key = "$year-CW$week";
if(!isset($groupedDates[$key])) {
$groupedDates[$key] = [];
}
$groupedDates[$key][] = $entry;
}
//print_r($groupedDates);
$homeofficedays = 0;
$sickdays = 0;
$vacations = 0;
$workdays = 0;
$currentWeek = date("W");
$currentWeekIndex = "$currentYear-CW$currentWeek";
// build the current week
echo "<h2>Current Week</h2>";
echo "<table style=\"width:-webkit-fill-available;\" >";
echo "<tr class=\"calenderweek\"><th colspan=\"7\" style=\"text-align:left;\">$currentWeekIndex</th></tr>";
echo "<tr class=\"cwheader\"><td width=\"10%\">Date</td><td>Info</th><td width=\"10%\">Start</td><td width=\"10%\">End</td><td width=\"10%\">Worktime</td><td width=\"10%\">Break</td><td width=\"10%\">Worktime Total</td></tr>";
$currentWeekTotal = 0;
foreach($groupedDates[$currentWeekIndex] as $id=>$data) {
$date = $data['date'];
$info = $data['info'];
$start = $data['start'];
$end = $data['end'];
$worktime = $data['worktime'];
$break = $data['break'];
$worktimeTotal = $data['worktime_total'];
$description = ($data['desc'] ? ' - '.$data['desc'] : '');
$class = strtolower($info);
echo "<tr class=\"$class\"><td>$date</td><td>$info$description</td><td>$start</td><td>$end</td><td>$worktime</td><td>$break</td><td>$worktimeTotal</td></tr>";
$currentWeekTotal += $worktimeTotal;
}
echo "<tr class=\"cwtotal\" style=\"font-weight: bold;\"><td colspan=\"6\" style=\"text-align:right;\">Total: </td><td>$currentWeekTotal</td></tr>";
echo '</table>';
echo "<p>&nbsp;</p>";
echo "<hr />";
echo "<h2>Full year table</h2>";
// build the full year table
echo "<table style=\"width:-webkit-fill-available;\" >";
foreach($groupedDates as $index=>$group) {
$isCurrentWeek = (strcmp($index, $currentWeekIndex) === 0 ? true : false);
if($isCurrentWeek) echo "<tr class=\"current\"><td colspan=\"7\">&nbsp;</td></tr>";
echo "<tr class=\"calenderweek\"><th colspan=\"7\" style=\"text-align:left;\">$index</th></tr>";
echo "<tr class=\"cwheader\"><td width=\"10%\">Date</td><td>Info</th><td width=\"10%\">Start</td><td width=\"10%\">End</td><td width=\"10%\">Worktime</td><td width=\"10%\">Break</td><td width=\"10%\">Worktime Total</td></tr>";
$weekTotal = 0;
foreach($group as $id=>$data) {
$date = $data['date'];
$info = $data['info'];
$start = $data['start'];
$end = $data['end'];
$worktime = $data['worktime'];
$break = $data['break'];
$worktimeTotal = $data['worktime_total'];
$description = ($data['desc'] ? ' - '.$data['desc'] : '');
$class = strtolower($info);
echo "<tr class=\"$class\"><td>$date</td><td>$info$description</td><td>$start</td><td>$end</td><td>$worktime</td><td>$break</td><td>$worktimeTotal</td></tr>";
$weekTotal += $worktimeTotal;
if(strcmp($info, 'Sickday') === 0) $sickdays++;
if(strcmp($info, 'Homeoffice') === 0) $homeofficedays++;
if(strcmp($info, 'Vacation') === 0) $vacations++;
if(strcmp($info, 'Vacation') !== 0 && strcmp($info, 'Holiday') !== 0) $workdays++;
}
echo "<tr class=\"cwtotal\" style=\"font-weight: bold;\"><td colspan=\"6\" style=\"text-align:right;\">Total: </td><td>$weekTotal</td></tr>";
if($isCurrentWeek) echo "<tr class=\"current\"><td colspan=\"7\">&nbsp;</td></tr>";
}
echo "<tr><td colspan=\"7\">&nbsp;</td></tr>";
//$workdaystotal = count($dates);
echo "<tr class=\"summary\" style=\"font-weight: bold;\"><td>Sickdays: </td><td>$sickdays</td><td>Vacationdays: </td><td>$vacations/30</td><td>Homeoffice: </td><td>$homeofficedays</th><td>$workdays</td></tr>";
echo '</table>';
?></body></html>

66
src/Application.php Normal file
View File

@ -0,0 +1,66 @@
<?php declare(strict_types=1);
namespace Nischcodes\Shiftcalc;
/**
* Application
*
* wraps the hole application
*
* PHP version 8.4 or higher
*
* LICENSE: GPL-3
*
* @package ShiftCalc
* @author nisch.codes <nischcodes@noreply.projects.nisch.codes>
* @copyright 2021 nisch.codes
* @license https://projects.nisch.codes/nischcodes/shiftcalc/src/branch/main/LICENSE GPL-3
* @version 1.0.0
* @link https://projects.nisch.codes/nischcodes/shiftcalc
*/
use Nischcodes\Shiftcalc\DotEnv;
class Application {
static function init() {
// get the current root directory
$projectRoot = self::getProjectRoot();
// load the config file from the config folder
require_once $projectRoot . '/config/config.php';
// load the env file if the config file constant says so
if(SC_LOADDOTENV) {
// load .env file
DotEnv::load("$projectRoot/.env");
}
}
static function run() {
//echo "run application";
}
static function getProjectRoot(?string $startDir = null): string {
$dir = realpath($startDir ?? __DIR__);
while ($dir) {
if (file_exists($dir . '/composer.json')) {
return $dir;
}
$parent = dirname($dir);
if ($parent === $dir) {
break;
}
$dir = $parent;
}
throw new RuntimeException('Project root folder not found.');
}
}

27
src/Controller.php Normal file
View File

@ -0,0 +1,27 @@
<?php declare(strict_types=1);
namespace Nischcodes\Shiftcalc;
/**
* Controller
*
* base controller
*
* PHP version 8.4 or higher
*
* LICENSE: GPL-3
*
* @package ShiftCalc
* @author nisch.codes <nischcodes@noreply.projects.nisch.codes>
* @copyright 2021 nisch.codes
* @license https://projects.nisch.codes/nischcodes/shiftcalc/src/branch/main/LICENSE GPL-3
* @version 1.0.0
* @link https://projects.nisch.codes/nischcodes/shiftcalc
*/
class Controller {
function init($repository) {
}
}

64
src/DotEnv.php Normal file
View File

@ -0,0 +1,64 @@
<?php declare(strict_types=1);
namespace Nischcodes\Shiftcalc;
/**
* Simple DotEnv parser
*
* reads a given .env file an stores the values into the $_ENV array
*
* PHP version 8.4 or higher
*
* LICENSE: GPL-3
*
* @package ShiftCalc
* @author nisch.codes <nischcodes@noreply.projects.nisch.codes>
* @copyright 2021 nisch.codes
* @license https://projects.nisch.codes/nischcodes/shiftcalc/src/branch/main/LICENSE GPL-3
* @version 1.0.0
* @link https://projects.nisch.codes/nischcodes/shiftcalc
*/
class DotEnv {
public static function load(string $path = '..\.env'): void {
// check if given path contains a valid file
if (!file_exists($path)) {
throw new Exception("No valid file: $path");
return;
}
// get file content without new and empty lines
$lines = file($path,
FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES
);
// read line by line
foreach ($lines as $line) {
// remove white characters
$line = trim($line);
// skip comments
if (strpos($line, '#') === 0) {
continue;
}
// split line into key and value
[$key, $value] = array_map(
'trim',
explode('=', $line, 2)
);
// remove the single quotes from the value string
$value = trim($value, "\"'");
// only add to $_ENV if key doesn't already exist
if (!array_key_exists($key, $_ENV)) {
$_ENV[$key] = $value;
putenv("{\$key}={\$value}");
}
}
}
}

45
src/HTTP.php Normal file
View File

@ -0,0 +1,45 @@
<?php declare(strict_types=1);
namespace Nischcodes\Shiftcalc;
/**
* HTTP interface
*
* wraps curl requests into a simple interface
*
* PHP version 8.4 or higher
*
* LICENSE: GPL-3
*
* @package ShiftCalc
* @author nisch.codes <nischcodes@noreply.projects.nisch.codes>
* @copyright 2021 nisch.codes
* @license https://projects.nisch.codes/nischcodes/shiftcalc/src/branch/main/LICENSE GPL-3
* @version 1.0.0
* @link https://projects.nisch.codes/nischcodes/shiftcalc
*/
class HTTP {
static function fetch(string $url, ?Array $headers = []): Mixed {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
if(!empty($headers)) curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
curl_close($ch);
if(curl_errno($ch)) {
throw new Exception('Curl-Error: ' . curl_error($ch));
exit;
}
// returns the raw response of the curl request
return $response;
}
static function fetchJSON(string $url, ?Array $headers = [], ?bool $associative = true): Mixed {
// converts the response of fetch into an JSON array/object
return json_decode(fetch($url, $headers), $associative);
}
}

27
src/Repository.php Normal file
View File

@ -0,0 +1,27 @@
<?php declare(strict_types=1);
namespace Nischcodes\Shiftcalc;
/**
* Controller
*
* base repository
*
* PHP version 8.4 or higher
*
* LICENSE: GPL-3
*
* @package ShiftCalc
* @author nisch.codes <nischcodes@noreply.projects.nisch.codes>
* @copyright 2021 nisch.codes
* @license https://projects.nisch.codes/nischcodes/shiftcalc/src/branch/main/LICENSE GPL-3
* @version 1.0.0
* @link https://projects.nisch.codes/nischcodes/shiftcalc
*/
class Repository {
function init() {
}
}