Updated API

This commit is contained in:
Maximilian Giller 2020-11-06 21:04:45 +01:00
parent fd5a824b89
commit 5c30876c80
18 changed files with 469 additions and 207 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@ juggl/config/config.txt
juggl/config/config.path juggl/config/config.path
juggl/config/config.php juggl/config/config.php
graphics graphics
.vscode

View file

@ -0,0 +1,8 @@
<?php
$config = [
"host" => "localhost",
"dbname" => "juggl",
"username" => "juggl",
"password" => "?=5,}f_F&){;@xthx-[i",
"table_prefix" => "ju_"
];

View file

@ -0,0 +1,28 @@
<?php
session_start();
require_once(__DIR__ . "/services/apiBranch.inc.php");
require_once(__DIR__ . "/services/responses.inc.php");
require_once(__DIR__ . "/services/jugglDbApi.inc.php");
class EndRecordBranch extends ApiBranch
{
function get(ParamCleaner $params)
{
respondStatus(405);
}
function post(ParamCleaner $params)
{
$user_id = $params->get("user_id");
$params->select("request");
if ($params->exists(["end_time", "record_id"]) == false) {
respondStatus(400, "Missing parameter");
}
updateEndRecord($user_id, $params);
}
}
$branch = new EndRecordBranch();
$branch->execute();

View file

@ -0,0 +1,34 @@
<?php
session_start();
require_once(__DIR__ . "/services/apiBranch.inc.php");
require_once(__DIR__ . "/services/jsonBuilder.inc.php");
require_once(__DIR__ . "/services/responses.inc.php");
require_once(__DIR__ . "/services/jugglDbApi.inc.php");
class GetRecordBranch extends ApiBranch
{
function get(ParamCleaner $params)
{
respondStatus(405);
}
function post(ParamCleaner $params)
{
$user_id = $params->get("user_id");
$params->select("request");
if ($params->exists(["record_id"]) == false) {
respondStatus(400, "Missing parameter");
}
$record = getTimeRecord($user_id, $params->get("record_id"));
$json = new JsonBuilder();
$json->addRecords([$record]);
respondJson($json);
}
}
$branch = new GetRecordBranch();
$branch->execute();

View file

@ -1,12 +1,14 @@
<?php <?php
require_once(__DIR__."/basicEnum.inc.php"); require_once(__DIR__ . "/basicEnum.inc.php");
class DbOperations { class DbOperations
function __construct ($tablePrefix = null) { {
function __construct($tablePrefix = null)
{
$this->resetQuery(); $this->resetQuery();
$this->tablePrefix = $tablePrefix; $this->tablePrefix = $tablePrefix;
require(__DIR__."/../config/config.php"); require(__DIR__ . "/../config/config.php");
$this->config = $config; $this->config = $config;
if ($this->tablePrefix == null) { if ($this->tablePrefix == null) {
@ -14,14 +16,15 @@ class DbOperations {
} }
} }
function resetQuery() { function resetQuery()
{
$this->query = ""; $this->query = "";
$this->data = array(); $this->data = array();
$this->table = ""; $this->table = "";
$this->tablePrefix = "";
} }
private function openConnection () { private function openConnection()
{
$host = $this->config['host']; $host = $this->config['host'];
$dbname = $this->config['dbname']; $dbname = $this->config['dbname'];
$dsn = "mysql:host=$host;dbname=$dbname"; $dsn = "mysql:host=$host;dbname=$dbname";
@ -31,12 +34,13 @@ class DbOperations {
$this->pdo = new PDO($dsn, $this->config['username'], $this->config['password'], $options); $this->pdo = new PDO($dsn, $this->config['username'], $this->config['password'], $options);
} }
function select (string $table, array $attributes = array()) { function select(string $table, array $attributes = array())
$this->table = $this->tablePrefix.$table; {
$this->table = $this->tablePrefix . $table;
if (count($attributes) == 0) if (count($attributes) == 0)
$formattedAttributes = "*"; $formattedAttributes = "*";
else { else {
for($i = 0; $i < count($attributes); $i++){ for ($i = 0; $i < count($attributes); $i++) {
$a = $attributes[$i]; $a = $attributes[$i];
if (strpos($a, ".") === false) { if (strpos($a, ".") === false) {
$attributes[$i] = "$this->table.$a"; $attributes[$i] = "$this->table.$a";
@ -51,13 +55,15 @@ class DbOperations {
} }
function orderBy (string $attribute, string $order = Order::ASC) { function orderBy(string $attribute, string $order = Order::ASC)
{
$this->addToQuery("ORDER BY $attribute $order"); $this->addToQuery("ORDER BY $attribute $order");
return $this; return $this;
} }
static function getLatestIdInTable (string $table, string $attribute = "id") { static function getLatestIdInTable(string $table, string $attribute = "id")
{
$db = new DbOperations(); $db = new DbOperations();
$db->select($table, array($attribute)); $db->select($table, array($attribute));
$db->orderBy($attribute, Order::DESC); $db->orderBy($attribute, Order::DESC);
@ -65,12 +71,13 @@ class DbOperations {
return $db->execute()[0][$attribute]; return $db->execute()[0][$attribute];
} }
function insert (string $table, array $data) { function insert(string $table, array $data)
$this->table = $this->tablePrefix.$table; {
$this->table = $this->tablePrefix . $table;
$attributes = implode(", ", array_keys($data)); $attributes = implode(", ", array_keys($data));
$valuesIds = array(); $valuesIds = array();
foreach($data as $attribute => $value) { foreach ($data as $attribute => $value) {
$valuesIds[] = $this->addData($value, $attribute); $valuesIds[] = $this->addData($value, $attribute);
} }
$values = implode(" , ", $valuesIds); $values = implode(" , ", $valuesIds);
@ -80,13 +87,14 @@ class DbOperations {
return $this; return $this;
} }
function insertMultiple (string $table, array $attributes, array $data) { function insertMultiple(string $table, array $attributes, array $data)
$this->table = $this->tablePrefix.$table; {
$this->table = $this->tablePrefix . $table;
$attributesString = implode(", ", $attributes); $attributesString = implode(", ", $attributes);
$valueGroups = array(); $valueGroups = array();
$groupIndex = 0; // To avoid same value ids $groupIndex = 0; // To avoid same value ids
foreach($data as $dataGroup) { foreach ($data as $dataGroup) {
if (sizeof($attributes) != sizeof($dataGroup)) { if (sizeof($attributes) != sizeof($dataGroup)) {
continue; continue;
} }
@ -97,7 +105,7 @@ class DbOperations {
$valueIds[] = $this->addData($dataGroup[$i], $attributes[$i] . "_" . (string) $groupIndex); $valueIds[] = $this->addData($dataGroup[$i], $attributes[$i] . "_" . (string) $groupIndex);
} }
$valueGroups[] = "(" . implode(", " ,$valueIds) . ")"; $valueGroups[] = "(" . implode(", ", $valueIds) . ")";
$groupIndex++; $groupIndex++;
} }
$values = implode(", ", $valueGroups); $values = implode(", ", $valueGroups);
@ -107,11 +115,12 @@ class DbOperations {
return $this; return $this;
} }
function update (string $table, array $data) { function update(string $table, array $data)
$this->table = $this->tablePrefix.$table; {
$this->table = $this->tablePrefix . $table;
$sets = array(); $sets = array();
foreach($data as $attribute => $value) { foreach ($data as $attribute => $value) {
$valueId = $this->addData($value, $attribute); $valueId = $this->addData($value, $attribute);
$sets[] = "$attribute = $valueId"; $sets[] = "$attribute = $valueId";
} }
@ -122,20 +131,34 @@ class DbOperations {
return $this; return $this;
} }
function delete (string $table) { function delete(string $table)
$this->table = $this->tablePrefix.$table; {
$this->table = $this->tablePrefix . $table;
$this->addToQuery("DELETE FROM $this->tablePrefix$table"); $this->addToQuery("DELETE FROM $this->tablePrefix$table");
return $this; return $this;
} }
private function addToQuery (string $phrase) { function limit(int $limit, int $offset = null)
{
$this->addToQuery("LIMIT $limit");
if ($offset != null) {
$this->addToQuery("OFFSET $offset");
}
return $this;
}
private function addToQuery(string $phrase)
{
$delimeter = " "; $delimeter = " ";
$this->query = implode($delimeter, array($this->query, $phrase)); $this->query = implode($delimeter, array($this->query, $phrase));
} }
function where (string $attribute, string $comparison, $value, string $connector = Combination::AND) { function where(string $attribute, string $comparison, $value, string $connector = Combination::AND)
{
if (Comparison::isValidValue($comparison) == false) if (Comparison::isValidValue($comparison) == false)
return; return;
@ -149,7 +172,33 @@ class DbOperations {
return $this; return $this;
} }
function innerJoin (string $table, string $externAttribute, string $internAttribute = "", string $internTable = "") { function whereOneOf(string $attribute, string $comparison, $values, string $connector = Combination::AND)
{
if (Comparison::isValidValue($comparison) == false)
return;
$keyWord = "WHERE";
if (!(strpos($this->query, $keyWord) === false))
$keyWord = $connector;
$whereClause = "$keyWord ( ";
for ($i = 0; $i < sizeof($values); $i++) {
if ($i > 0) {
$whereClause .= " OR ";
}
$valueId = $this->addData($values[$i], $attribute . '_' . $i);
$whereClause .= "$attribute $comparison $valueId";
}
$whereClause .= " )";
$this->addToQuery($whereClause);
return $this;
}
function innerJoin(string $table, string $externAttribute, string $internAttribute = "", string $internTable = "")
{
if ($internTable === "") { if ($internTable === "") {
$internTable = substr($this->table, sizeof($this->tablePrefix)); $internTable = substr($this->table, sizeof($this->tablePrefix));
} }
@ -164,22 +213,37 @@ class DbOperations {
return $this; return $this;
} }
private function addData($data, $attribute) { private function addData($data, $attribute)
{
$name = str_replace(".", "", $attribute); $name = str_replace(".", "", $attribute);
$this->data[$name] = $data; $this->data[$name] = $data;
return ":".$name; return ":" . $name;
} }
function execute() { function addSql($sql)
try{ {
$this->addToQuery($sql);
}
function addValue($value)
{
$identifier = "customIdentifier" . $this->customValueId;
$this->customValueId += 1;
$this->addToQuery($this->addData($value, $identifier));
}
function execute()
{
try {
$this->openConnection(); $this->openConnection();
$pdoQuery = $this->pdo->prepare($this->query); $pdoQuery = $this->pdo->prepare($this->query);
$pdoQuery->execute($this->data); $pdoQuery->execute($this->data);
$results = array(); $results = array();
while($row = $pdoQuery->fetch()) { while ($row = $pdoQuery->fetch()) {
$results[] = $row; $results[] = $row;
} }
@ -193,16 +257,18 @@ class DbOperations {
} }
} }
function sql(string $sqlStatement, array $data) { function sql(string $sqlStatement, array $data)
{
$this->query = $sqlStatement; $this->query = $sqlStatement;
foreach($data as $attribute => $value) { foreach ($data as $attribute => $value) {
$this->addData($value, $attribute); $this->addData($value, $attribute);
} }
} }
} }
abstract class Comparison extends BasicEnum { abstract class Comparison extends BasicEnum
{
const EQUAL = "="; const EQUAL = "=";
const GREATER_THAN = ">"; const GREATER_THAN = ">";
const GREATER_THAN_OR_EQUAL = ">="; const GREATER_THAN_OR_EQUAL = ">=";
@ -212,13 +278,14 @@ abstract class Comparison extends BasicEnum {
const LIKE = "LIKE"; const LIKE = "LIKE";
} }
abstract class Combination extends BasicEnum { abstract class Combination extends BasicEnum
{
const AND = "AND"; const AND = "AND";
const OR = "OR"; const OR = "OR";
} }
abstract class Order extends BasicEnum { abstract class Order extends BasicEnum
{
const ASC = "ASC"; const ASC = "ASC";
const DESC = "DESC"; const DESC = "DESC";
} }
?>

View file

@ -0,0 +1,49 @@
<?php
class JsonBuilder
{
function __construct()
{
$this->jsonData = array();
}
function getJson()
{
return json_encode($this->jsonData, JSON_FORCE_OBJECT);
}
function getArray()
{
return $this->jsonData;
}
function addRecords(array $records)
{
$columns = array(
"record_id" => "",
"start_time" => "",
"end_time" => "",
"duration" => "",
"user_id" => "",
"project_id" => "",
"start_device_id" => ""
);
foreach ($records as $record) {
$this->jsonData['records'] = array();
$this->jsonData['records'][] = $this->createJsonArray($record, $columns);
}
return $this;
}
private function createJsonArray(array $data, array $columns)
{
$jsonArray = array();
foreach ($columns as $key => $column) {
if ($column === "") {
$column = $key;
}
$jsonArray[$key] = $data[$column];
}
return $jsonArray;
}
}

View file

@ -0,0 +1,167 @@
<?php
require_once(__DIR__ . "/services/dbOperations.inc.php");
function addStartRecord($user_id, $params, $project_id = null, $start_device_id = null)
{
$data = [
"user_id" => $user_id,
"start_time" => $params->get("start_time"),
"project_id" => $project_id,
"start_device_id" => $start_device_id
];
$db = new DbOperations();
$db->insert("time_records", $data);
$db->execute();
}
function addTimeRecord($user_id, $params, $project_id = null, $start_device_id = null)
{
$data = [
"user_id" => $user_id,
"start_time" => $params->get("start_time"),
"end_time" => $params->get("end_time"),
"duration" => $params->get("duration"),
"project_id" => $project_id,
"start_device_id" => $start_device_id
];
$db = new DbOperations();
$db->insert("time_records", $data);
$db->execute();
}
function getTimeRecord($user_id, $record_id)
{
$db = new DbOperations();
$db->select("time_records");
$db->where("user_id", Comparison::EQUAL, $user_id);
$db->where("record_id", Comparison::EQUAL, $record_id);
$result = $db->execute();
if (count($result) <= 0) {
return null;
}
$result = $result[0];
// Is still running?
if ($result["end_time"] == null) {
$result["duration"] = calcDuration($result["start_time"]);
}
return $result;
}
function getProjectRecord($user_id, $project_id, $finished = null)
{
$db = new DbOperations();
$db->select("time_records");
$db->where("user_id", Comparison::EQUAL, $user_id);
$db->where("project_id", Comparison::EQUAL, $project_id);
if ($finished != null) {
$comp = Comparison::UNEQUAL;
if ($finished == false) {
$comp = Comparison::EQUAL;
}
$db->where("end_time", $comp, null);
}
$db->orderBy("start_time", Order::DESC);
$result = $db->execute();
if (count($result) <= 0) {
return null;
}
$result = $result[0];
// Is still running?
if ($result["end_time"] == null) {
$result["duration"] = calcDuration($result["start_time"]);
}
return $result;
}
function updateEndRecord($user_id, $params)
{
$record_id = $params->get("record_id");
// Get start instance to calculate duration
$start_time = getTimeRecord($user_id, $record_id)[0]["start_time"];
$data = [
"end_time" => $params->get("end_time"),
"duration" => calcDuration($start_time, $params->get("end_time"))
];
$db = new DbOperations();
$db->update("time_records", $data);
$db->where("user_id", Comparison::EQUAL, $user_id);
$db->where("record_id", Comparison::EQUAL, $record_id);
$db->execute();
}
function updateTimeRecord($user_id, $params)
{
$data = [];
$anythingUpdated = false;
if ($params->exists(["start_time"])) {
$data["start_time"] = $params->get("start_time");
$anythingUpdated = true;
}
if ($params->exists(["end_time"])) {
$data["end_time"] = $params->get("end_time");
$anythingUpdated = true;
}
if ($params->exists(["duration"])) {
$data["duration"] = $params->get("duration");
$anythingUpdated = true;
}
if ($params->exists(["project_id"])) {
$data["project_id"] = $params->get("project_id");
$anythingUpdated = true;
}
if ($params->exists(["start_device_id"])) {
$data["start_device_id"] = $params->get("start_device_id");
$anythingUpdated = true;
}
if ($anythingUpdated == false) {
return;
}
$db = new DbOperations();
$db->update("time_records", $data);
$db->where("user_id", Comparison::EQUAL, $user_id);
$db->where("record_id", Comparison::EQUAL, $params->get("record_id"));
$db->execute();
}
function isProjectValid($project_id, $user_id)
{
$db = new DbOperations();
$db->select("projects");
$db->where("project_id", Comparison::EQUAL, $project_id);
$db->where("user_id", Comparison::EQUAL, $user_id);
return count($db->execute()) == 1;
}
function isDeviceValid($start_device_id, $user_id)
{
$db = new DbOperations();
$db->select("devices");
$db->where("start_device_id", Comparison::EQUAL, $start_device_id);
$db->where("user_id", Comparison::EQUAL, $user_id);
return count($db->execute()) == 1;
}
function calcDuration($start_time, $end_time = "NOW")
{
return (int)((new DateTime($start_time))->diff(new DateTime($end_time))->format("%s"));
}

View file

@ -0,0 +1,50 @@
<?php
session_start();
require_once(__DIR__ . "/services/apiBranch.inc.php");
require_once(__DIR__ . "/services/jsonBuilder.inc.php");
require_once(__DIR__ . "/services/responses.inc.php");
require_once(__DIR__ . "/services/jugglDbApi.inc.php");
class StartRecordBranch extends ApiBranch
{
function get(ParamCleaner $params)
{
respondStatus(405);
}
function post(ParamCleaner $params)
{
$user_id = $params->get("user_id");
$params->select("request");
if ($params->exists(["start_time"]) == false) {
respondStatus(400, "Missing parameter");
}
$project_id = $params->get("project_id");
if (isProjectValid($project_id, $user_id) == false) {
$project_id = null;
}
$device_id = $params->get("start_device_id");
if (isDeviceValid($device_id, $user_id) == false) {
$device_id = null;
}
// Does a running record for that project already exist?
if (getProjectRecord($user_id, $project_id, false) != null) {
respondStatus(409, "Project record already started");
}
addStartRecord($user_id, $params, $project_id, $device_id);
$record = getProjectRecord($user_id, $project_id, false);
$json = new JsonBuilder();
$json->addRecords([$record]);
respondJson($json);
}
}
$branch = new StartRecordBranch();
$branch->execute();

View file

@ -1,37 +0,0 @@
<?php
class JsonBuilder {
function __construct () {
$this->jsonData = array();
}
function getJson () {
return json_encode($this->jsonData, JSON_FORCE_OBJECT);
}
function getArray () {
return $this->jsonData;
}
function addCategories (array $categories) {
$columns = array("id" => "",
"name" => "");
foreach ($categories as $category) {
$this->jsonData['categories'] = array();
$this->jsonData['categories'][] = $this->createJsonArray($category, $columns);
}
return $this;
}
private function createJsonArray (array $data, array $columns) {
$jsonArray = array();
foreach ($columns as $key => $column) {
if ($column === "") {
$column = $key;
}
$jsonArray[$key] = $data[$column];
}
return $jsonArray;
}
}
?>

View file

@ -1,110 +0,0 @@
<?php
session_start();
require_once(__DIR__."/services/apiBranch.inc.php");
require_once(__DIR__."/services/dbOperations.inc.php");
require_once(__DIR__."/services/jsonBuilder.inc.php");
require_once(__DIR__."/services/responses.inc.php");
class TimeTrackingBranch extends ApiBranch {
function get (ParamCleaner $params) {
respondStatus(404);
}
function post (ParamCleaner $params) {
$user_id = $params->get("user_id");
$params->select("request");
// Is id given, should update?
if ($params->exists(["record_id"])) {
$this->updateTimeRecord($user_id, $params);
} else {
if ($params->exists(["start_time", "end_time", "duration"]) == false) {
respondStatus(400, "Missing parameter");
}
$project_id = $params->get("project_id");
if ($this->isProjectValid($project_id, $user_id) == false) {
$project_id = null;
}
$device_id = $params->get("device_id");
if ($this->isDeviceValid($device_id, $user_id) == false) {
$device_id = null;
}
$this->addTimeRecord($user_id, $params, $project_id, $device_id);
}
}
private function isProjectValid ($project_id, $user_id) {
$db = new DbOperations();
$db->select("projects");
$db->where("project_id", Comparison::EQUAL, $project_id);
$db->where("user_id", Comparison::EQUAL, $user_id);
return count($db->execute()) == 1;
}
private function isDeviceValid ($device_id, $user_id) {
$db = new DbOperations();
$db->select("devices");
$db->where("device_id", Comparison::EQUAL, $device_id);
$db->where("user_id", Comparison::EQUAL, $user_id);
return count($db->execute()) == 1;
}
private function addTimeRecord ($user_id, $params, $project_id = null, $device_id = null) {
$data = ["user_id" => $user_id,
"start_time" => $params->get("start_time"),
"end_time" => $params->get("end_time"),
"duration" => $params->get("duration"),
"project_id" => $project_id,
"device_id" => $device_id];
$db = new DbOperations();
$db->insert("time_records", $data);
$db->execute();
}
private function updateTimeRecord ($user_id, $params) {
$data = ["user_id" => $user_id,
"record_id" => $params->get("record_id")
];
$anythingUpdated = false;
if ($params->exists(["start_time"])) {
$data["start_time"] = $params->get("start_time");
$anythingUpdated = true;
}
if ($params->exists(["end_time"])) {
$data["end_time"] = $params->get("end_time");
$anythingUpdated = true;
}
if ($params->exists(["duration"])) {
$data["duration"] = $params->get("duration");
$anythingUpdated = true;
}
if ($params->exists(["project_id"])) {
$data["project_id"] = $params->get("project_id");
$anythingUpdated = true;
}
if ($params->exists(["device_id"])) {
$data["device_id"] = $params->get("device_id");
$anythingUpdated = true;
}
if ($anythingUpdated == false) {
return;
}
$db = new DbOperations();
$db->update("time_records", $data);
$db->execute();
}
}
$branch = new TimeTrackingBranch();
$branch->execute();
?>

View file

@ -14,12 +14,17 @@ Juggl Documentation
ToDo ToDo
High Priority High Priority
Tracking Windows Client
Refactor TimeLogger
Offline BackUps
Nur tracking wenn aktiviert
Time tracking Time tracking
API interface API interface
Web interface Web interface
General
Hold some kind of current state
e.g. "Currently working on"
Low Priority Low Priority
Timetracking API
Setting null does not work
Web interface Web interface
Datbase Datbase