diff --git a/action.php b/action.php index c1413a8..bceda74 100644 --- a/action.php +++ b/action.php @@ -97,20 +97,19 @@ switch ($VARS['action']) { returnToSender("invalid_parameters"); } - $machine = new Machine($VARS['machine']); - - $machine->addEvent( - date( - "Y-m-d H:i:s", - strtotime($VARS['date'] . " " . $VARS['time']) - ), - $VARS['event'], - $user->getUID(), - $VARS['publicnotes'], - $VARS['privatenotes'] + $evt = Event::create( + $VARS['machine'], + date( + "Y-m-d H:i:s", + strtotime($VARS['date'] . " " . $VARS['time']) + ), + $VARS['event'], + $user->getUID(), + $VARS['publicnotes'], + $VARS['privatenotes'] ); - returnToSender("event_added", $machine->getID()); + returnToSender("event_added", $VARS['machine']); case "editclient": $user = new User($_SESSION['uid']); if (!$user->hasPermission("MACHINEMANAGER_EDIT")) { diff --git a/api/.htaccess b/api/.htaccess index 9a4efe4..c26f042 100644 --- a/api/.htaccess +++ b/api/.htaccess @@ -1,4 +1,3 @@ -# Rewrite for Nextcloud Notes API RewriteEngine on RewriteRule ([a-zA-Z0-9]+) index.php?action=$1 [PT] diff --git a/api/actions/lookup.php b/api/actions/lookup.php deleted file mode 100644 index 6231c21..0000000 --- a/api/actions/lookup.php +++ /dev/null @@ -1,21 +0,0 @@ -hasPermission("MACHINEMANAGER_EDIT")) { + http_response_code(403); + sendJsonResp("You don't have permission to edit.", "ERROR"); + } + + if (!empty($VARS["model"])) { + $machine->setModel($VARS['model']); + } + if (!empty($VARS["client"])) { + $machine->setClientID($VARS['client']); + } + if (!empty($VARS["os"])) { + $machine->setOS($VARS['os']); + } + if (!empty($VARS["serial"])) { + $machine->setSerial($VARS['serial']); + } + if (!empty($VARS["manufacturer"])) { + $machine->setManufacturer($VARS['manufacturer']); + } + if (!empty($VARS["condition"])) { + $machine->setCondition($VARS['condition']); + } + if (!empty($VARS["price"])) { + $machine->setPrice($VARS['price']); + } + if (!empty($VARS["privatenotes"])) { + $machine->setPrivateNotes($VARS['privatenotes']); + } + if (!empty($VARS["publicnotes"])) { + $machine->setPublicNotes($VARS['publicnotes']); + } + + $machine->save(); +} + +header("Content-Type: application/json"); + +$output = $machine->toArray(); +$output["editable"] = $user->hasPermission("MACHINEMANAGER_EDIT"); + +exit(json_encode($output)); diff --git a/api/apisettings.php b/api/apisettings.php index 8d34b16..97dc943 100644 --- a/api/apisettings.php +++ b/api/apisettings.php @@ -13,9 +13,38 @@ $APIS = [ ] ], "lookup" => [ - "load" => "lookup.php", + "load" => "machine.php", "vars" => [ "id" => "/^[0-9a-z]+$/" ] + ], + "editmachine" => [ + "load" => "machine.php", + "vars" => [ + "id" => "/^[0-9a-z]+$/", + "model (optional)" => "string", + "client (optional)" => "string", + "os (optional)" => "string", + "serial (optional)" => "string", + "manufacturer (optional)" => "string", + "condition (optional)" => "numeric", + "price (optional)" => "numeric", + "privatenotes (optional)" => "string", + "publicnotes (optional)" => "string" + ] + ], + "addmachine" => [ + "load" => "machine.php", + "vars" => [ + "model (optional)" => "string", + "client (optional)" => "string", + "os (optional)" => "string", + "serial (optional)" => "string", + "manufacturer (optional)" => "string", + "condition (optional)" => "numeric", + "price (optional)" => "numeric", + "privatenotes (optional)" => "string", + "publicnotes (optional)" => "string" + ] ] ]; diff --git a/api/login/index.php b/api/login/index.php new file mode 100644 index 0000000..667654e --- /dev/null +++ b/api/login/index.php @@ -0,0 +1,148 @@ + + + + + + + <?php echo $SETTINGS['app_name']; ?> + + + + + + +
+
+
+ +
+ +
+

+
+ + +
+
+
+

+ +

+
+
+
+ + + +
+
+
+ +
+
+
+ +
+
+ $_SESSION["login_code"]]); + + if ($uidinfo["status"] == "ERROR") { + throw new Exception(); + } + if (is_numeric($uidinfo['uid'])) { + $user = new User($uidinfo['uid'] * 1); + + $addpassresp = AccountHubApi::get( + "addapppassword", + [ + "desc" => $SETTINGS["app_name"], + "username" => $user->getUsername() + ], + true + ); + + $_SESSION["login_code"] = null; + + $redirecturl = "https://apploginhelper.netsyms.net/?user:" . htmlentities($user->getUsername()) . "&password:" . htmlentities($addpassresp["pass"]); + + header("Location: $redirecturl"); + showHTML("Continue", "Click Here", $redirecturl); + } else { + throw new Exception(); + } + } catch (Exception $ex) { + $redirecttologin = true; + } +} + +if ($redirecttologin) { + try { + $codedata = AccountHubApi::get("getloginkey", ["appname" => $SETTINGS["app_name"], "appicon" => $iconurl], true); + + if ($codedata['status'] != "OK") { + throw new Exception("There was a problem. Try again later."); + } + + $_SESSION["login_code"] = $codedata["code"]; + + $locationurl = $codedata["loginurl"] . "?code=" . htmlentities($codedata["code"]) . "&redirect=" . htmlentities($thisurl); + + header("Location: $locationurl"); + showHTML("Continue", "Continue", $locationurl); + die(); + } catch (Exception $ex) { + showHTML("Error", "", "", $ex->getMessage()); + } +} \ No newline at end of file diff --git a/langs/en/components.json b/langs/en/components.json new file mode 100644 index 0000000..db23641 --- /dev/null +++ b/langs/en/components.json @@ -0,0 +1,4 @@ +{ + "Type": "Type", + "Tested": "Tested" +} diff --git a/langs/en/events.json b/langs/en/events.json new file mode 100644 index 0000000..ed44fad --- /dev/null +++ b/langs/en/events.json @@ -0,0 +1,4 @@ +{ + "Date": "Date", + "Technician": "Technician" +} diff --git a/lib/Client.lib.php b/lib/Client.lib.php index f8a4ffb..be98587 100644 --- a/lib/Client.lib.php +++ b/lib/Client.lib.php @@ -10,7 +10,7 @@ use InvoiceNinja\Config as NinjaConfig; use InvoiceNinja\Models\Client as NinjaClient; -class Client { +class Client implements JsonSerializable { private $local = true; private $exists = false; @@ -54,6 +54,13 @@ class Client { } } + public function jsonSerialize() { + return [ + "id" => $this->id, + "name" => $this->name + ]; + } + /** * Fill in all the client data from the InvoiceNinja API. */ diff --git a/lib/Clients.lib.php b/lib/Clients.lib.php index 6ce99f5..c8c8dee 100644 --- a/lib/Clients.lib.php +++ b/lib/Clients.lib.php @@ -41,6 +41,15 @@ if (!empty($SETTINGS["apis"]["invoiceninja"]["token"])) { return $list; } + public static function getAllAsIDNameArray(): array { + $clients = Clients::getAll(); + $arr = []; + foreach ($clients as $c) { + $arr[$c->getID()] = $c->getName(); + } + return $arr; + } + public static function getClient($id): Client { return new Client($id, false); } diff --git a/lib/Component.lib.php b/lib/Component.lib.php index fef9f10..db10907 100644 --- a/lib/Component.lib.php +++ b/lib/Component.lib.php @@ -4,7 +4,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -class Component { +class Component implements JsonSerializable { private $componentid = ""; private $component = []; @@ -39,6 +39,60 @@ class Component { return $list; } + public function toArray() { + global $Strings; + if ($this->exists) { + return [ + "info" => [ + "id" => $this->getID(), + "machineid" => $this->getMachineID(), + "serial" => $this->getSerial(), + "type" => $this->getTypeID(), + "tested" => $this->getTestedDate(), + "capacity" => $this->getCapacity(), + "model" => $this->getModel(), + "price" => $this->getPrice(), + "manufacturer" => $this->getManufacturer(), + "publicnotes" => $this->getPublicNotes(), + "privatenotes" => $this->getPrivateNotes() + ], + "formdata" => [ + "types" => $this->getTypes(), + "inputtypes" => [ + "machineid" => "text", + "serial" => "text", + "type" => "number", + "tested" => "datetime", + "capacity" => "text", + "model" => "text", + "price" => "number", + "manufacturer" => "text", + "privatenotes" => "textarea", + "publicnotes" => "textarea" + ], + "labels" => [ + "machineid" => $Strings->get("Machine ID", false), + "serial" => $Strings->get("Serial", false), + "type" => $Strings->get("Type", false), + "tested" => $Strings->get("Tested", false), + "capacity" => $Strings->get("Capacity", false), + "model" => $Strings->get("Model", false), + "price" => $Strings->get("Price", false), + "manufacturer" => $Strings->get("Manufacturer", false), + "privatenotes" => $Strings->get("Private Notes", false), + "publicnotes" => $Strings->get("Public Notes", false) + ], + "icons" => [] + ] + ]; + } + return []; + } + + public function jsonSerialize() { + return $this->toArray(); + } + public function save() { global $database; if ($this->exists) { diff --git a/lib/Event.lib.php b/lib/Event.lib.php new file mode 100644 index 0000000..ec5a12c --- /dev/null +++ b/lib/Event.lib.php @@ -0,0 +1,195 @@ +id = $eventid; + if (\Event::exists($eventid)) { + $this->exists = true; + $this->event = $database->get('events', ['machineid', 'eventid', 'techuid', 'date', 'privatenotes', 'publicnotes'], ['historyid' => $eventid]); + } + } + + public static function create(string $machineid = "", string $date = "", int $event = 0, string $techuid = "", string $publicnotes = "", string $privatenotes = ""): Event { + if ($machineid == "" || $date == "" || $event == 0) { + return new Event(""); + } else { + if (!Machine::exists($machineid)) { + throw new Exception("Invalid machine ID $machineid"); + } + if (strtotime($date) === false) { + throw new Exception("Invalid date."); + } + $date = date("Y-m-d H:i:s", strtotime($date)); + if (!array_key_exists($event, \Event::getTypes())) { + throw new Exception("Invalid event type."); + } + $evt = new Event(""); + + $evt->setMachineID($machineid); + $evt->setTypeID($event); + $evt->setDate($date); + $evt->setTechUID($techuid); + $evt->setPrivateNotes($privatenotes); + $evt->setPublicNotes($publicnotes); + $evt->save(); + + return $evt; + } + } + + public static function exists($id): bool { + global $database; + return $database->has('events', ['historyid' => $id]); + } + + public static function getTypes() { + global $database; + $types = $database->select("event_types", ["eventid (id)", "eventname (name)"]); + + $list = []; + foreach ($types as $t) { + $list[$t['id']] = $t['name']; + } + return $list; + } + + public function toArray() { + global $Strings; + if ($this->exists) { + return [ + "info" => [ + "id" => $this->getID(), + "machineid" => $this->getMachineID(), + "type" => $this->getTypeID(), + "date" => $this->getDate(), + "techuid" => $this->getTechUID(), + "publicnotes" => $this->getPublicNotes(), + "privatenotes" => $this->getPrivateNotes() + ], + "formdata" => [ + "types" => $this->getTypes(), + "inputtypes" => [ + "machineid" => "text", + "type" => "number", + "date" => "datetime", + "techuid" => "text", + "privatenotes" => "textarea", + "publicnotes" => "textarea" + ], + "labels" => [ + "machineid" => $Strings->get("Machine ID", false), + "type" => $Strings->get("Type", false), + "date" => $Strings->get("Date", false), + "techuid" => $Strings->get("Technician", false), + "privatenotes" => $Strings->get("Private Notes", false), + "publicnotes" => $Strings->get("Public Notes", false) + ], + "icons" => [] + ] + ]; + } + return []; + } + + public function jsonSerialize() { + return $this->toArray(); + } + + public function save() { + global $database; + if ($this->exists) { + $database->update("events", $this->event, ["historyid" => $this->id]); + } else { + $database->insert("events", $this->event); + $this->id = $database->id(); + $this->exists = true; + } + } + + public function getID(): string { + return $this->id . ""; + } + + public function getMachineID(): string { + if (!empty($this->event["machineid"])) { + return $this->event["machineid"]; + } + return ""; + } + + public function getTypeID(): int { + if (!empty($this->event["eventid"])) { + return $this->event["eventid"] * 1; + } + return 0; + } + + public function getName(): string { + return $this->getTypes()[$this->getTypeID()] ?? ""; + } + + public function getDate(): string { + if (!empty($this->event["date"])) { + return $this->event["date"]; + } + return ""; + } + + public function getTechUID(): string { + if (!empty($this->event["techuid"])) { + return $this->event["techuid"]; + } + return ""; + } + + public function getPublicNotes(): string { + if (!empty($this->event["publicnotes"])) { + return $this->event["publicnotes"]; + } + return ""; + } + + public function getPrivateNotes(): string { + if (!empty($this->event["privatenotes"])) { + return $this->event["privatenotes"]; + } + return ""; + } + + public function setMachineID($id) { + $this->event["machineid"] = $id; + } + + public function setTypeID(int $id) { + if (!empty($this->getTypes()[$id])) { + $this->event["eventid"] = $id; + } + } + + public function setTechUID($uid) { + $this->event["techuid"] = $uid; + } + + public function setDate(string $date) { + $this->event["date"] = date("Y-m-d H:i:s", strtotime($date)); + } + + public function setPrivateNotes(string $notes) { + $this->event["privatenotes"] = $notes; + } + + public function setPublicNotes(string $notes) { + $this->event["publicnotes"] = $notes; + } + +} diff --git a/lib/Machine.lib.php b/lib/Machine.lib.php index 170ca93..826de86 100644 --- a/lib/Machine.lib.php +++ b/lib/Machine.lib.php @@ -18,7 +18,10 @@ class Machine implements JsonSerializable { if (Machine::exists($machineid)) { $this->exists = true; $this->machine = $database->get('machines', ['model', 'condition', 'price', 'os', 'serial', 'manufacturer', 'clientid', 'privatenotes', 'publicnotes'], ['machineid' => $machineid]); - $this->events = $database->select('events', ['[>]event_types' => 'eventid'], ['historyid', 'date', 'event_types.eventname', 'techuid', 'privatenotes', 'publicnotes'], ['machineid' => $machineid, "ORDER" => ["date" => "DESC"]]); + $events = $database->select('events', 'historyid', ['machineid' => $machineid, "ORDER" => ["date" => "DESC"]]); + foreach ($events as $e) { + $this->events[] = new Event($e); + } $components = $database->select("components", "compid", ["machineid" => $machineid]); foreach ($components as $c) { $this->components[] = new Component($c); @@ -26,19 +29,52 @@ class Machine implements JsonSerializable { } } - public function jsonSerialize() { + public function toArray() { + global $Strings; if ($this->exists) { return [ "status" => "OK", "id" => $this->machineid, "info" => $this->machine, "events" => $this->events, - "components" => $this->components + "components" => $this->components, + "formdata" => [ + "options" => [ + "clientid" => Clients::getAllAsIDNameArray() + ], + "inputtypes" => [ + "model" => "text", + "condition" => "number", + "price" => "number", + "os" => "text", + "serial" => "text", + "manufacturer" => "text", + "clientid" => "select", + "privatenotes" => "textarea", + "publicnotes" => "textarea" + ], + "labels" => [ + "model" => $Strings->get("Model", false), + "condition" => $Strings->get("Condition", false), + "price" => $Strings->get("Price", false), + "os" => $Strings->get("OS/Software", false), + "serial" => $Strings->get("Serial", false), + "manufacturer" => $Strings->get("Manufacturer", false), + "clientid" => $Strings->get("Client", false), + "privatenotes" => $Strings->get("Private Notes", false), + "publicnotes" => $Strings->get("Public Notes", false) + ], + "icons" => [] + ] ]; } return []; } + public function jsonSerialize() { + return $this->toArray(); + } + public static function create(): Machine { return new Machine(Machine::generateId()); } @@ -204,22 +240,9 @@ class Machine implements JsonSerializable { } public function addEvent(string $date, int $event, string $techuid = "", string $publicnotes = "", string $privatenotes = "") { - global $database; - if (strtotime($date) === false) { - throw new Exception("Invalid date."); - } - $date = date("Y-m-d H:i:s", strtotime($date)); - if (!$database->has('event_types', ['eventid' => $event])) { - throw new Exception("Invalid event type."); - } - $event = (int) $event; - if (empty($publicnotes)) { - $publicnotes = ""; - } - if (empty($privatenotes)) { - $privatenotes = ""; - } - $database->insert('events', ['date' => $date, 'eventid' => $event, 'techuid' => $techuid, 'machineid' => $this->machineid, 'publicnotes' => $publicnotes, 'privatenotes' => $privatenotes]); + $evt = Event::create($this->machineid, $date, $event, $techuid, $publicnotes, $privatenotes); + + $this->events[] = $evt; } /** diff --git a/pages/viewmachine.php b/pages/viewmachine.php index 5750a8c..1dec957 100644 --- a/pages/viewmachine.php +++ b/pages/viewmachine.php @@ -96,13 +96,13 @@ $machine = new Machine($machineid); \n"; - echo "$h[eventname] on " . date($SETTINGS["datetime_format"], strtotime($h['date'])) . "
\n"; - echo "Technician: " . htmlspecialchars((new User($h['techuid']))->getName()) . "
\n"; - if (!empty($h['publicnotes'])) { - echo "
Public Notes:
" . htmlspecialchars($h['publicnotes']) . "
"; + echo "" . $h->getName() . " on " . date($SETTINGS["datetime_format"], strtotime($h->getDate())) . "
\n"; + echo "Technician: " . htmlspecialchars((new User($h->getTechUID()))->getName()) . "
\n"; + if (!empty($h->getPublicNotes())) { + echo "
Public Notes:
" . htmlspecialchars($h->getPublicNotes()) . "
"; } - if (!empty($h['privatenotes'])) { - echo "
Private Notes:
" . htmlspecialchars($h['privatenotes']) . "
"; + if (!empty($h->getPrivateNotes())) { + echo "
Private Notes:
" . htmlspecialchars($h->getPrivateNotes()) . "
"; } echo "\n\n"; } diff --git a/public/index.php b/public/index.php index 9e0dbe6..c8191db 100644 --- a/public/index.php +++ b/public/index.php @@ -321,9 +321,9 @@ if (isset($_GET["backgroundcolor"]) && !empty($_GET["backgroundcolor"]) && preg_ \n"; - echo "$h[eventname] on " . date($SETTINGS["datetime_format"], strtotime($h['date'])) . "
\n"; - if (!empty($h['publicnotes'])) { - echo "
Notes:
" . htmlspecialchars($h['publicnotes']) . "
"; + echo "" . $h->getName() . " on " . date($SETTINGS["datetime_format"], strtotime($h->getDate())) . "
\n"; + if (!empty($h->getPublicNotes())) { + echo "
Notes:
" . htmlspecialchars($h->getPublicNotes()) . "
"; } echo "\n\n"; } diff --git a/required.php b/required.php index 97cc2fc..788bcd7 100644 --- a/required.php +++ b/required.php @@ -106,7 +106,10 @@ try { 'server' => $SETTINGS['database']['server'], 'username' => $SETTINGS['database']['user'], 'password' => $SETTINGS['database']['password'], - 'charset' => $SETTINGS['database']['charset'] + 'charset' => $SETTINGS['database']['charset'], + 'option' => [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION + ] ]); } catch (Exception $ex) { //header('HTTP/1.1 500 Internal Server Error'); diff --git a/static/img/logo.png b/static/img/logo.png index 8c956b8..c916515 100644 Binary files a/static/img/logo.png and b/static/img/logo.png differ diff --git a/static/img/logo.svg b/static/img/logo.svg index 410fb09..6c9f6a4 100644 --- a/static/img/logo.svg +++ b/static/img/logo.svg @@ -14,11 +14,11 @@ viewBox="0 0 512.00001 512.00001" id="svg2" version="1.1" - inkscape:version="0.91 r13725" + inkscape:version="0.92.3 (2405546, 2018-03-11)" sodipodi:docname="logo.svg" - inkscape:export-filename="/home/skylar/Documents/Projects/Sources/WebAppTemplate/static/img/logo.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> + inkscape:export-filename="/home/skylar/Documents/Projects/Sources/Apps/Native/MachineManager/resources/icon.png" + inkscape:export-xdpi="384" + inkscape:export-ydpi="384"> + units="px" + inkscape:window-width="1920" + inkscape:window-height="1013" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" /> @@ -51,7 +56,7 @@ image/svg+xml - + @@ -69,10 +74,20 @@ y="540.36218" rx="50" ry="50" /> - + + + +