diff --git a/include/Ajax.php b/include/Ajax.php new file mode 100644 index 0000000..7496423 --- /dev/null +++ b/include/Ajax.php @@ -0,0 +1,349 @@ +<?php +class Ajax extends Responder { + private $action = ''; + + public function __construct() { + parent::__construct(); + if(isset($_GET['action'])) { + $this->action = $_GET['action']; + } + } + + public function render() { + $out = ''; + switch($this->action) { + default: + $out = new Success('ajax endpoint'); + break; + case 'getfragment': + $out = $this->get_fragment(); + break; + case 'checkout': + $out = $this->checkout_product(); + break; + case 'return': + $out = $this->return_product(); + break; + case 'extend': + $out = $this->extend_loan(); + break; + case 'startinventory': + $out = $this->start_inventory(); + break; + case 'endinventory': + $out = $this->end_inventory(); + break; + case 'inventoryproduct': + $out = $this->inventory_product(); + break; + case 'updateproduct': + $out = $this->update_product(); + break; + case 'updateuser': + $out = $this->update_user(); + break; + case 'savetemplate': + $out = $this->save_template(); + break; + case 'deletetemplate': + $out = $this->delete_template(); + break; + case 'suggest': + $out = $this->suggest(); + break; + case 'discardproduct': + $out = $this->discard_product(); + break; + } + print($out->toJson()); + } + + private function get_fragment() { + $fragment = $_POST['fragment']; + if(isset($this->fragments[$fragment])) { + return new Success($this->fragments[$fragment]); + } + return new Failure("Ogiltigt fragment '$fragment'"); + } + + private function checkout_product() { + $user = new User($_POST['user'], 'name'); + $product = null; + try { + $product = new Product($_POST['product'], 'serial'); + } catch(Exception $e) { + return new Failure('Ogiltigt serienummer.'); + } + try { + $user->create_loan($product, $_POST['end']); + return new Success($product->get_name() . 'utlånad.'); + } catch(Exception $e) { + return new Failure('Artikeln är redan utlånad.'); + } + } + + private function return_product() { + $product = null; + try { + $product = new Product($_POST['serial'], 'serial'); + } catch(Exception $e) { + return new Failure('Ogiltigt serienummer.'); + } + $loan = $product->get_active_loan(); + if($loan) { + $loan->end(); + $user = $loan->get_user(); + $userlink = replace(array('page' => 'users', + 'id' => $user->get_id(), + 'name' => $user->get_displayname()), + $this->fragments['item_link']); + $productlink = replace(array('page' => 'products', + 'id' => $product->get_id(), + 'name' => $product->get_name()), + $this->fragments['item_link']); + $user = $loan->get_user(); + return new Success($productlink . ' åter från ' . $userlink); + } + return new Failure('Artikeln är inte utlånad.'); + } + + private function extend_loan() { + $product = null; + try { + $product = new Product($_POST['product']); + } catch(Exception $e) { + return new Failure('Ogiltigt ID.'); + } + $loan = $product->get_active_loan(); + if($loan) { + $loan->extend($_POST['end']); + return new Success('Lånet förlängt'); + } + return new Failure('Lån saknas.'); + } + + private function start_inventory() { + try { + Inventory::begin(); + return new Success('Inventering startad.'); + } catch(Exception $e) { + return new Failure('Inventering redan igång.'); + } + } + + private function end_inventory() { + $inventory = Inventory::get_active(); + if($inventory === null) { + return new Failure('Ingen inventering pågår.'); + } + $inventory->end(); + return new Success('Inventering avslutad.'); + } + + private function inventory_product() { + $inventory = Inventory::get_active(); + if($inventory === null) { + return new Failure('Ingen inventering pågår.'); + } + $product = null; + try { + $product = new Product($_POST['serial'], 'serial'); + } catch(Exception $e) { + return new Failure('Ogiltigt serienummer.'); + } + $result = $inventory->add_product($product); + if(!$result) { + return new Failure('Artikeln är redan registrerad.'); + } + return new Success('Artikeln registrerad.'); + } + + private function update_product() { + $info = $_POST; + $id = $info['id']; + $name = $info['name']; + $serial = $info['serial']; + $invoice = $info['invoice']; + $tags = array(); + if(isset($info['tag'])) { + $tags = $this->unescape_tags($info['tag']); + } + foreach(array('id', 'name', 'serial', 'invoice', 'tag') as $key) { + unset($info[$key]); + } + if(!$name) { + return new Failure('Artikeln måste ha ett namn.'); + } + if(!$serial) { + return new Failure('Artikeln måste ha ett serienummer.'); + } + if(!$invoice) { + return new Failure('Artikeln måste ha ett fakturanummer.'); + } + $product = null; + if(!$id) { + try { + $temp = new Product($serial, 'serial'); + return new Failure( + 'Det angivna serienumret finns redan på en annan artikel.'); + } catch(Exception $e) {} + try { + $product = Product::create_product($name, + $invoice, + $serial, + $info, + $tags); + $prodlink = replace(array('page' => 'products', + 'id' => $product->get_id(), + 'name' => $product->get_name()), + $this->fragments['item_link']); + return new Success("Artikeln '$prodlink' sparad."); + } catch(Exception $e) { + return new Failure($e->getMessage()); + } + } + $product = new Product($id); + if($product->get_discardtime()) { + return new Failure('Skrotade artiklar får inte modifieras.'); + } + if($name != $product->get_name()) { + $product->set_name($name); + } + if($serial != $product->get_serial()) { + try { + $product->set_serial($serial); + } catch(Exception $e) { + return new Failure('Det angivna serienumret finns redan på en annan artikel.'); + } + } + if($invoice != $product->get_invoice()) { + $product->set_invoice($invoice); + } + foreach($product->get_info() as $key => $prodvalue) { + if(!isset($info[$key]) || !$info[$key]) { + $product->remove_info($key); + continue; + } + if($prodvalue != $info[$key]) { + $product->set_info($key, $info[$key]); + } + unset($info[$key]); + } + foreach($info as $key => $invalue) { + if($invalue) { + $product->set_info($key, $invalue); + } + } + foreach($product->get_tags() as $tag) { + if(!in_array($tag, $tags)) { + $product->remove_tag($tag); + continue; + } + unset($tags[array_search($tag, $tags)]); + } + foreach($tags as $tag) { + $product->add_tag($tag); + } + return new Success('Ändringarna sparade.'); + } + + private function update_user() { + $id = $_POST['id']; + $name = $_POST['name']; + $notes = $_POST['notes']; + if(!$name) { + return new Failure('Användarnamnet får inte vara tomt.'); + } + $user = new User($id); + if($user->get_name() != $name) { + $user->set_name($name); + } + if($user->get_notes() != $notes) { + $user->set_notes($notes); + } + return new Success('Ändringarna sparade.'); + } + + private function save_template() { + $info = $_POST; + $name = $info['template']; + $tags = array(); + if(isset($info['tag'])) { + $tags = $this->unescape_tags($info['tag']); + } + foreach(array('template', + 'id', + 'name', + 'serial', + 'invoice', + 'tags') as $key) { + unset($info[$key]); + } + if(!$name) { + return new Failure('Mallen måste ha ett namn.'); + } + $template = null; + try { + $template = new Template($name, 'name'); + } catch(Exception $e) { + $template = Template::create_template($name, $info, $tags); + $name = $template->get_name(); + return new Success( + "Aktuella fält och taggar har sparats till mallen '$name'."); + } + foreach($template->get_fields() as $field) { + if(!isset($info[$field])) { + $template->remove_field($field); + } + } + $existingfields = $template->get_fields(); + foreach($info as $field) { + if(!in_array($field, $existingfields)) { + $template->add_field($field); + } + } + foreach($template->get_tags() as $tag) { + if(!in_array($tag, $tags)) { + $template->remove_tag($tag); + } + } + $existingtags = $template->get_tags(); + foreach($tags as $tag) { + if(!in_array($tag, $existingtags)) { + $template->add_tag($tag); + } + } + $name = $template->get_name(); + return new Success("Mallen '$name' uppdaterad."); + } + + private function delete_template() { + try { + $template = $_POST['template']; + Template::delete_template($template); + $name = ucfirst(strtolower($template)); + return new Success("Mallen '$name' har raderats."); + } catch(Exception $e) { + return new Failure('Det finns ingen mall med det namnet.'); + } + } + + private function suggest() { + return new Success(suggest($_POST['type'])); + } + + private function discard_product() { + $product = new Product($_POST['id']); + if(!$product->get_discardtime()) { + if($product->get_active_loan()) { + return new Failure('Artikeln har ett aktivt lån.<br/>' + .'Lånet måste avslutas innan artikeln skrotas.'); + } + $product->discard(); + return new Success('Artikeln skrotad.'); + } else { + return new Failure('Artikeln är redan skrotad.'); + } + } +} +?> diff --git a/include/CheckoutPage.php b/include/CheckoutPage.php new file mode 100644 index 0000000..f0fa652 --- /dev/null +++ b/include/CheckoutPage.php @@ -0,0 +1,58 @@ +<?php +class CheckoutPage extends Page { + private $userstr = ''; + private $user = null; + + public function __construct() { + parent::__construct(); + if(isset($_GET['user'])) { + $this->userstr = $_GET['user']; + try { + $this->user = new User($this->userstr, 'name'); + } catch(Exception $ue) { + try { + $ldap = new Ldap(); + $ldap->get_user($this->userstr); + $this->user = User::create_user($this->userstr); + } catch(Exception $le) { + $this->error = "Användarnamnet '"; + $this->error .= $this->userstr; + $this->error .= "' kunde inte hittas."; + } + } + } + } + + protected function render_body() { + $username = ''; + $displayname = ''; + $notes = ''; + $loan_table = ''; + $subhead = ''; + $enddate = ''; + $disabled = 'disabled'; + if($this->user !== null) { + $username = $this->user->get_name(); + $displayname = $this->user->get_displayname(); + $notes = $this->user->get_notes(); + $enddate = gmdate('Y-m-d', time() + 604800); # 1 week from now + $disabled = ''; + $loans = $this->user->get_loans('active'); + $loan_table = 'Inga pågående lån.'; + if($loans) { + $loan_table = $this->build_user_loan_table($loans, 'renew'); + } + $subhead = replace(array('title' => 'Lånade artiklar'), + $this->fragments['subtitle']); + } + print(replace(array('user' => $this->userstr, + 'displayname' => $displayname, + 'notes' => $notes, + 'end' => $enddate, + 'subtitle' => $subhead, + 'disabled' => $disabled, + 'loan_table' => $loan_table), + $this->fragments['checkout_page'])); + } +} +?> diff --git a/include/Failure.php b/include/Failure.php new file mode 100644 index 0000000..95145d3 --- /dev/null +++ b/include/Failure.php @@ -0,0 +1,7 @@ +<?php +class Failure extends Result { + public function __construct($message) { + parent::__construct('error', $message); + } +} +?> diff --git a/include/HistoryPage.php b/include/HistoryPage.php new file mode 100644 index 0000000..77eb0cd --- /dev/null +++ b/include/HistoryPage.php @@ -0,0 +1,80 @@ +<?php +class HistoryPage extends Page { + private $action = 'list'; + private $inventory = null; + + public function __construct() { + parent::__construct(); + if(isset($_GET['action'])) { + $this->action = $_GET['action']; + } + if(isset($_GET['id'])) { + try { + $this->inventory = new Inventory($_GET['id']); + } catch(Exception $e) { + $this->inventory = null; + $this->action = 'list'; + $this->error = 'Det finns ingen inventering med det ID-numret.'; + } + } + switch($this->action) { + case 'show': + $this->subtitle = 'Inventeringsdetaljer'; + break; + case 'list': + $this->subtitle = 'Genomförda inventeringar'; + break; + } + } + + protected function render_body() { + switch($this->action) { + case 'list': + print($this->build_inventory_table()); + print(replace(array('title' => 'Skrotade artiklar'), + $this->fragments['title'])); + $discards = get_items('product_discarded'); + if($discards) { + print($this->build_product_table($discards)); + } else { + print('Inga artiklar skrotade.'); + } + break; + case 'show': + if($this->inventory && + Inventory::get_active() !== $this->inventory) { + print($this->build_inventory_details($this->inventory, + false)); + } + break; + } + } + + private function build_inventory_table() { + $items = get_items('inventory_old'); + if(!$items) { + return 'Inga inventeringar gjorda.'; + } + $rows = ''; + foreach($items as $inventory) { + $id = $inventory->get_id(); + $inventory_link = replace(array('id' => $id, + 'name' => $id, + 'page' => 'history'), + $this->fragments['item_link']); + $duration = $inventory->get_duration(); + $num_seen = count($inventory->get_seen_products()); + $num_unseen = count($inventory->get_unseen_products()); + $rows .= replace(array('item_link' => $inventory_link, + 'start_date' => $duration['start'], + 'end_date' => $duration['end'], + 'num_seen' => $num_seen, + 'num_unseen' => $num_unseen), + $this->fragments['inventory_row']); + } + return replace(array('item' => 'Tillfälle', + 'rows' => $rows), + $this->fragments['inventory_table']); + } +} +?> diff --git a/include/Inventory.php b/include/Inventory.php new file mode 100644 index 0000000..6d45589 --- /dev/null +++ b/include/Inventory.php @@ -0,0 +1,141 @@ +<?php +class Inventory { + private $id = ''; + private $starttime = ''; + private $endtime = null; + private $seen_products = array(); + + public static function begin() { + if(Inventory::get_active() !== null) { + throw new Exception('Inventory already in progress.'); + } + $now = time(); + $start = prepare('insert into `inventory`(`starttime`) values (?)'); + bind($start, 'i', $now); + execute($start); + $invid = $start->insert_id; + $prodid = ''; + $register = prepare('insert into + `inventory_product`(`inventory`, `product`) + values (?, ?)'); + foreach(get_items('loan_active') as $loan) { + $prodid = $loan->get_product()->get_id(); + bind($register, 'ii', $invid, $prodid); + execute($register); + } + return new Inventory($invid); + } + + public static function get_active() { + $search = prepare('select * from `inventory` where `endtime` is null'); + execute($search); + $result = result_single($search); + if($result === null) { + return null; + } + return new Inventory($result['id']); + } + + public function __construct($id) { + $search = prepare('select `id` from `inventory` where `id`=?'); + bind($search, 'i', $id); + execute($search); + $result = result_single($search); + if($result === null) { + throw new Exception('Invalid id'); + } + $this->id = $result['id']; + $this->update_fields(); + } + + private function update_fields() { + $get = prepare('select * from `inventory` where `id`=?'); + bind($get, 'i', $this->id); + execute($get); + $result = result_single($get); + $this->starttime = $result['starttime']; + $this->endtime = $result['endtime']; + $prodget = prepare('select * from `inventory_product` + where `inventory`=?'); + bind($prodget, 'i', $this->id); + execute($prodget); + foreach(result_list($prodget) as $row) { + $this->seen_products[] = $row['product']; + } + } + + public function end() { + $now = time(); + $update = prepare('update `inventory` set `endtime`=? + where `id`=? and `endtime` is null'); + bind($update, 'ii', $now, $this->id); + execute($update); + $this->endtime = $now; + return true; + } + + public function add_product($product) { + $add = prepare('insert into `inventory_product`(`inventory`, `product`) + values (?, ?)'); + bind($add, 'ii', $this->id, $product->get_id()); + try { + execute($add); + } catch(Exception $e) { + return false; + } + $this->products[] = $product->get_id(); + return true; + } + + public function get_id() { + return $this->id; + } + + public function get_duration($format = true) { + $style = function($time) { + return $time; + }; + if($format) { + $style = function($time) { + return gmdate('Y-m-d', $time); + }; + } + return array('start' => $style($this->starttime), + 'end' => $style($this->endtime)); + } + + public function get_seen_products() { + $out = array(); + foreach($this->seen_products as $prodid) { + $out[] = new Product($prodid); + } + return $out; + } + + public function get_unseen_products() { + $all = get_items('product'); + $out = array(); + $include = function($product) { + if(!in_array($product->get_id(), $this->seen_products)) { + return true; + } + return false; + }; + if($this->endtime) { + $include = function($product) { + if($product->get_createtime() < $this->endtime + && !in_array($product->get_id(), $this->seen_products)) { + return true; + } + return false; + }; + } + foreach($all as $product) { + if($include($product)) { + $out[] = $product; + } + } + return $out; + } +} +?> diff --git a/include/InventoryPage.php b/include/InventoryPage.php new file mode 100644 index 0000000..2e3320a --- /dev/null +++ b/include/InventoryPage.php @@ -0,0 +1,18 @@ +<?php +class InventoryPage extends Page { + private $inventory = null; + + public function __construct() { + parent::__construct(); + $this->inventory = Inventory::get_active(); + } + + protected function render_body() { + if($this->inventory === null) { + print($this->fragments['inventory_start']); + return; + } + print($this->build_inventory_details($this->inventory)); + } +} +?> diff --git a/include/Kvs.php b/include/Kvs.php new file mode 100644 index 0000000..e80edf8 --- /dev/null +++ b/include/Kvs.php @@ -0,0 +1,56 @@ +<?php +class Kvs { + private $items = array(); + + public function __construct() { + $get = prepare('select * from `kvs`'); + execute($get); + foreach(result_list($get) as $row) { + $key = $row['key']; + $value = $row['value']; + $this->items[$key] = $value; + } + } + + public function get_keys() { + return array_keys($this->items); + } + + public function get_value($key) { + if(isset($this->items[$key])) { + return $this->items[$key]; + } + return null; + } + + public function set_key($key, $value) { + $find = prepare('select * from `kvs` where `key`=?'); + bind($find, 's', $key); + execute($find); + if(result_single($find) === null) { + $update = prepare('insert into `kvs`(`value`, `key`) + values (?, ?)'); + } else { + $update = prepare('update `kvs` set `value`=? where `key`=?'); + } + bind($update, 'ss', $value, $key); + execute($update); + $this->items[$key] = $value; + return true; + } + + public function remove_key($key) { + $find = prepare('select * from `kvs` where `key`=?'); + bind($find, 's', $key); + execute($find); + if(result_single($find) === null) { + return true; + } + $update = prepare('delete from `kvs` where `key`=?'); + bind($update, 's', $key); + execute($update); + unset($this->items[$key]); + return true; + } +} +?> diff --git a/include/ldap.php b/include/Ldap.php similarity index 98% rename from include/ldap.php rename to include/Ldap.php index e2fef8d..91c7c84 100644 --- a/include/ldap.php +++ b/include/Ldap.php @@ -1,5 +1,4 @@ <?php - class Ldap { private $conn; private $base_dn = "dc=su,dc=se"; @@ -42,6 +41,4 @@ class Ldap { return $out; } } - -$ldap = new Ldap(); ?> diff --git a/include/Loan.php b/include/Loan.php new file mode 100644 index 0000000..87d57d7 --- /dev/null +++ b/include/Loan.php @@ -0,0 +1,93 @@ +<?php +class Loan { + private $id = 0; + private $user = 0; + private $product = 0; + private $starttime = 0; + private $endtime = 0; + private $returntime = null; + + public function __construct($id) { + $this->id = $id; + $this->update_fields(); + } + + private function update_fields() { + $get = prepare('select * from `loan` where `id`=?'); + bind($get, 'i', $this->id); + execute($get); + $loan = result_single($get); + $this->user = $loan['user']; + $this->product = $loan['product']; + $this->starttime = $loan['starttime']; + $this->endtime = $loan['endtime']; + $this->returntime = $loan['returntime']; + } + + public function get_id() { + return $this->id; + } + + public function get_user() { + return new User($this->user); + } + + public function get_product() { + return new Product($this->product); + } + + public function get_duration($format = true) { + $style = function($time) { + return $time; + }; + if($format) { + $style = function($time) { + if($time) { + return gmdate('Y-m-d', $time); + } + return $time; + }; + } + return array('start' => $style($this->starttime), + 'end' => $style($this->endtime), + 'end_renew' => $style($this->endtime + 604800), # +1 week + 'return' => $style($this->returntime)); + } + + public function is_active() { + if($this->returntime === null) { + return true; + } + return false; + } + + public function extend($time) { + $ts = strtotime($time . ' 13:00'); + $query = prepare('update `loan` set `endtime`=? where `id`=?'); + bind($query, 'ii', $ts, $this->id); + execute($query); + $this->endtime = $ts; + return true; + } + + public function end() { + $now = time(); + $query = prepare('update `loan` set `returntime`=? where `id`=?'); + bind($query, 'ii', $now, $this->id); + execute($query); + $this->returntime = $now; + return true; + } + + public function is_overdue() { + if($this->returntime !== null) { + return false; + } + $now = time(); + if($now > $this->endtime) { + return true; + } + return false; + } +} +?> diff --git a/include/Page.php b/include/Page.php new file mode 100644 index 0000000..e50799c --- /dev/null +++ b/include/Page.php @@ -0,0 +1,306 @@ +<?php +abstract class Page extends Responder { + protected abstract function render_body(); + + protected $page = 'checkout'; + protected $title = "DSV Utlåning"; + protected $subtitle = ''; + protected $error = null; + protected $menuitems = array('checkout' => 'Låna', + 'return' => 'Lämna', + 'products' => 'Artiklar', + 'users' => 'Låntagare', + 'inventory' => 'Inventera', + 'history' => 'Historik', + 'search' => 'Sök'); + private $template_parts = array(); + + public function __construct() { + parent::__construct(); + $this->template_parts = get_fragments('./html/base.html'); + + if(isset($_GET['page'])) { + $this->page = $_GET['page']; + } + if(isset($this->menuitems[$this->page])) { + $this->subtitle = $this->menuitems[$this->page]; + } + } + + public function render() { + $this->render_head(); + $this->render_body(); + if($this->error) { + $this->render_error(); + } + $this->render_foot(); + } + + final private function render_head() { + $headtitle = $this->title; + $pagetitle = $this->title; + if($this->subtitle) { + $headtitle .= ' - '. $this->subtitle; + $pagetitle = $this->subtitle; + } + $query = ''; + if(isset($_GET['q'])) { + $query = $_GET['q']; + } + print(replace( + array('title' => $headtitle, + 'menu' => $this->build_menu(), + 'query'=> $query), + $this->template_parts['head'] + )); + print(replace(array('title' => $pagetitle), + $this->fragments['title'])); + } + + private function build_menu() { + $menu = ''; + foreach($this->menuitems as $page => $title) { + $align = 'left'; + $active = ''; + if($this->page == $page) { + $active = 'active'; + } + if($page == 'search') { + $align = 'right'; + } + $menu .= replace(array('title' => $title, + 'page' => $page, + 'align' => $align, + 'active' => $active), + $this->template_parts['menuitem']); + } + return $menu; + } + + final private function render_error() { + print(replace(array('type' => 'error', + 'message' => $this->error), + $this->fragments['message'])); + } + + final private function render_foot() { + print($this->template_parts['foot']); + } + + final protected function build_user_table($users) { + $rows = ''; + foreach($users as $user) { + $replacements = array('name' => '', + 'loan' => '', + 'has_notes' => '', + 'notes' => '', + 'item_link' => ''); + $replacements['name'] = $user->get_name(); + $notes = $user->get_notes(); + if($notes) { + $replacements['notes'] = $notes; + $replacements['has_notes'] = '*'; + } + $userlink = replace(array('id' => $user->get_id(), + 'name' => $user->get_displayname(), + 'page' => 'users'), + $this->fragments['item_link']); + $replacements['item_link'] = $userlink; + $loans = $user->get_loans('active'); + $loan_str = ''; + $count = count($loans); + switch($count) { + case 0: + break; + case 1: + $product = $loans[0]->get_product(); + $loan_str = $product->get_name(); + break; + default: + $loan_str = $count .' artiklar'; + break; + } + $replacements['loan'] = $loan_str; + $rows .= replace($replacements, $this->fragments['user_row']); + } + return replace(array('rows' => $rows), + $this->fragments['user_table']); + } + + final protected function build_product_table($products) { + $rows = ''; + foreach($products as $product) { + $prodlink = replace(array('id' => $product->get_id(), + 'name' => $product->get_name(), + 'page' => 'products'), + $this->fragments['item_link']); + $available = 'Tillgänglig'; + $status = 'available'; + $discarded = $product->get_discardtime(); + if($discarded) { + $available = 'Skrotad '.$discarded; + $status = 'discarded'; + } else { + $loan = $product->get_active_loan(); + if($loan) { + $user = $loan->get_user(); + $userlink = replace(array('name' => $user->get_displayname(), + 'id' => $user->get_id(), + 'page' => 'users'), + $this->fragments['item_link']); + $available = 'Utlånad till '.$userlink; + if($loan->is_overdue()) { + $status = 'overdue'; + $available .= ', försenad'; + } else { + $status = 'on_loan'; + $available .= ', åter '.$loan->get_duration()['end']; + } + } + } + $rows .= replace(array('available' => $available, + 'status' => $status, + 'item_link' => $prodlink), + $this->fragments['product_row']); + } + return replace(array('rows' => $rows), + $this->fragments['product_table']); + } + + final protected function build_user_loan_table($loans, $show = 'none') { + $vis_return = 'hidden'; + $vis_renew = 'hidden'; + switch($show) { + case 'return': + $vis_return = ''; + break; + case 'renew': + $vis_renew = ''; + break; + case 'both': + $vis_return = ''; + $vis_renew = ''; + break; + case 'none': + break; + default: + throw new Exception('Invalid argument.'); + } + $rows = ''; + foreach($loans as $loan) { + $product = $loan->get_product(); + $prodlink = replace(array('id' => $product->get_id(), + 'name' => $product->get_name(), + 'page' => 'products'), + $this->fragments['item_link']); + $available = ''; + $duration = $loan->get_duration(); + $status = 'on_loan'; + if($loan->is_overdue()) { + $status = 'overdue'; + } + $returndate = ''; + if($duration['return'] !== null) { + $returndate = $duration['return']; + } + $rows .= replace(array('id' => $product->get_id(), + 'item_link' => $prodlink, + 'start_date' => $duration['start'], + 'end_date' => $duration['end'], + 'return_date' => $returndate, + 'status' => $status, + 'vis_renew' => $vis_renew, + 'vis_return' => $vis_return, + 'end_new' => $duration['end_renew']), + $this->fragments['loan_row']); + } + return replace(array('rows' => $rows, + 'vis_renew' => $vis_renew, + 'vis_return' => $vis_return, + 'item' => 'Artikel'), + $this->fragments['loan_table']); + } + + final protected function build_product_loan_table($loans) { + $rows = ''; + $renew_column_visible = 'hidden'; + foreach($loans as $loan) { + $user = $loan->get_user(); + $product = $loan->get_product(); + $userlink = replace(array('id' => $user->get_id(), + 'name' => $user->get_name(), + 'page' => 'users'), + $this->fragments['item_link']); + $available = ''; + $duration = $loan->get_duration(); + $status = 'on_loan'; + if($loan->is_overdue()) { + $status = 'overdue'; + } + $returndate = ''; + $renew_visible = ''; + if($duration['return']) { + $returndate = $duration['return']; + $renew_visible = 'hidden'; + } else { + $renew_column_visible = ''; + } + $rows .= replace(array('item_link' => $userlink, + 'start_date' => $duration['start'], + 'end_date' => $duration['end'], + 'return_date' => $returndate, + 'status' => $status, + 'vis_renew' => $renew_column_visible, + 'vis_renew_button' => $renew_visible, + 'vis_return' => '', + 'id' => $product->get_id(), + 'end_new' => $duration['end_renew']), + $this->fragments['loan_row']); + } + return replace(array('rows' => $rows, + 'vis_renew' => $renew_column_visible, + 'vis_return' => '', + 'item' => 'Låntagare'), + $this->fragments['loan_table']); + } + + final protected function build_inventory_details($inventory, + $interactive = true) { + $duration = $inventory->get_duration(); + $all_products = get_items('product'); + $seen = $inventory->get_seen_products(); + $unseen = array(); + foreach($all_products as $product) { + if(!in_array($product, $seen)) { + $unseen[] = $product; + } + } + $missing = 'Saknade artiklar'; + $hidden = 'hidden'; + if($interactive) { + $missing = 'Kvarvarande artiklar'; + $hidden = ''; + } + $out = replace(array('start_date' => $duration['start'], + 'total_count' => count($all_products), + 'seen_count' => count($seen), + 'hide' => $hidden), + $this->fragments['inventory_do']); + $out .= replace(array('title' => $missing), + $this->fragments['subtitle']); + if($unseen) { + $out .= $this->build_product_table($unseen); + } else { + $out .= 'Inga artiklar saknas.'; + } + $out .= replace(array('title' => 'Inventerade artiklar'), + $this->fragments['subtitle']); + if($seen) { + $out .= $this->build_product_table($seen); + } else { + $out .= 'Inga artiklar inventerade.'; + } + return $out; + } +} +?> diff --git a/include/Printer.php b/include/Printer.php new file mode 100644 index 0000000..1b3a8e2 --- /dev/null +++ b/include/Printer.php @@ -0,0 +1,18 @@ +<?php +class Printer extends QR { + public function __construct() { + parent::__construct(); + } + + public function render() { + $label = replace(array('id' => $this->product->get_id(), + 'name' => $this->product->get_name(), + 'serial' => $this->product->get_serial()), + $this->fragments['product_label']); + $title = 'Etikett för artikel '.$this->product->get_serial(); + print(replace(array('title' => $title, + 'label' => $label), + $this->fragments['label_page'])); + } +} +?> diff --git a/include/Product.php b/include/Product.php new file mode 100644 index 0000000..0b8a806 --- /dev/null +++ b/include/Product.php @@ -0,0 +1,318 @@ +<?php +class Product { + private $id = 0; + private $name = ''; + private $invoice = ''; + private $serial = ''; + private $createtime = null; + private $discardtime = null; + private $info = array(); + private $tags = array(); + + public static function create_product( + $name = '', + $invoice = '', + $serial = '', + $info = array(), + $tags = array() + ) { + $now = time(); + begin_trans(); + try { + $stmt = 'insert into + `product`(`name`, `invoice`, `serial`, `createtime`) + values (?, ?, ?, ?)'; + $ins_prod = prepare($stmt); + bind($ins_prod, 'sssi', $name, $invoice, $serial, $now); + execute($ins_prod); + $product = new Product($serial, 'serial'); + foreach($info as $field => $value) { + $product->set_info($field, $value); + } + foreach($tags as $tag) { + $product->add_tag($tag); + } + commit_trans(); + return $product; + } catch(Exception $e) { + revert_trans(); + throw $e; + } + } + + public function __construct($clue, $type = 'id') { + $search = null; + switch($type) { + case 'id': + $search = prepare('select `id` from `product` + where `id`=?'); + bind($search, 'i', $clue); + break; + case 'serial': + $search = prepare('select `id` from `product` + where `serial`=?'); + bind($search, 's', $clue); + break; + default: + throw new Exception('Invalid type.'); + } + execute($search); + $result = result_single($search); + if($result === null) { + throw new Exception('Product does not exist..'); + } + $this->id = $result['id']; + $this->update_fields(); + $this->update_info(); + $this->update_tags(); + } + + private function update_fields() { + $get = prepare('select * from `product` where `id`=?'); + bind($get, 'i', $this->id); + execute($get); + $product = result_single($get); + $this->name = $product['name']; + $this->invoice = $product['invoice']; + $this->serial = $product['serial']; + $this->createtime = $product['createtime']; + $this->discardtime = $product['discardtime']; + return true; + } + + private function update_info() { + $get = prepare('select * from `product_info` + where `product`=? order by `field`'); + bind($get, 'i', $this->id); + execute($get); + foreach(result_list($get) as $row) { + $field = $row['field']; + $data = $row['data']; + $this->info[$field] = $data; + } + return true; + } + + private function update_tags() { + $get = prepare('select * from `product_tag` + where `product`=? order by `tag`'); + bind($get, 'i', $this->id); + execute($get); + $newtags = array(); + foreach(result_list($get) as $row) { + $newtags[] = $row['tag']; + } + $this->tags = $newtags; + return true; + } + + public function matches($terms) { + foreach($terms as $field => $values) { + $matchvalues = array(); + if(property_exists($this, $field)) { + $matchvalues[] = $this->$field; + } else if(array_key_exists($field, $this->get_info())) { + $matchvalues[] = $this->get_info()[$field]; + } else { + switch($field) { + case 'tag': + $matchvalues = $this->get_tags(); + case 'status': + $matchvalues[] = $this->get_loan_status(); + case 'fritext': + $matchvalues[] = $this->name; + $matchvalues[] = $this->serial; + $matchvalues[] = $this->invoice; + $matchvalues = array_merge($matchvalues, + $this->get_tags(), + array_values( + $this->get_info())); + } + } + if(!match($values, $matchvalues)) { + return false; + } + } + return true; + } + + public function get_id() { + return $this->id; + } + + public function get_createtime() { + return $this->createtime; + } + + public function get_discardtime($format = true) { + if($this->discardtime && $format) { + return gmdate('Y-m-d', $this->discardtime); + } + return $this->discardtime; + } + + public function discard() { + $now = time(); + $update = prepare('update `product` set `discardtime`=? where `id`=?'); + bind($update, 'ii', $now, $this->id); + execute($update); + $this->discardtime = $now; + return true; + } + + public function get_name() { + return $this->name; + } + + public function set_name($newname) { + $update = prepare('update `product` set `name`=? where `id`=?'); + bind($update, 'si', $newname, $this->id); + execute($update); + $this->name = $newname; + return true; + } + + public function get_invoice() { + return $this->invoice; + } + + public function set_invoice($newinvoice) { + $update = prepare('update `product` set `invoice`=? where `id`=?'); + bind($update, 'si', $newinvoice, $this->id); + execute($update); + $this->invoice = $newinvoice; + return true; + } + + public function get_serial() { + return $this->serial; + } + + public function set_serial($newserial) { + $update = prepare('update `product` set `serial`=? where `id`=?'); + bind($update, 'si', $newserial, $this->id); + execute($update); + $this->serial = $newserial; + return true; + } + + public function get_info() { + return $this->info; + } + + public function set_info($field, $value) { + if(!$value) { + return true; + } + $find = prepare('select * from `product_info` + where `product`=? and `field`=?'); + bind($find, 'is', $this->id, $field); + execute($find); + if(result_single($find) === null) { + $update = prepare('insert into + `product_info`(`data`, `product`, `field`) + values (?, ?, ?)'); + } else { + $update = prepare('update `product_info` set `data`=? + where `product`=? and `field`=?'); + } + bind($update, 'sis', $value, $this->id, $field); + execute($update); + $this->update_info(); + return true; + } + + public function remove_info($field) { + $find = prepare('select * from `product_info` + where `product`=? and `field`=?'); + bind($find, 'is', $this->id, $field); + execute($find); + if(result_single($find) === null) { + return true; + } + $update = prepare('delete from `product_info` + where `field`=? and `product`=?'); + bind($update, 'si', $field, $this->id); + execute($update); + $this->update_info(); + return true; + } + + public function get_tags() { + return $this->tags; + } + + public function add_tag($tag) { + if(!$tag) { + return true; + } + $find = prepare('select * from `product_tag` + where `product`=? and `tag`=?'); + bind($find, 'is', $this->id, $tag); + execute($find); + if(result_single($find) === null) { + $update = prepare('insert into `product_tag`(`tag`, `product`) + values (?, ?)'); + bind($update, 'si', $tag, $this->id); + execute($update); + $this->update_tags(); + } + return true; + } + + public function remove_tag($tag) { + $find = prepare('select * from `product_tag` + where `product`=? and `tag`=?'); + bind($find, 'is', $this->id, $tag); + execute($find); + if(result_single($find) === null) { + return true; + } + $update = prepare('delete from `product_tag` + where `tag`=? and `product`=?'); + bind($update, 'si', $tag, $this->id); + execute($update); + $this->update_tags(); + return true; + } + + public function get_loan_status() { + if($this->get_discardtime(false)) { + return 'discarded'; + } + $loan = $this->get_active_loan(); + if(!$loan) { + return 'no_loan'; + } + if($loan->is_overdue()) { + return 'overdue'; + } + return 'on_loan'; + } + + public function get_active_loan() { + $find = prepare('select `id` from `loan` + where `returntime` is null and product=?'); + bind($find, 'i', $this->id); + execute($find); + $result = result_single($find); + if($result === null) { + return null; + } + return new Loan($result['id']); + } + + public function get_loan_history() { + $find = prepare('select `id` from `loan` + where product=? order by `starttime` desc'); + bind($find, 'i', $this->id); + execute($find); + $loans = result_list($find); + $out = array(); + foreach($loans as $loan) { + $out[] = new Loan($loan['id']); + } + return $out; + } +} +?> diff --git a/include/ProductPage.php b/include/ProductPage.php new file mode 100644 index 0000000..ae26645 --- /dev/null +++ b/include/ProductPage.php @@ -0,0 +1,133 @@ +<?php +class ProductPage extends Page { + private $action = 'list'; + private $template = null; + private $product = null; + + public function __construct() { + parent::__construct(); + if(isset($_GET['action'])) { + $this->action = $_GET['action']; + } + if(isset($_GET['template'])) { + $template = $_GET['template']; + if($template) { + try { + $this->template = new Template($template, 'name'); + } catch(Exception $e) { + $this->template = null; + $this->error = 'Det finns ingen mall med det namnet.'; + } + } + } + if(isset($_GET['id'])) { + $id = $_GET['id']; + if($id) { + try { + $this->product = new Product($id); + } catch(Exception $e) { + $this->action = 'list'; + $this->product = null; + $this->error = 'Det finns ingen artikel med det ID-numret.'; + } + } + } + switch($this->action) { + case 'show': + $this->subtitle = 'Artikeldetaljer'; + break; + case 'new': + $this->subtitle = 'Ny artikel'; + break; + case 'list': + $this->subtitle = 'Artikellista'; + break; + } + } + + protected function render_body() { + switch($this->action) { + case 'list': + print($this->fragments['create_product']); + print($this->build_product_table(get_items('product'))); + break; + case 'show': + print($this->build_product_details()); + break; + case 'new': + print($this->build_new_page()); + break; + } + } + + private function build_product_details() { + $info = ''; + foreach($this->product->get_info() as $key => $value) { + $info .= replace(array('name' => ucfirst($key), + 'key' => $key, + 'value' => $value), + $this->fragments['info_item']); + } + $tags = ''; + foreach($this->escape_tags($this->product->get_tags()) as $tag) { + $tags .= replace(array('tag' => ucfirst($tag)), + $this->fragments['tag']); + } + $fields = array('id' => $this->product->get_id(), + 'name' => $this->product->get_name(), + 'serial' => $this->product->get_serial(), + 'invoice' => $this->product->get_invoice(), + 'tags' => $tags, + 'info' => $info); + $label = ''; + if(class_exists('QRcode', false)) { + $label = replace($fields, $this->fragments['product_label']); + } + $fields['label'] = $label; + $out = replace($fields, $this->fragments['product_details']); + if(!$this->product->get_discardtime()) { + $out .= replace(array('id' => $this->product->get_id()), + $this->fragments['discard_button']); + } + $out .= replace(array('title' => 'Lånehistorik'), + $this->fragments['subtitle']); + $loan_table = 'Inga lån att visa.'; + $history = $this->product->get_loan_history(); + if($history) { + $loan_table = $this->build_product_loan_table($history); + } + $out .= $loan_table; + return $out; + } + + private function build_new_page() { + $template = ''; + $fields = ''; + $tags = ''; + if($this->template) { + $template = $this->template->get_name(); + foreach($this->template->get_fields() as $field) { + $fields .= replace(array('name' => ucfirst($field), + 'key' => $field, + 'value' => ''), + $this->fragments['info_item']); + } + foreach($this->template->get_tags() as $tag) { + $tags .= replace(array('tag' => ucfirst($tag)), + $this->fragments['tag']); + } + } + $out = replace(array('template' => $template), + $this->fragments['template_management']); + $out .= replace(array('id' => '', + 'name' => '', + 'serial' => '', + 'invoice' => '', + 'tags' => $tags, + 'info' => $fields, + 'label' => ''), + $this->fragments['product_details']); + return $out; + } +} +?> diff --git a/include/QR.php b/include/QR.php new file mode 100644 index 0000000..9525b65 --- /dev/null +++ b/include/QR.php @@ -0,0 +1,18 @@ +<?php +class QR extends Responder { + protected $product = ''; + + public function __construct() { + parent::__construct(); + if(isset($_GET['id'])) { + $this->product = new Product($_GET['id']); + } + } + + public function render() { + if(class_exists('QRcode', false)) { + QRcode::svg((string)$this->product->get_serial()); + } + } +} +?> diff --git a/include/Responder.php b/include/Responder.php new file mode 100644 index 0000000..80a4953 --- /dev/null +++ b/include/Responder.php @@ -0,0 +1,31 @@ +<?php +abstract class Responder { + protected $fragments = array(); + + public function __construct() { + $this->fragments = get_fragments('./html/fragments.html'); + } + + final protected function escape_tags($tags) { + foreach($tags as $key => $tag) { + $tags[$key] = str_replace(array("'", + '"'), + array(''', + '"'), + strtolower($tag)); + } + return $tags; + } + + final protected function unescape_tags($tags) { + foreach($tags as $key => $tag) { + $tags[$key] = str_replace(array(''', + '"'), + array("'", + '"'), + strtolower($tag)); + } + return $tags; + } +} +?> diff --git a/include/Result.php b/include/Result.php new file mode 100644 index 0000000..2ef92f5 --- /dev/null +++ b/include/Result.php @@ -0,0 +1,18 @@ +<?php +class Result { + private $type = ''; + private $message = ''; + + public function __construct($type, $message) { + $this->type = $type; + $this->message = $message; + } + + public function toJson() { + return json_encode(array( + 'type' => $this->type, + 'message' => $this->message + )); + } +} +?> diff --git a/include/ReturnPage.php b/include/ReturnPage.php new file mode 100644 index 0000000..bdb1690 --- /dev/null +++ b/include/ReturnPage.php @@ -0,0 +1,7 @@ +<?php +class ReturnPage extends Page { + protected function render_body() { + print($this->fragments['return_page']); + } +} +?> diff --git a/include/SearchPage.php b/include/SearchPage.php new file mode 100644 index 0000000..49d6970 --- /dev/null +++ b/include/SearchPage.php @@ -0,0 +1,156 @@ +<?php +class SearchPage extends Page { + private $terms = array(); + + public function __construct() { + parent::__construct(); + unset($_GET['page']); + if(isset($_GET['q']) && !$_GET['q']) { + unset($_GET['q']); + } + $this->terms = $this->translate_keys($_GET); + } + + private function do_search() { + $out = array(); + if(!$this->terms) { + return $out; + } + foreach(array('user', 'product') as $type) { + $result = $this->search($type, $this->terms); + if($result) { + $out[$type] = $result; + } + } + return $out; + } + + private function translate_keys($terms) { + $translated = array(); + foreach($terms as $key => $value) { + $newkey = $key; + switch($key) { + case 'q': + $newkey = 'fritext'; + break; + case 'namn': + $newkey = 'name'; + break; + case 'faktura': + case 'fakturanummer': + $newkey = 'invoice'; + break; + case 'serienummer': + $newkey = 'serial'; + break; + case 'tagg': + $newkey = 'tag'; + break; + case 'status': + $value = $this->translate_values($value); + break; + } + if(!array_key_exists($newkey, $translated)) { + $translated[$newkey] = $value; + } else { + $temp = $translated[$newkey]; + $translated[$newkey] = array_merge((array)$temp, (array)$value); + } + } + return $translated; + } + + private function translate_values($value) { + if(!is_array($value)) { + $value = array($value); + } + $translated = array(); + foreach($value as $item) { + $newitem = $item; + switch($item) { + case 'ute': + case 'utlånad': + case 'utlånat': + case 'lånad': + case 'lånat': + $newitem = 'on_loan'; + break; + case 'inne': + case 'ledig': + case 'ledigt': + case 'tillgänglig': + case 'tillgängligt': + $newitem = 'no_loan'; + break; + case 'sen': + case 'sent': + case 'försenad': + case 'försenat': + case 'överdraget': + $newitem = 'overdue'; + break; + case 'skrotad': + case 'skrotat': + case 'slängd': + case 'slängt': + $newitem = 'discarded'; + break; + } + $translated[] = $newitem; + } + return $translated; + } + + private function search($type, $terms) { + $items = get_items($type); + $out = array(); + foreach($items as $item) { + if($item->matches($terms)) { + $out[] = $item; + } + } + return $out; + } + + protected function render_body() { + $terms = ''; + foreach($this->terms as $key => $value) { + if(!is_array($value)) { + $terms .= replace(array('term' => ucfirst($key).": $value", + 'key' => $key, + 'value' => $value), + $this->fragments['search_term']); + } else { + foreach($value as $item) { + $terms .= replace(array('term' => ucfirst($key).": $item", + 'key' => $key, + 'value' => $item), + $this->fragments['search_term']); + } + } + } + print(replace(array('terms' => $terms), + $this->fragments['search_form'])); + if($this->terms) { + $hits = $this->do_search(); + print(replace(array('title' => 'Sökresultat'), + $this->fragments['title'])); + $result = ''; + if(isset($hits['user'])) { + $result = replace(array('title' => 'Låntagare'), + $this->fragments['subtitle']); + $result .= $this->build_user_table($hits['user']); + } + if(isset($hits['product'])) { + $result .= replace(array('title' => 'Artiklar'), + $this->fragments['subtitle']); + $result .= $this->build_product_table($hits['product']); + } + if(!$result) { + $result = 'Inga träffar.'; + } + print($result); + } + } +} +?> diff --git a/include/Success.php b/include/Success.php new file mode 100644 index 0000000..c4b534f --- /dev/null +++ b/include/Success.php @@ -0,0 +1,7 @@ +<?php +class Success extends Result { + public function __construct($message) { + parent::__construct('success', $message); + } +} +?> diff --git a/include/Template.php b/include/Template.php new file mode 100644 index 0000000..b069cc2 --- /dev/null +++ b/include/Template.php @@ -0,0 +1,196 @@ +<?php +class Template { + private $id = 0; + private $name = ''; + private $fields = array(); + private $tags = array(); + + public static function create_template( + $name = '', + $fields = array(), + $tags = array() + ) { + begin_trans(); + try { + $stmt = 'insert into `template`(`name`) values (?)'; + $ins_prod = prepare($stmt); + bind($ins_prod, 's', strtolower($name)); + execute($ins_prod); + $template = new Template($name, 'name'); + foreach(array_keys($fields) as $field) { + $template->add_field($field); + } + foreach($tags as $tag) { + $template->add_tag($tag); + } + commit_trans(); + return $template; + } catch(Exception $e) { + revert_trans(); + throw $e; + } + } + + public static function delete_template($name) { + $template = new Template($name, 'name'); + foreach($template->get_fields() as $field) { + $template->remove_field($field); + } + foreach($template->get_tags() as $tag) { + $template->remove_tag($tag); + } + $delete = prepare('delete from `template` where `id`=?'); + bind($delete, 'i', $template->get_id()); + execute($delete); + return true; + } + + public function __construct($clue, $type = 'id') { + switch($type) { + case 'id': + $this->id = $clue; + $search = prepare('select `name` from `template` + where `id`=?'); + bind($search, 'i', $this->id); + execute($search); + $result = result_single($search); + if($result === null) { + throw new Exception('Invalid id'); + } + $this->name = $result['name']; + break; + case 'name': + $this->name = strtolower($clue); + $search = prepare('select `id` from `template` + where `name`=?'); + bind($search, 's', $this->name); + execute($search); + $result = result_single($search); + if($result === null) { + throw new Exception('Invalid name.'); + } + $this->id = $result['id']; + break; + default: + throw new Exception('Invalid type.'); + } + $this->update_fields(); + $this->update_tags(); + } + + public function get_id() { + return $this->id; + } + + public function get_name() { + return ucfirst($this->name); + } + + public function set_name($name) { + $update = prepare('update `template` set `name`=? where `id`=?'); + bind($update, 'si', $name, $this->id); + execute($update); + $this->name = $name; + return true; + } + + private function update_fields() { + $get = prepare('select `field` from `template_info` + where `template`=? order by `field`'); + bind($get, 'i', $this->id); + execute($get); + $fields = array(); + foreach(result_list($get) as $row) { + $fields[] = $row['field']; + } + $this->fields = $fields; + return true; + } + + private function update_tags() { + $get = prepare('select * from `template_tag` + where `template`=? order by `tag`'); + bind($get, 'i', $this->id); + execute($get); + $newtags = array(); + foreach(result_list($get) as $row) { + $newtags[] = $row['tag']; + } + $this->tags = $newtags; + return true; + } + + public function get_fields() { + return $this->fields; + } + + public function add_field($field) { + $find = prepare('select * from `template_info` + where `template`=? and `field`=?'); + bind($find, 'is', $this->id, $field); + execute($find); + if(result_single($find) === null) { + $update = prepare('insert into `template_info`(`template`, `field`) + values (?, ?)'); + bind($update, 'is', $this->id, $field); + execute($update); + $this->update_fields(); + } + return true; + } + + public function remove_field($field) { + $find = prepare('select * from `template_info` + where `template`=? and `field`=?'); + bind($find, 'is', $this->id, $field); + execute($find); + if(result_single($find) === null) { + return true; + } + $update = prepare('delete from `template_info` + where `field`=? and `template`=?'); + bind($update, 'si', $field, $this->id); + execute($update); + $this->update_fields(); + return true; + } + + public function get_tags() { + return $this->tags; + } + + public function add_tag($tag) { + if(!$tag) { + return true; + } + $find = prepare('select * from `template_tag` + where `template`=? and `tag`=?'); + bind($find, 'is', $this->id, $tag); + execute($find); + if(result_single($find) === null) { + $update = prepare('insert into `template_tag`(`tag`, `template`) + values (?, ?)'); + bind($update, 'si', $tag, $this->id); + execute($update); + $this->update_tags(); + } + return true; + } + + public function remove_tag($tag) { + $find = prepare('select * from `template_tag` + where `template`=? and `tag`=?'); + bind($find, 'is', $this->id, $tag); + execute($find); + if(result_single($find) === null) { + return true; + } + $update = prepare('delete from `template_tag` + where `tag`=? and `template`=?'); + bind($update, 'si', $tag, $this->id); + execute($update); + $this->update_tags(); + return true; + } +} +?> diff --git a/include/User.php b/include/User.php new file mode 100644 index 0000000..d21c0a4 --- /dev/null +++ b/include/User.php @@ -0,0 +1,176 @@ +<?php +class User { + private $id = 0; + private $name = ''; + private $notes = ''; + private $ldap = null; + + public static function create_user($name) { + $ins_user = prepare('insert into `user`(`name`) values (?)'); + bind($ins_user, 's', $name); + execute($ins_user); + return new User($ins_user->insert_id); + } + + public function __construct($clue, $type = 'id') { + $find = null; + switch($type) { + case 'id': + $find = prepare('select `id` from `user` where `id`=?'); + bind($find, 'i', $clue); + break; + case 'name': + $find = prepare('select `id` from `user` where `name`=?'); + bind($find, 's', $clue); + break; + default: + throw new Exception('Invalid type'); + } + execute($find); + $id = result_single($find)['id']; + if($id === null) { + throw new Exception("Invalid username '$clue'"); + } + $this->id = $id; + $this->update_fields(); + $this->ldap = new Ldap(); + } + + private function update_fields() { + $get = prepare('select * from `user` where `id`=?'); + bind($get, 'i', $this->id); + execute($get); + $user = result_single($get); + $this->name = $user['name']; + $this->notes = $user['notes']; + return true; + } + + public function matches($terms) { + foreach($terms as $field => $values) { + $matchvalues = array(); + if($field == 'name') { + $matchvalues[] = $this->name; + $matchvalues[] = $this->get_displayname(); + } else if(property_exists($this, $field)) { + $matchvalues[] = $this->$field; + } else if($field == 'fritext') { + $matchvalues[] = $this->name; + $matchvalues[] = $this->get_displayname(); + $matchvalues[] = $this->notes; + } else { + return false; + } + if(!match($values, $matchvalues)) { + return false; + } + } + return true; + } + + public function get_displayname() { + try { + return $this->ldap->get_user($this->name); + } catch(Exception $e) { + return 'Ej i SUKAT'; + } + } + + public function get_email() { + try { + return $this->ldap->get_user_email($this->name); + } catch(Exception $e) { + return 'Mailadress saknas'; + } + } + + public function get_id() { + return $this->id; + } + + public function get_name() { + return $this->name; + } + + public function set_name($newname) { + $update = prepare('update `user` set `name`=? where `id`=?'); + bind($update, 'si', $newname, $this->id); + execute($update); + $this->name = $newname; + return true; + } + + public function get_notes() { + return $this->notes; + } + + public function set_notes($newnotes) { + $update = prepare('update `user` set `notes`=? where `id`=?'); + bind($update, 'si', $newnotes, $this->id); + execute($update); + $this->notes = $newnotes; + return true; + } + + public function get_loans($type = 'both') { + $statement = 'select `id` from `loan` where `user`=?'; + switch($type) { + case 'active': + $statement .= ' and `returntime` is null'; + break; + case 'inactive': + $statement .= ' and `returntime` is not null'; + break; + case 'both': + break; + default: + $err = "$type is not a valid argument. Valid arguments are active, inactive, both."; + throw new Exception($err); + break; + } + $statement .= ' order by `starttime` desc'; + $get = prepare($statement); + bind($get, 'i', $this->id); + execute($get); + $loans = array(); + foreach(result_list($get) as $row) { + $loans[] = new Loan($row['id']); + } + return $loans; + } + + public function get_overdue_loans() { + $overdue = array(); + foreach($this->get_loans('active') as $loan) { + if($loan->is_overdue()) { + $overdue[] = $loan; + } + } + return $overdue; + } + + public function create_loan($product, $endtime) { + $find = prepare('select * from `loan` + where `product`=? and `returntime` is null'); + $prod_id = $product->get_id(); + bind($find, 'i', $prod_id); + execute($find); + $loan = result_single($find); + if($loan !== null) { + $loan_id = $loan['id']; + throw new Exception( + "Product $prod_id has an active loan (id $loan_id) already."); + } + $now = time(); + $insert = prepare('insert into + `loan`(`user`, `product`, `starttime`, `endtime`) + values (?, ?, ?, ?)'); + bind($insert, 'iiii', + $this->id, $prod_id, + $now, strtotime($endtime . ' 13:00')); + execute($insert); + $loan_id = $insert->insert_id; + return new Loan($loan_id); + } +} +?> diff --git a/include/UserPage.php b/include/UserPage.php new file mode 100644 index 0000000..5335ab0 --- /dev/null +++ b/include/UserPage.php @@ -0,0 +1,65 @@ +<?php +class UserPage extends Page { + private $action = 'list'; + private $user = null; + + public function __construct() { + parent::__construct(); + if(isset($_GET['action'])) { + $this->action = $_GET['action']; + } + if(isset($_GET['id'])) { + $id = $_GET['id']; + if($id) { + try { + $this->user = new User($_GET['id']); + } catch(Exception $e) { + $this->user = null; + $this->action = 'list'; + $this->error = 'Det finns ingen användare med det ID-numret.'; + } + } + } + switch($this->action) { + case 'show': + $this->subtitle = 'Låntagardetaljer'; + break; + case 'list': + $this->subtitle = 'Låntagarlista'; + break; + } + } + + protected function render_body() { + switch($this->action) { + case 'list': + print($this->build_user_table(get_items('user'))); + break; + case 'show': + print($this->build_user_details()); + break; + } + } + + private function build_user_details() { + $active_loans = $this->user->get_loans('active'); + $table_active = 'Inga aktuella lån.'; + if($active_loans) { + $table_active = $this->build_user_loan_table($active_loans, 'renew'); + } + $inactive_loans = $this->user->get_loans('inactive'); + $table_inactive = 'Inga gamla lån.'; + if($inactive_loans) { + $table_inactive = $this->build_user_loan_table($inactive_loans, + 'return'); + } + return replace(array('active_loans' => $table_active, + 'inactive_loans' => $table_inactive, + 'id' => $this->user->get_id(), + 'name' => $this->user->get_name(), + 'displayname' => $this->user->get_displayname(), + 'notes' => $this->user->get_notes()), + $this->fragments['user_details']); + } +} +?> diff --git a/include/db.php b/include/db.php deleted file mode 100644 index 876fe95..0000000 --- a/include/db.php +++ /dev/null @@ -1,1111 +0,0 @@ -<?php -require_once('./include/sql.php'); -require_once('./include/ldap.php'); - -function get_ids($type) { - $append = ''; - switch($type) { - case 'user': - break; - case 'product': - $append = 'where `discardtime` is null'; - break; - case 'loan': - break; - case 'inventory': - break; - case 'product_discarded': - $append = 'where `discardtime` is not null'; - $type = 'product'; - break; - case 'loan_active': - $append = 'where `returntime` is null'; - $type = 'loan'; - break; - case 'inventory_old': - $append = 'where `endtime` is not null order by `id` desc'; - $type = 'inventory'; - break; - default: - $err = "$type is not a valid argument."; - throw new Exception($err); - break; - } - $query = "select `id` from `$type`"; - if($append) { - $query .= " $append"; - } - $get = prepare($query); - execute($get); - $ids = array(); - foreach(result_list($get) as $row) { - $ids[] = $row['id']; - } - return $ids; -} - -function get_items($type) { - $construct = null; - switch($type) { - case 'user': - $construct = function($id) { - return new User($id); - }; - break; - case 'product': - case 'product_discarded': - $construct = function($id) { - return new Product($id); - }; - break; - case 'loan': - case 'loan_active': - $construct = function($id) { - return new Loan($id); - }; - break; - case 'inventory': - case 'inventory_old': - $construct = function($id) { - return new Inventory($id); - }; - break; - default: - $err = "$type is not a valid argument."; - throw new Exception($err); - break; - } - $ids = get_ids($type); - $list = array(); - foreach($ids as $id) { - $list[] = $construct($id); - } - return $list; -} - -function suggest($type) { - $search = ''; - $typename = 'name'; - switch($type) { - case 'user': - $search = prepare('select `name` from `user` order by `name`'); - break; - case 'template': - $search = prepare('select `name` from `template` order by `name`'); - break; - case 'tag': - $search = prepare( - '(select `tag` from `product_tag`) - union - (select `tag` from `template_tag`) - order by `tag`'); - $typename = 'tag'; - break; - case 'field': - $search = prepare( - '(select `field` from `product_info`) - union - (select `field` from `template_info`) - order by `field`'); - $typename = 'field'; - break; - default: - return array(); - } - execute($search); - $out = array(); - foreach(result_list($search) as $row) { - $out[] = $row[$typename]; - } - return $out; -} - -function match($testvalues, $matchvalues) { - if(!is_array($testvalues)) { - $testvalues = array($testvalues); - } - foreach($testvalues as $value) { - foreach($matchvalues as $candidate) { - if(fnmatch($value, $candidate, FNM_CASEFOLD)) { - return true; - } - } - } - return false; -} - -class Product { - private $id = 0; - private $name = ''; - private $invoice = ''; - private $serial = ''; - private $createtime = null; - private $discardtime = null; - private $info = array(); - private $tags = array(); - - public static function create_product( - $name = '', - $invoice = '', - $serial = '', - $info = array(), - $tags = array() - ) { - $now = time(); - begin_trans(); - try { - $stmt = 'insert into - `product`(`name`, `invoice`, `serial`, `createtime`) - values (?, ?, ?, ?)'; - $ins_prod = prepare($stmt); - bind($ins_prod, 'sssi', $name, $invoice, $serial, $now); - execute($ins_prod); - $product = new Product($serial, 'serial'); - foreach($info as $field => $value) { - $product->set_info($field, $value); - } - foreach($tags as $tag) { - $product->add_tag($tag); - } - commit_trans(); - return $product; - } catch(Exception $e) { - revert_trans(); - throw $e; - } - } - - public function __construct($clue, $type = 'id') { - $search = null; - switch($type) { - case 'id': - $search = prepare('select `id` from `product` - where `id`=?'); - bind($search, 'i', $clue); - break; - case 'serial': - $search = prepare('select `id` from `product` - where `serial`=?'); - bind($search, 's', $clue); - break; - default: - throw new Exception('Invalid type.'); - } - execute($search); - $result = result_single($search); - if($result === null) { - throw new Exception('Product does not exist..'); - } - $this->id = $result['id']; - $this->update_fields(); - $this->update_info(); - $this->update_tags(); - } - - private function update_fields() { - $get = prepare('select * from `product` where `id`=?'); - bind($get, 'i', $this->id); - execute($get); - $product = result_single($get); - $this->name = $product['name']; - $this->invoice = $product['invoice']; - $this->serial = $product['serial']; - $this->createtime = $product['createtime']; - $this->discardtime = $product['discardtime']; - return true; - } - - private function update_info() { - $get = prepare('select * from `product_info` - where `product`=? order by `field`'); - bind($get, 'i', $this->id); - execute($get); - foreach(result_list($get) as $row) { - $field = $row['field']; - $data = $row['data']; - $this->info[$field] = $data; - } - return true; - } - - private function update_tags() { - $get = prepare('select * from `product_tag` - where `product`=? order by `tag`'); - bind($get, 'i', $this->id); - execute($get); - $newtags = array(); - foreach(result_list($get) as $row) { - $newtags[] = $row['tag']; - } - $this->tags = $newtags; - return true; - } - - public function matches($terms) { - foreach($terms as $field => $values) { - $matchvalues = array(); - if(property_exists($this, $field)) { - $matchvalues[] = $this->$field; - } else if(array_key_exists($field, $this->get_info())) { - $matchvalues[] = $this->get_info()[$field]; - } else { - switch($field) { - case 'tag': - $matchvalues = $this->get_tags(); - case 'status': - $matchvalues[] = $this->get_loan_status(); - case 'fritext': - $matchvalues[] = $this->name; - $matchvalues[] = $this->serial; - $matchvalues[] = $this->invoice; - $matchvalues = array_merge($matchvalues, - $this->get_tags(), - array_values( - $this->get_info())); - } - } - if(!match($values, $matchvalues)) { - return false; - } - } - return true; - } - - public function get_id() { - return $this->id; - } - - public function get_createtime() { - return $this->createtime; - } - - public function get_discardtime($format = true) { - if($this->discardtime && $format) { - return gmdate('Y-m-d', $this->discardtime); - } - return $this->discardtime; - } - - public function discard() { - $now = time(); - $update = prepare('update `product` set `discardtime`=? where `id`=?'); - bind($update, 'ii', $now, $this->id); - execute($update); - $this->discardtime = $now; - return true; - } - - public function get_name() { - return $this->name; - } - - public function set_name($newname) { - $update = prepare('update `product` set `name`=? where `id`=?'); - bind($update, 'si', $newname, $this->id); - execute($update); - $this->name = $newname; - return true; - } - - public function get_invoice() { - return $this->invoice; - } - - public function set_invoice($newinvoice) { - $update = prepare('update `product` set `invoice`=? where `id`=?'); - bind($update, 'si', $newinvoice, $this->id); - execute($update); - $this->invoice = $newinvoice; - return true; - } - - public function get_serial() { - return $this->serial; - } - - public function set_serial($newserial) { - $update = prepare('update `product` set `serial`=? where `id`=?'); - bind($update, 'si', $newserial, $this->id); - execute($update); - $this->serial = $newserial; - return true; - } - - public function get_info() { - return $this->info; - } - - public function set_info($field, $value) { - if(!$value) { - return true; - } - $find = prepare('select * from `product_info` - where `product`=? and `field`=?'); - bind($find, 'is', $this->id, $field); - execute($find); - if(result_single($find) === null) { - $update = prepare('insert into - `product_info`(`data`, `product`, `field`) - values (?, ?, ?)'); - } else { - $update = prepare('update `product_info` set `data`=? - where `product`=? and `field`=?'); - } - bind($update, 'sis', $value, $this->id, $field); - execute($update); - $this->update_info(); - return true; - } - - public function remove_info($field) { - $find = prepare('select * from `product_info` - where `product`=? and `field`=?'); - bind($find, 'is', $this->id, $field); - execute($find); - if(result_single($find) === null) { - return true; - } - $update = prepare('delete from `product_info` - where `field`=? and `product`=?'); - bind($update, 'si', $field, $this->id); - execute($update); - $this->update_info(); - return true; - } - - public function get_tags() { - return $this->tags; - } - - public function add_tag($tag) { - if(!$tag) { - return true; - } - $find = prepare('select * from `product_tag` - where `product`=? and `tag`=?'); - bind($find, 'is', $this->id, $tag); - execute($find); - if(result_single($find) === null) { - $update = prepare('insert into `product_tag`(`tag`, `product`) - values (?, ?)'); - bind($update, 'si', $tag, $this->id); - execute($update); - $this->update_tags(); - } - return true; - } - - public function remove_tag($tag) { - $find = prepare('select * from `product_tag` - where `product`=? and `tag`=?'); - bind($find, 'is', $this->id, $tag); - execute($find); - if(result_single($find) === null) { - return true; - } - $update = prepare('delete from `product_tag` - where `tag`=? and `product`=?'); - bind($update, 'si', $tag, $this->id); - execute($update); - $this->update_tags(); - return true; - } - - public function get_loan_status() { - if($this->get_discardtime(false)) { - return 'discarded'; - } - $loan = $this->get_active_loan(); - if(!$loan) { - return 'no_loan'; - } - if($loan->is_overdue()) { - return 'overdue'; - } - return 'on_loan'; - } - - public function get_active_loan() { - $find = prepare('select `id` from `loan` - where `returntime` is null and product=?'); - bind($find, 'i', $this->id); - execute($find); - $result = result_single($find); - if($result === null) { - return null; - } - return new Loan($result['id']); - } - - public function get_loan_history() { - $find = prepare('select `id` from `loan` - where product=? order by `starttime` desc'); - bind($find, 'i', $this->id); - execute($find); - $loans = result_list($find); - $out = array(); - foreach($loans as $loan) { - $out[] = new Loan($loan['id']); - } - return $out; - } -} - -class Template { - private $id = 0; - private $name = ''; - private $fields = array(); - private $tags = array(); - - public static function create_template( - $name = '', - $fields = array(), - $tags = array() - ) { - begin_trans(); - try { - $stmt = 'insert into `template`(`name`) values (?)'; - $ins_prod = prepare($stmt); - bind($ins_prod, 's', strtolower($name)); - execute($ins_prod); - $template = new Template($name, 'name'); - foreach(array_keys($fields) as $field) { - $template->add_field($field); - } - foreach($tags as $tag) { - $template->add_tag($tag); - } - commit_trans(); - return $template; - } catch(Exception $e) { - revert_trans(); - throw $e; - } - } - - public static function delete_template($name) { - $template = new Template($name, 'name'); - foreach($template->get_fields() as $field) { - $template->remove_field($field); - } - foreach($template->get_tags() as $tag) { - $template->remove_tag($tag); - } - $delete = prepare('delete from `template` where `id`=?'); - bind($delete, 'i', $template->get_id()); - execute($delete); - return true; - } - - public function __construct($clue, $type = 'id') { - switch($type) { - case 'id': - $this->id = $clue; - $search = prepare('select `name` from `template` - where `id`=?'); - bind($search, 'i', $this->id); - execute($search); - $result = result_single($search); - if($result === null) { - throw new Exception('Invalid id'); - } - $this->name = $result['name']; - break; - case 'name': - $this->name = strtolower($clue); - $search = prepare('select `id` from `template` - where `name`=?'); - bind($search, 's', $this->name); - execute($search); - $result = result_single($search); - if($result === null) { - throw new Exception('Invalid name.'); - } - $this->id = $result['id']; - break; - default: - throw new Exception('Invalid type.'); - } - $this->update_fields(); - $this->update_tags(); - } - - public function get_id() { - return $this->id; - } - - public function get_name() { - return ucfirst($this->name); - } - - public function set_name($name) { - $update = prepare('update `template` set `name`=? where `id`=?'); - bind($update, 'si', $name, $this->id); - execute($update); - $this->name = $name; - return true; - } - - private function update_fields() { - $get = prepare('select `field` from `template_info` - where `template`=? order by `field`'); - bind($get, 'i', $this->id); - execute($get); - $fields = array(); - foreach(result_list($get) as $row) { - $fields[] = $row['field']; - } - $this->fields = $fields; - return true; - } - - private function update_tags() { - $get = prepare('select * from `template_tag` - where `template`=? order by `tag`'); - bind($get, 'i', $this->id); - execute($get); - $newtags = array(); - foreach(result_list($get) as $row) { - $newtags[] = $row['tag']; - } - $this->tags = $newtags; - return true; - } - - public function get_fields() { - return $this->fields; - } - - public function add_field($field) { - $find = prepare('select * from `template_info` - where `template`=? and `field`=?'); - bind($find, 'is', $this->id, $field); - execute($find); - if(result_single($find) === null) { - $update = prepare('insert into `template_info`(`template`, `field`) - values (?, ?)'); - bind($update, 'is', $this->id, $field); - execute($update); - $this->update_fields(); - } - return true; - } - - public function remove_field($field) { - $find = prepare('select * from `template_info` - where `template`=? and `field`=?'); - bind($find, 'is', $this->id, $field); - execute($find); - if(result_single($find) === null) { - return true; - } - $update = prepare('delete from `template_info` - where `field`=? and `template`=?'); - bind($update, 'si', $field, $this->id); - execute($update); - $this->update_fields(); - return true; - } - - public function get_tags() { - return $this->tags; - } - - public function add_tag($tag) { - if(!$tag) { - return true; - } - $find = prepare('select * from `template_tag` - where `template`=? and `tag`=?'); - bind($find, 'is', $this->id, $tag); - execute($find); - if(result_single($find) === null) { - $update = prepare('insert into `template_tag`(`tag`, `template`) - values (?, ?)'); - bind($update, 'si', $tag, $this->id); - execute($update); - $this->update_tags(); - } - return true; - } - - public function remove_tag($tag) { - $find = prepare('select * from `template_tag` - where `template`=? and `tag`=?'); - bind($find, 'is', $this->id, $tag); - execute($find); - if(result_single($find) === null) { - return true; - } - $update = prepare('delete from `template_tag` - where `tag`=? and `template`=?'); - bind($update, 'si', $tag, $this->id); - execute($update); - $this->update_tags(); - return true; - } -} - -class User { - private $id = 0; - private $name = ''; - private $notes = ''; - - public static function create_user($name) { - $ins_user = prepare('insert into `user`(`name`) values (?)'); - bind($ins_user, 's', $name); - execute($ins_user); - return new User($ins_user->insert_id); - } - - public function __construct($clue, $type = 'id') { - $find = null; - switch($type) { - case 'id': - $find = prepare('select `id` from `user` where `id`=?'); - bind($find, 'i', $clue); - break; - case 'name': - $find = prepare('select `id` from `user` where `name`=?'); - bind($find, 's', $clue); - break; - default: - throw new Exception('Invalid type'); - } - execute($find); - $id = result_single($find)['id']; - if($id === null) { - throw new Exception("Invalid username '$clue'"); - } - $this->id = $id; - $this->update_fields(); - } - - private function update_fields() { - $get = prepare('select * from `user` where `id`=?'); - bind($get, 'i', $this->id); - execute($get); - $user = result_single($get); - $this->name = $user['name']; - $this->notes = $user['notes']; - return true; - } - - public function matches($terms) { - foreach($terms as $field => $values) { - $matchvalues = array(); - if($field == 'name') { - $matchvalues[] = $this->name; - $matchvalues[] = $this->get_displayname(); - } else if(property_exists($this, $field)) { - $matchvalues[] = $this->$field; - } else if($field == 'fritext') { - $matchvalues[] = $this->name; - $matchvalues[] = $this->get_displayname(); - $matchvalues[] = $this->notes; - } else { - return false; - } - if(!match($values, $matchvalues)) { - return false; - } - } - return true; - } - - public function get_displayname() { - global $ldap; - try { - return $ldap->get_user($this->name); - } catch(Exception $e) { - return 'Ej i SUKAT'; - } - } - - public function get_email() { - global $ldap; - try { - return $ldap->get_user_email($this->name); - } catch(Exception $e) { - return 'Mailadress saknas'; - } - } - - public function get_id() { - return $this->id; - } - - public function get_name() { - return $this->name; - } - - public function set_name($newname) { - $update = prepare('update `user` set `name`=? where `id`=?'); - bind($update, 'si', $newname, $this->id); - execute($update); - $this->name = $newname; - return true; - } - - public function get_notes() { - return $this->notes; - } - - public function set_notes($newnotes) { - $update = prepare('update `user` set `notes`=? where `id`=?'); - bind($update, 'si', $newnotes, $this->id); - execute($update); - $this->notes = $newnotes; - return true; - } - - public function get_loans($type = 'both') { - $statement = 'select `id` from `loan` where `user`=?'; - switch($type) { - case 'active': - $statement .= ' and `returntime` is null'; - break; - case 'inactive': - $statement .= ' and `returntime` is not null'; - break; - case 'both': - break; - default: - $err = "$type is not a valid argument. Valid arguments are active, inactive, both."; - throw new Exception($err); - break; - } - $statement .= ' order by `starttime` desc'; - $get = prepare($statement); - bind($get, 'i', $this->id); - execute($get); - $loans = array(); - foreach(result_list($get) as $row) { - $loans[] = new Loan($row['id']); - } - return $loans; - } - - public function get_overdue_loans() { - $overdue = array(); - foreach($this->get_loans('active') as $loan) { - if($loan->is_overdue()) { - $overdue[] = $loan; - } - } - return $overdue; - } - - public function create_loan($product, $endtime) { - $find = prepare('select * from `loan` - where `product`=? and `returntime` is null'); - $prod_id = $product->get_id(); - bind($find, 'i', $prod_id); - execute($find); - $loan = result_single($find); - if($loan !== null) { - $loan_id = $loan['id']; - throw new Exception( - "Product $prod_id has an active loan (id $loan_id) already."); - } - $now = time(); - $insert = prepare('insert into - `loan`(`user`, `product`, `starttime`, `endtime`) - values (?, ?, ?, ?)'); - bind($insert, 'iiii', - $this->id, $prod_id, - $now, strtotime($endtime . ' 13:00')); - execute($insert); - $loan_id = $insert->insert_id; - return new Loan($loan_id); - } -} - -class Loan { - private $id = 0; - private $user = 0; - private $product = 0; - private $starttime = 0; - private $endtime = 0; - private $returntime = null; - - public function __construct($id) { - $this->id = $id; - $this->update_fields(); - } - - private function update_fields() { - $get = prepare('select * from `loan` where `id`=?'); - bind($get, 'i', $this->id); - execute($get); - $loan = result_single($get); - $this->user = $loan['user']; - $this->product = $loan['product']; - $this->starttime = $loan['starttime']; - $this->endtime = $loan['endtime']; - $this->returntime = $loan['returntime']; - } - - public function get_id() { - return $this->id; - } - - public function get_user() { - return new User($this->user); - } - - public function get_product() { - return new Product($this->product); - } - - public function get_duration($format = true) { - $style = function($time) { - return $time; - }; - if($format) { - $style = function($time) { - if($time) { - return gmdate('Y-m-d', $time); - } - return $time; - }; - } - return array('start' => $style($this->starttime), - 'end' => $style($this->endtime), - 'end_renew' => $style($this->endtime + 604800), # +1 week - 'return' => $style($this->returntime)); - } - - public function is_active() { - if($this->returntime === null) { - return true; - } - return false; - } - - public function extend($time) { - $ts = strtotime($time . ' 13:00'); - $query = prepare('update `loan` set `endtime`=? where `id`=?'); - bind($query, 'ii', $ts, $this->id); - execute($query); - $this->endtime = $ts; - return true; - } - - public function end() { - $now = time(); - $query = prepare('update `loan` set `returntime`=? where `id`=?'); - bind($query, 'ii', $now, $this->id); - execute($query); - $this->returntime = $now; - return true; - } - - public function is_overdue() { - if($this->returntime !== null) { - return false; - } - $now = time(); - if($now > $this->endtime) { - return true; - } - return false; - } -} - -class Inventory { - private $id = ''; - private $starttime = ''; - private $endtime = null; - private $seen_products = array(); - - public static function begin() { - if(Inventory::get_active() !== null) { - throw new Exception('Inventory already in progress.'); - } - $now = time(); - $start = prepare('insert into `inventory`(`starttime`) values (?)'); - bind($start, 'i', $now); - execute($start); - $invid = $start->insert_id; - $prodid = ''; - $register = prepare('insert into - `inventory_product`(`inventory`, `product`) - values (?, ?)'); - foreach(get_items('loan_active') as $loan) { - $prodid = $loan->get_product()->get_id(); - bind($register, 'ii', $invid, $prodid); - execute($register); - } - return new Inventory($invid); - } - - public static function get_active() { - $search = prepare('select * from `inventory` where `endtime` is null'); - execute($search); - $result = result_single($search); - if($result === null) { - return null; - } - return new Inventory($result['id']); - } - - public function __construct($id) { - $search = prepare('select `id` from `inventory` where `id`=?'); - bind($search, 'i', $id); - execute($search); - $result = result_single($search); - if($result === null) { - throw new Exception('Invalid id'); - } - $this->id = $result['id']; - $this->update_fields(); - } - - private function update_fields() { - $get = prepare('select * from `inventory` where `id`=?'); - bind($get, 'i', $this->id); - execute($get); - $result = result_single($get); - $this->starttime = $result['starttime']; - $this->endtime = $result['endtime']; - $prodget = prepare('select * from `inventory_product` - where `inventory`=?'); - bind($prodget, 'i', $this->id); - execute($prodget); - foreach(result_list($prodget) as $row) { - $this->seen_products[] = $row['product']; - } - } - - public function end() { - $now = time(); - $update = prepare('update `inventory` set `endtime`=? - where `id`=? and `endtime` is null'); - bind($update, 'ii', $now, $this->id); - execute($update); - $this->endtime = $now; - return true; - } - - public function add_product($product) { - $add = prepare('insert into `inventory_product`(`inventory`, `product`) - values (?, ?)'); - bind($add, 'ii', $this->id, $product->get_id()); - try { - execute($add); - } catch(Exception $e) { - return false; - } - $this->products[] = $product->get_id(); - return true; - } - - public function get_id() { - return $this->id; - } - - public function get_duration($format = true) { - $style = function($time) { - return $time; - }; - if($format) { - $style = function($time) { - return gmdate('Y-m-d', $time); - }; - } - return array('start' => $style($this->starttime), - 'end' => $style($this->endtime)); - } - - public function get_seen_products() { - $out = array(); - foreach($this->seen_products as $prodid) { - $out[] = new Product($prodid); - } - return $out; - } - - public function get_unseen_products() { - $all = get_items('product'); - $out = array(); - $include = function($product) { - if(!in_array($product->get_id(), $this->seen_products)) { - return true; - } - return false; - }; - if($this->endtime) { - $include = function($product) { - if($product->get_createtime() < $this->endtime - && !in_array($product->get_id(), $this->seen_products)) { - return true; - } - return false; - }; - } - foreach($all as $product) { - if($include($product)) { - $out[] = $product; - } - } - return $out; - } -} - -class Kvs { - private $items = array(); - - public function __construct() { - $get = prepare('select * from `kvs`'); - execute($get); - foreach(result_list($get) as $row) { - $key = $row['key']; - $value = $row['value']; - $this->items[$key] = $value; - } - } - - public function get_keys() { - return array_keys($this->items); - } - - public function get_value($key) { - if(isset($this->items[$key])) { - return $this->items[$key]; - } - return null; - } - - public function set_key($key, $value) { - $find = prepare('select * from `kvs` where `key`=?'); - bind($find, 's', $key); - execute($find); - if(result_single($find) === null) { - $update = prepare('insert into `kvs`(`value`, `key`) - values (?, ?)'); - } else { - $update = prepare('update `kvs` set `value`=? where `key`=?'); - } - bind($update, 'ss', $value, $key); - execute($update); - $this->items[$key] = $value; - return true; - } - - public function remove_key($key) { - $find = prepare('select * from `kvs` where `key`=?'); - bind($find, 's', $key); - execute($find); - if(result_single($find) === null) { - return true; - } - $update = prepare('delete from `kvs` where `key`=?'); - bind($update, 's', $key); - execute($update); - unset($this->items[$key]); - return true; - } -} - -?> diff --git a/include/functions.php b/include/functions.php index bcec9d9..9ef1b5a 100644 --- a/include/functions.php +++ b/include/functions.php @@ -1,7 +1,5 @@ <?php -require_once("./config.php"); - /* Takes an html file containing named fragments. Returns an associative array on the format array[name]=>fragment. @@ -76,4 +74,237 @@ function replace($assoc_arr, $subject) { return str_replace($keys, $values, $subject); } +function make_page($page) { + switch($page) { + default: + case 'checkout': + return new CheckoutPage(); + case 'return': + return new ReturnPage(); + case 'search': + return new SearchPage(); + case 'products': + return new ProductPage(); + case 'users': + return new UserPage(); + case 'inventory': + return new InventoryPage(); + case 'history': + return new HistoryPage(); + case 'ajax': + return new Ajax(); + case 'qr': + return new QR(); + case 'print': + return new Printer(); + } +} + +function get_ids($type) { + $append = ''; + switch($type) { + case 'user': + break; + case 'product': + $append = 'where `discardtime` is null'; + break; + case 'loan': + break; + case 'inventory': + break; + case 'product_discarded': + $append = 'where `discardtime` is not null'; + $type = 'product'; + break; + case 'loan_active': + $append = 'where `returntime` is null'; + $type = 'loan'; + break; + case 'inventory_old': + $append = 'where `endtime` is not null order by `id` desc'; + $type = 'inventory'; + break; + default: + $err = "$type is not a valid argument."; + throw new Exception($err); + break; + } + $query = "select `id` from `$type`"; + if($append) { + $query .= " $append"; + } + $get = prepare($query); + execute($get); + $ids = array(); + foreach(result_list($get) as $row) { + $ids[] = $row['id']; + } + return $ids; +} + +function get_items($type) { + $construct = null; + switch($type) { + case 'user': + $construct = function($id) { + return new User($id); + }; + break; + case 'product': + case 'product_discarded': + $construct = function($id) { + return new Product($id); + }; + break; + case 'loan': + case 'loan_active': + $construct = function($id) { + return new Loan($id); + }; + break; + case 'inventory': + case 'inventory_old': + $construct = function($id) { + return new Inventory($id); + }; + break; + default: + $err = "$type is not a valid argument."; + throw new Exception($err); + break; + } + $ids = get_ids($type); + $list = array(); + foreach($ids as $id) { + $list[] = $construct($id); + } + return $list; +} + +function suggest($type) { + $search = ''; + $typename = 'name'; + switch($type) { + case 'user': + $search = prepare('select `name` from `user` order by `name`'); + break; + case 'template': + $search = prepare('select `name` from `template` order by `name`'); + break; + case 'tag': + $search = prepare( + '(select `tag` from `product_tag`) + union + (select `tag` from `template_tag`) + order by `tag`'); + $typename = 'tag'; + break; + case 'field': + $search = prepare( + '(select `field` from `product_info`) + union + (select `field` from `template_info`) + order by `field`'); + $typename = 'field'; + break; + default: + return array(); + } + execute($search); + $out = array(); + foreach(result_list($search) as $row) { + $out[] = $row[$typename]; + } + return $out; +} + +function match($testvalues, $matchvalues) { + if(!is_array($testvalues)) { + $testvalues = array($testvalues); + } + foreach($testvalues as $value) { + foreach($matchvalues as $candidate) { + if(fnmatch($value, $candidate, FNM_CASEFOLD)) { + return true; + } + } + } + return false; +} + +### Database interaction functions ### + +$db = new mysqli($db_host, $db_user, $db_pass, $db_name); +if($db->connect_errno) { + $error = 'Failed to connect to db. The error was: '.$db->connect_error; + throw new Exception($error); +} + +function prepare($statement) { + global $db; + + if(!($s = $db->prepare($statement))) { + $error = 'Failed to prepare the following statement: '.$statement; + $error .= '\n'; + $error .= $db->error.' ('.$db->errno.')'; + throw new Exception($error); + } + + return $s; +} + +function bind($statement, $types, ...$values) { + global $db; + + return $statement->bind_param($types, ...$values); +} + +function execute($statement) { + if(!$statement->execute()) { + $error = 'Failed to execute statement.'; + $error .= '\n'; + $error .= $statement->error.' ('.$statement->errno.')'; + throw new Exception($error); + } + return true; +} + +function result_list($statement) { + return $statement->get_result()->fetch_all(MYSQLI_ASSOC); +} + +function result_single($statement) { + $out = result_list($statement); + switch(count($out)) { + case 0: + return null; + case 1: + foreach($out as $value) { + return $value; + } + default: + throw new Exception('More than one result available.'); + } +} + +function begin_trans() { + global $db; + + $db->begin_transaction(MYSQLI_TRANS_START_WITH_CONSISTENT_SNAPSHOT); +} + +function commit_trans() { + global $db; + + $db->commit(); + return true; +} + +function revert_trans() { + global $db; + + $db->rollback(); + return false; +} + ?> diff --git a/include/sql.php b/include/sql.php deleted file mode 100644 index 7c1a68a..0000000 --- a/include/sql.php +++ /dev/null @@ -1,77 +0,0 @@ -<?php -require_once("./config.php"); - -$db = new mysqli($db_host, $db_user, $db_pass, $db_name); -if($db->connect_errno) { - $error = 'Failed to connect to db. The error was: '.$db->connect_error; - throw new Exception($error); -} - -function prepare($statement) { - global $db; - - if(!($s = $db->prepare($statement))) { - $error = 'Failed to prepare the following statement: '.$statement; - $error .= '\n'; - $error .= $db->error.' ('.$db->errno.')'; - throw new Exception($error); - } - - return $s; -} - -function bind($statement, $types, ...$values) { - global $db; - - return $statement->bind_param($types, ...$values); -} - -function execute($statement) { - if(!$statement->execute()) { - $error = 'Failed to execute statement.'; - $error .= '\n'; - $error .= $statement->error.' ('.$statement->errno.')'; - throw new Exception($error); - } - return true; -} - -function result_list($statement) { - return $statement->get_result()->fetch_all(MYSQLI_ASSOC); -} - -function result_single($statement) { - $out = result_list($statement); - switch(count($out)) { - case 0: - return null; - case 1: - foreach($out as $value) { - return $value; - } - default: - throw new Exception('More than one result available.'); - } -} - -function begin_trans() { - global $db; - - $db->begin_transaction(MYSQLI_TRANS_START_WITH_CONSISTENT_SNAPSHOT); -} - -function commit_trans() { - global $db; - - $db->commit(); - return true; -} - -function revert_trans() { - global $db; - - $db->rollback(); - return false; -} - -?> diff --git a/include/view.php b/include/view.php deleted file mode 100644 index c5e06e2..0000000 --- a/include/view.php +++ /dev/null @@ -1,1289 +0,0 @@ -<?php - -require_once('./include/db.php'); -require_once('./include/ldap.php'); -require_once('./include/functions.php'); -include_once('./phpqrcode/qrlib.php'); - -function make_page($page) { - switch($page) { - default: - case 'checkout': - return new CheckoutPage(); - case 'return': - return new ReturnPage(); - case 'search': - return new SearchPage(); - case 'products': - return new ProductPage(); - case 'users': - return new UserPage(); - case 'inventory': - return new InventoryPage(); - case 'history': - return new HistoryPage(); - case 'ajax': - return new Ajax(); - case 'qr': - return new QR(); - case 'print': - return new Printer(); - } -} - -abstract class Responder { - protected $fragments = array(); - - public function __construct() { - $this->fragments = get_fragments('./html/fragments.html'); - } - - final protected function escape_tags($tags) { - foreach($tags as $key => $tag) { - $tags[$key] = str_replace(array("'", - '"'), - array(''', - '"'), - strtolower($tag)); - } - return $tags; - } - - final protected function unescape_tags($tags) { - foreach($tags as $key => $tag) { - $tags[$key] = str_replace(array(''', - '"'), - array("'", - '"'), - strtolower($tag)); - } - return $tags; - } -} - -abstract class Page extends Responder { - protected abstract function render_body(); - - protected $page = 'checkout'; - protected $title = "DSV Utlåning"; - protected $subtitle = ''; - protected $error = null; - protected $menuitems = array('checkout' => 'Låna', - 'return' => 'Lämna', - 'products' => 'Artiklar', - 'users' => 'Låntagare', - 'inventory' => 'Inventera', - 'history' => 'Historik', - 'search' => 'Sök'); - private $template_parts = array(); - - public function __construct() { - parent::__construct(); - $this->template_parts = get_fragments('./html/base.html'); - - if(isset($_GET['page'])) { - $this->page = $_GET['page']; - } - if(isset($this->menuitems[$this->page])) { - $this->subtitle = $this->menuitems[$this->page]; - } - } - - public function render() { - $this->render_head(); - $this->render_body(); - if($this->error) { - $this->render_error(); - } - $this->render_foot(); - } - - final private function render_head() { - $headtitle = $this->title; - $pagetitle = $this->title; - if($this->subtitle) { - $headtitle .= ' - '. $this->subtitle; - $pagetitle = $this->subtitle; - } - $query = ''; - if(isset($_GET['q'])) { - $query = $_GET['q']; - } - print(replace( - array('title' => $headtitle, - 'menu' => $this->build_menu(), - 'query'=> $query), - $this->template_parts['head'] - )); - print(replace(array('title' => $pagetitle), - $this->fragments['title'])); - } - - private function build_menu() { - $menu = ''; - foreach($this->menuitems as $page => $title) { - $align = 'left'; - $active = ''; - if($this->page == $page) { - $active = 'active'; - } - if($page == 'search') { - $align = 'right'; - } - $menu .= replace(array('title' => $title, - 'page' => $page, - 'align' => $align, - 'active' => $active), - $this->template_parts['menuitem']); - } - return $menu; - } - - final private function render_error() { - print(replace(array('type' => 'error', - 'message' => $this->error), - $this->fragments['message'])); - } - - final private function render_foot() { - print($this->template_parts['foot']); - } - - final protected function build_user_table($users) { - $rows = ''; - foreach($users as $user) { - $replacements = array('name' => '', - 'loan' => '', - 'has_notes' => '', - 'notes' => '', - 'item_link' => ''); - $replacements['name'] = $user->get_name(); - $notes = $user->get_notes(); - if($notes) { - $replacements['notes'] = $notes; - $replacements['has_notes'] = '*'; - } - $userlink = replace(array('id' => $user->get_id(), - 'name' => $user->get_displayname(), - 'page' => 'users'), - $this->fragments['item_link']); - $replacements['item_link'] = $userlink; - $loans = $user->get_loans('active'); - $loan_str = ''; - $count = count($loans); - switch($count) { - case 0: - break; - case 1: - $product = $loans[0]->get_product(); - $loan_str = $product->get_name(); - break; - default: - $loan_str = $count .' artiklar'; - break; - } - $replacements['loan'] = $loan_str; - $rows .= replace($replacements, $this->fragments['user_row']); - } - return replace(array('rows' => $rows), - $this->fragments['user_table']); - } - - final protected function build_product_table($products) { - $rows = ''; - foreach($products as $product) { - $prodlink = replace(array('id' => $product->get_id(), - 'name' => $product->get_name(), - 'page' => 'products'), - $this->fragments['item_link']); - $available = 'Tillgänglig'; - $status = 'available'; - $discarded = $product->get_discardtime(); - if($discarded) { - $available = 'Skrotad '.$discarded; - $status = 'discarded'; - } else { - $loan = $product->get_active_loan(); - if($loan) { - $user = $loan->get_user(); - $userlink = replace(array('name' => $user->get_displayname(), - 'id' => $user->get_id(), - 'page' => 'users'), - $this->fragments['item_link']); - $available = 'Utlånad till '.$userlink; - if($loan->is_overdue()) { - $status = 'overdue'; - $available .= ', försenad'; - } else { - $status = 'on_loan'; - $available .= ', åter '.$loan->get_duration()['end']; - } - } - } - $rows .= replace(array('available' => $available, - 'status' => $status, - 'item_link' => $prodlink), - $this->fragments['product_row']); - } - return replace(array('rows' => $rows), - $this->fragments['product_table']); - } - - final protected function build_user_loan_table($loans, $show = 'none') { - $vis_return = 'hidden'; - $vis_renew = 'hidden'; - switch($show) { - case 'return': - $vis_return = ''; - break; - case 'renew': - $vis_renew = ''; - break; - case 'both': - $vis_return = ''; - $vis_renew = ''; - break; - case 'none': - break; - default: - throw new Exception('Invalid argument.'); - } - $rows = ''; - foreach($loans as $loan) { - $product = $loan->get_product(); - $prodlink = replace(array('id' => $product->get_id(), - 'name' => $product->get_name(), - 'page' => 'products'), - $this->fragments['item_link']); - $available = ''; - $duration = $loan->get_duration(); - $status = 'on_loan'; - if($loan->is_overdue()) { - $status = 'overdue'; - } - $returndate = ''; - if($duration['return'] !== null) { - $returndate = $duration['return']; - } - $rows .= replace(array('id' => $product->get_id(), - 'item_link' => $prodlink, - 'start_date' => $duration['start'], - 'end_date' => $duration['end'], - 'return_date' => $returndate, - 'status' => $status, - 'vis_renew' => $vis_renew, - 'vis_return' => $vis_return, - 'end_new' => $duration['end_renew']), - $this->fragments['loan_row']); - } - return replace(array('rows' => $rows, - 'vis_renew' => $vis_renew, - 'vis_return' => $vis_return, - 'item' => 'Artikel'), - $this->fragments['loan_table']); - } - - final protected function build_product_loan_table($loans) { - $rows = ''; - $renew_column_visible = 'hidden'; - foreach($loans as $loan) { - $user = $loan->get_user(); - $product = $loan->get_product(); - $userlink = replace(array('id' => $user->get_id(), - 'name' => $user->get_name(), - 'page' => 'users'), - $this->fragments['item_link']); - $available = ''; - $duration = $loan->get_duration(); - $status = 'on_loan'; - if($loan->is_overdue()) { - $status = 'overdue'; - } - $returndate = ''; - $renew_visible = ''; - if($duration['return']) { - $returndate = $duration['return']; - $renew_visible = 'hidden'; - } else { - $renew_column_visible = ''; - } - $rows .= replace(array('item_link' => $userlink, - 'start_date' => $duration['start'], - 'end_date' => $duration['end'], - 'return_date' => $returndate, - 'status' => $status, - 'vis_renew' => $renew_column_visible, - 'vis_renew_button' => $renew_visible, - 'vis_return' => '', - 'id' => $product->get_id(), - 'end_new' => $duration['end_renew']), - $this->fragments['loan_row']); - } - return replace(array('rows' => $rows, - 'vis_renew' => $renew_column_visible, - 'vis_return' => '', - 'item' => 'Låntagare'), - $this->fragments['loan_table']); - } - - final protected function build_inventory_details($inventory, - $interactive = true) { - $duration = $inventory->get_duration(); - $all_products = get_items('product'); - $seen = $inventory->get_seen_products(); - $unseen = array(); - foreach($all_products as $product) { - if(!in_array($product, $seen)) { - $unseen[] = $product; - } - } - $missing = 'Saknade artiklar'; - $hidden = 'hidden'; - if($interactive) { - $missing = 'Kvarvarande artiklar'; - $hidden = ''; - } - $out = replace(array('start_date' => $duration['start'], - 'total_count' => count($all_products), - 'seen_count' => count($seen), - 'hide' => $hidden), - $this->fragments['inventory_do']); - $out .= replace(array('title' => $missing), - $this->fragments['subtitle']); - if($unseen) { - $out .= $this->build_product_table($unseen); - } else { - $out .= 'Inga artiklar saknas.'; - } - $out .= replace(array('title' => 'Inventerade artiklar'), - $this->fragments['subtitle']); - if($seen) { - $out .= $this->build_product_table($seen); - } else { - $out .= 'Inga artiklar inventerade.'; - } - return $out; - } -} - -class SearchPage extends Page { - private $terms = array(); - - public function __construct() { - parent::__construct(); - unset($_GET['page']); - if(isset($_GET['q']) && !$_GET['q']) { - unset($_GET['q']); - } - $this->terms = $this->translate_keys($_GET); - } - - private function do_search() { - $out = array(); - if(!$this->terms) { - return $out; - } - foreach(array('user', 'product') as $type) { - $result = $this->search($type, $this->terms); - if($result) { - $out[$type] = $result; - } - } - return $out; - } - - private function translate_keys($terms) { - $translated = array(); - foreach($terms as $key => $value) { - $newkey = $key; - switch($key) { - case 'q': - $newkey = 'fritext'; - break; - case 'namn': - $newkey = 'name'; - break; - case 'faktura': - case 'fakturanummer': - $newkey = 'invoice'; - break; - case 'serienummer': - $newkey = 'serial'; - break; - case 'tagg': - $newkey = 'tag'; - break; - case 'status': - $value = $this->translate_values($value); - break; - } - if(!array_key_exists($newkey, $translated)) { - $translated[$newkey] = $value; - } else { - $temp = $translated[$newkey]; - $translated[$newkey] = array_merge((array)$temp, (array)$value); - } - } - return $translated; - } - - private function translate_values($value) { - if(!is_array($value)) { - $value = array($value); - } - $translated = array(); - foreach($value as $item) { - $newitem = $item; - switch($item) { - case 'ute': - case 'utlånad': - case 'utlånat': - case 'lånad': - case 'lånat': - $newitem = 'on_loan'; - break; - case 'inne': - case 'ledig': - case 'ledigt': - case 'tillgänglig': - case 'tillgängligt': - $newitem = 'no_loan'; - break; - case 'sen': - case 'sent': - case 'försenad': - case 'försenat': - case 'överdraget': - $newitem = 'overdue'; - break; - case 'skrotad': - case 'skrotat': - case 'slängd': - case 'slängt': - $newitem = 'discarded'; - break; - } - $translated[] = $newitem; - } - return $translated; - } - - private function search($type, $terms) { - $items = get_items($type); - $out = array(); - foreach($items as $item) { - if($item->matches($terms)) { - $out[] = $item; - } - } - return $out; - } - - protected function render_body() { - $terms = ''; - foreach($this->terms as $key => $value) { - if(!is_array($value)) { - $terms .= replace(array('term' => ucfirst($key).": $value", - 'key' => $key, - 'value' => $value), - $this->fragments['search_term']); - } else { - foreach($value as $item) { - $terms .= replace(array('term' => ucfirst($key).": $item", - 'key' => $key, - 'value' => $item), - $this->fragments['search_term']); - } - } - } - print(replace(array('terms' => $terms), - $this->fragments['search_form'])); - if($this->terms) { - $hits = $this->do_search(); - print(replace(array('title' => 'Sökresultat'), - $this->fragments['title'])); - $result = ''; - if(isset($hits['user'])) { - $result = replace(array('title' => 'Låntagare'), - $this->fragments['subtitle']); - $result .= $this->build_user_table($hits['user']); - } - if(isset($hits['product'])) { - $result .= replace(array('title' => 'Artiklar'), - $this->fragments['subtitle']); - $result .= $this->build_product_table($hits['product']); - } - if(!$result) { - $result = 'Inga träffar.'; - } - print($result); - } - } -} - -class ProductPage extends Page { - private $action = 'list'; - private $template = null; - private $product = null; - - public function __construct() { - parent::__construct(); - if(isset($_GET['action'])) { - $this->action = $_GET['action']; - } - if(isset($_GET['template'])) { - $template = $_GET['template']; - if($template) { - try { - $this->template = new Template($template, 'name'); - } catch(Exception $e) { - $this->template = null; - $this->error = 'Det finns ingen mall med det namnet.'; - } - } - } - if(isset($_GET['id'])) { - $id = $_GET['id']; - if($id) { - try { - $this->product = new Product($id); - } catch(Exception $e) { - $this->action = 'list'; - $this->product = null; - $this->error = 'Det finns ingen artikel med det ID-numret.'; - } - } - } - switch($this->action) { - case 'show': - $this->subtitle = 'Artikeldetaljer'; - break; - case 'new': - $this->subtitle = 'Ny artikel'; - break; - case 'list': - $this->subtitle = 'Artikellista'; - break; - } - } - - protected function render_body() { - switch($this->action) { - case 'list': - print($this->fragments['create_product']); - print($this->build_product_table(get_items('product'))); - break; - case 'show': - print($this->build_product_details()); - break; - case 'new': - print($this->build_new_page()); - break; - } - } - - private function build_product_details() { - $info = ''; - foreach($this->product->get_info() as $key => $value) { - $info .= replace(array('name' => ucfirst($key), - 'key' => $key, - 'value' => $value), - $this->fragments['info_item']); - } - $tags = ''; - foreach($this->escape_tags($this->product->get_tags()) as $tag) { - $tags .= replace(array('tag' => ucfirst($tag)), - $this->fragments['tag']); - } - $fields = array('id' => $this->product->get_id(), - 'name' => $this->product->get_name(), - 'serial' => $this->product->get_serial(), - 'invoice' => $this->product->get_invoice(), - 'tags' => $tags, - 'info' => $info); - $label = ''; - if(class_exists('QRcode', false)) { - $label = replace($fields, $this->fragments['product_label']); - } - $fields['label'] = $label; - $out = replace($fields, $this->fragments['product_details']); - if(!$this->product->get_discardtime()) { - $out .= replace(array('id' => $this->product->get_id()), - $this->fragments['discard_button']); - } - $out .= replace(array('title' => 'Lånehistorik'), - $this->fragments['subtitle']); - $loan_table = 'Inga lån att visa.'; - $history = $this->product->get_loan_history(); - if($history) { - $loan_table = $this->build_product_loan_table($history); - } - $out .= $loan_table; - return $out; - } - - private function build_new_page() { - $template = ''; - $fields = ''; - $tags = ''; - if($this->template) { - $template = $this->template->get_name(); - foreach($this->template->get_fields() as $field) { - $fields .= replace(array('name' => ucfirst($field), - 'key' => $field, - 'value' => ''), - $this->fragments['info_item']); - } - foreach($this->template->get_tags() as $tag) { - $tags .= replace(array('tag' => ucfirst($tag)), - $this->fragments['tag']); - } - } - $out = replace(array('template' => $template), - $this->fragments['template_management']); - $out .= replace(array('id' => '', - 'name' => '', - 'serial' => '', - 'invoice' => '', - 'tags' => $tags, - 'info' => $fields, - 'label' => ''), - $this->fragments['product_details']); - return $out; - } -} - -class UserPage extends Page { - private $action = 'list'; - private $user = null; - - public function __construct() { - parent::__construct(); - if(isset($_GET['action'])) { - $this->action = $_GET['action']; - } - if(isset($_GET['id'])) { - $id = $_GET['id']; - if($id) { - try { - $this->user = new User($_GET['id']); - } catch(Exception $e) { - $this->user = null; - $this->action = 'list'; - $this->error = 'Det finns ingen användare med det ID-numret.'; - } - } - } - switch($this->action) { - case 'show': - $this->subtitle = 'Låntagardetaljer'; - break; - case 'list': - $this->subtitle = 'Låntagarlista'; - break; - } - } - - protected function render_body() { - switch($this->action) { - case 'list': - print($this->build_user_table(get_items('user'))); - break; - case 'show': - print($this->build_user_details()); - break; - } - } - - private function build_user_details() { - $active_loans = $this->user->get_loans('active'); - $table_active = 'Inga aktuella lån.'; - if($active_loans) { - $table_active = $this->build_user_loan_table($active_loans, 'renew'); - } - $inactive_loans = $this->user->get_loans('inactive'); - $table_inactive = 'Inga gamla lån.'; - if($inactive_loans) { - $table_inactive = $this->build_user_loan_table($inactive_loans, - 'return'); - } - return replace(array('active_loans' => $table_active, - 'inactive_loans' => $table_inactive, - 'id' => $this->user->get_id(), - 'name' => $this->user->get_name(), - 'displayname' => $this->user->get_displayname(), - 'notes' => $this->user->get_notes()), - $this->fragments['user_details']); - } -} - -class CheckoutPage extends Page { - private $userstr = ''; - private $user = null; - - public function __construct() { - parent::__construct(); - if(isset($_GET['user'])) { - $this->userstr = $_GET['user']; - try { - $this->user = new User($this->userstr, 'name'); - } catch(Exception $ue) { - try { - $ldap = new Ldap(); - $ldap->get_user($this->userstr); - $this->user = User::create_user($this->userstr); - } catch(Exception $le) { - $this->error = "Användarnamnet '"; - $this->error .= $this->userstr; - $this->error .= "' kunde inte hittas."; - } - } - } - } - - protected function render_body() { - $username = ''; - $displayname = ''; - $notes = ''; - $loan_table = ''; - $subhead = ''; - $enddate = ''; - $disabled = 'disabled'; - if($this->user !== null) { - $username = $this->user->get_name(); - $displayname = $this->user->get_displayname(); - $notes = $this->user->get_notes(); - $enddate = gmdate('Y-m-d', time() + 604800); # 1 week from now - $disabled = ''; - $loans = $this->user->get_loans('active'); - $loan_table = 'Inga pågående lån.'; - if($loans) { - $loan_table = $this->build_user_loan_table($loans, 'renew'); - } - $subhead = replace(array('title' => 'Lånade artiklar'), - $this->fragments['subtitle']); - } - print(replace(array('user' => $this->userstr, - 'displayname' => $displayname, - 'notes' => $notes, - 'end' => $enddate, - 'subtitle' => $subhead, - 'disabled' => $disabled, - 'loan_table' => $loan_table), - $this->fragments['checkout_page'])); - } -} - -class ReturnPage extends Page { - protected function render_body() { - print($this->fragments['return_page']); - } -} - -class InventoryPage extends Page { - private $inventory = null; - - public function __construct() { - parent::__construct(); - $this->inventory = Inventory::get_active(); - } - - protected function render_body() { - if($this->inventory === null) { - print($this->fragments['inventory_start']); - return; - } - print($this->build_inventory_details($this->inventory)); - } -} - -class HistoryPage extends Page { - private $action = 'list'; - private $inventory = null; - - public function __construct() { - parent::__construct(); - if(isset($_GET['action'])) { - $this->action = $_GET['action']; - } - if(isset($_GET['id'])) { - try { - $this->inventory = new Inventory($_GET['id']); - } catch(Exception $e) { - $this->inventory = null; - $this->action = 'list'; - $this->error = 'Det finns ingen inventering med det ID-numret.'; - } - } - switch($this->action) { - case 'show': - $this->subtitle = 'Inventeringsdetaljer'; - break; - case 'list': - $this->subtitle = 'Genomförda inventeringar'; - break; - } - } - - protected function render_body() { - switch($this->action) { - case 'list': - print($this->build_inventory_table()); - print(replace(array('title' => 'Skrotade artiklar'), - $this->fragments['title'])); - $discards = get_items('product_discarded'); - if($discards) { - print($this->build_product_table($discards)); - } else { - print('Inga artiklar skrotade.'); - } - break; - case 'show': - if($this->inventory && - Inventory::get_active() !== $this->inventory) { - print($this->build_inventory_details($this->inventory, - false)); - } - break; - } - } - - private function build_inventory_table() { - $items = get_items('inventory_old'); - if(!$items) { - return 'Inga inventeringar gjorda.'; - } - $rows = ''; - foreach($items as $inventory) { - $id = $inventory->get_id(); - $inventory_link = replace(array('id' => $id, - 'name' => $id, - 'page' => 'history'), - $this->fragments['item_link']); - $duration = $inventory->get_duration(); - $num_seen = count($inventory->get_seen_products()); - $num_unseen = count($inventory->get_unseen_products()); - $rows .= replace(array('item_link' => $inventory_link, - 'start_date' => $duration['start'], - 'end_date' => $duration['end'], - 'num_seen' => $num_seen, - 'num_unseen' => $num_unseen), - $this->fragments['inventory_row']); - } - return replace(array('item' => 'Tillfälle', - 'rows' => $rows), - $this->fragments['inventory_table']); - } -} - -class Ajax extends Responder { - private $action = ''; - - public function __construct() { - parent::__construct(); - if(isset($_GET['action'])) { - $this->action = $_GET['action']; - } - } - - public function render() { - $out = ''; - switch($this->action) { - default: - $out = new Success('ajax endpoint'); - break; - case 'getfragment': - $out = $this->get_fragment(); - break; - case 'checkout': - $out = $this->checkout_product(); - break; - case 'return': - $out = $this->return_product(); - break; - case 'extend': - $out = $this->extend_loan(); - break; - case 'startinventory': - $out = $this->start_inventory(); - break; - case 'endinventory': - $out = $this->end_inventory(); - break; - case 'inventoryproduct': - $out = $this->inventory_product(); - break; - case 'updateproduct': - $out = $this->update_product(); - break; - case 'updateuser': - $out = $this->update_user(); - break; - case 'savetemplate': - $out = $this->save_template(); - break; - case 'deletetemplate': - $out = $this->delete_template(); - break; - case 'suggest': - $out = $this->suggest(); - break; - case 'discardproduct': - $out = $this->discard_product(); - break; - } - print($out->toJson()); - } - - private function get_fragment() { - $fragment = $_POST['fragment']; - if(isset($this->fragments[$fragment])) { - return new Success($this->fragments[$fragment]); - } - return new Failure("Ogiltigt fragment '$fragment'"); - } - - private function checkout_product() { - $user = new User($_POST['user'], 'name'); - $product = null; - try { - $product = new Product($_POST['product'], 'serial'); - } catch(Exception $e) { - return new Failure('Ogiltigt serienummer.'); - } - try { - $user->create_loan($product, $_POST['end']); - return new Success($product->get_name() . 'utlånad.'); - } catch(Exception $e) { - return new Failure('Artikeln är redan utlånad.'); - } - } - - private function return_product() { - $product = null; - try { - $product = new Product($_POST['serial'], 'serial'); - } catch(Exception $e) { - return new Failure('Ogiltigt serienummer.'); - } - $loan = $product->get_active_loan(); - if($loan) { - $loan->end(); - $user = $loan->get_user(); - $userlink = replace(array('page' => 'users', - 'id' => $user->get_id(), - 'name' => $user->get_displayname()), - $this->fragments['item_link']); - $productlink = replace(array('page' => 'products', - 'id' => $product->get_id(), - 'name' => $product->get_name()), - $this->fragments['item_link']); - $user = $loan->get_user(); - return new Success($productlink . ' åter från ' . $userlink); - } - return new Failure('Artikeln är inte utlånad.'); - } - - private function extend_loan() { - $product = null; - try { - $product = new Product($_POST['product']); - } catch(Exception $e) { - return new Failure('Ogiltigt ID.'); - } - $loan = $product->get_active_loan(); - if($loan) { - $loan->extend($_POST['end']); - return new Success('Lånet förlängt'); - } - return new Failure('Lån saknas.'); - } - - private function start_inventory() { - try { - Inventory::begin(); - return new Success('Inventering startad.'); - } catch(Exception $e) { - return new Failure('Inventering redan igång.'); - } - } - - private function end_inventory() { - $inventory = Inventory::get_active(); - if($inventory === null) { - return new Failure('Ingen inventering pågår.'); - } - $inventory->end(); - return new Success('Inventering avslutad.'); - } - - private function inventory_product() { - $inventory = Inventory::get_active(); - if($inventory === null) { - return new Failure('Ingen inventering pågår.'); - } - $product = null; - try { - $product = new Product($_POST['serial'], 'serial'); - } catch(Exception $e) { - return new Failure('Ogiltigt serienummer.'); - } - $result = $inventory->add_product($product); - if(!$result) { - return new Failure('Artikeln är redan registrerad.'); - } - return new Success('Artikeln registrerad.'); - } - - private function update_product() { - $info = $_POST; - $id = $info['id']; - $name = $info['name']; - $serial = $info['serial']; - $invoice = $info['invoice']; - $tags = array(); - if(isset($info['tag'])) { - $tags = $this->unescape_tags($info['tag']); - } - foreach(array('id', 'name', 'serial', 'invoice', 'tag') as $key) { - unset($info[$key]); - } - if(!$name) { - return new Failure('Artikeln måste ha ett namn.'); - } - if(!$serial) { - return new Failure('Artikeln måste ha ett serienummer.'); - } - if(!$invoice) { - return new Failure('Artikeln måste ha ett fakturanummer.'); - } - $product = null; - if(!$id) { - try { - $temp = new Product($serial, 'serial'); - return new Failure( - 'Det angivna serienumret finns redan på en annan artikel.'); - } catch(Exception $e) {} - try { - $product = Product::create_product($name, - $invoice, - $serial, - $info, - $tags); - $prodlink = replace(array('page' => 'products', - 'id' => $product->get_id(), - 'name' => $product->get_name()), - $this->fragments['item_link']); - return new Success("Artikeln '$prodlink' sparad."); - } catch(Exception $e) { - return new Failure($e->getMessage()); - } - } - $product = new Product($id); - if($product->get_discardtime()) { - return new Failure('Skrotade artiklar får inte modifieras.'); - } - if($name != $product->get_name()) { - $product->set_name($name); - } - if($serial != $product->get_serial()) { - try { - $product->set_serial($serial); - } catch(Exception $e) { - return new Failure('Det angivna serienumret finns redan på en annan artikel.'); - } - } - if($invoice != $product->get_invoice()) { - $product->set_invoice($invoice); - } - foreach($product->get_info() as $key => $prodvalue) { - if(!isset($info[$key]) || !$info[$key]) { - $product->remove_info($key); - continue; - } - if($prodvalue != $info[$key]) { - $product->set_info($key, $info[$key]); - } - unset($info[$key]); - } - foreach($info as $key => $invalue) { - if($invalue) { - $product->set_info($key, $invalue); - } - } - foreach($product->get_tags() as $tag) { - if(!in_array($tag, $tags)) { - $product->remove_tag($tag); - continue; - } - unset($tags[array_search($tag, $tags)]); - } - foreach($tags as $tag) { - $product->add_tag($tag); - } - return new Success('Ändringarna sparade.'); - } - - private function update_user() { - $id = $_POST['id']; - $name = $_POST['name']; - $notes = $_POST['notes']; - if(!$name) { - return new Failure('Användarnamnet får inte vara tomt.'); - } - $user = new User($id); - if($user->get_name() != $name) { - $user->set_name($name); - } - if($user->get_notes() != $notes) { - $user->set_notes($notes); - } - return new Success('Ändringarna sparade.'); - } - - private function save_template() { - $info = $_POST; - $name = $info['template']; - $tags = array(); - if(isset($info['tag'])) { - $tags = $this->unescape_tags($info['tag']); - } - foreach(array('template', - 'id', - 'name', - 'serial', - 'invoice', - 'tags') as $key) { - unset($info[$key]); - } - if(!$name) { - return new Failure('Mallen måste ha ett namn.'); - } - $template = null; - try { - $template = new Template($name, 'name'); - } catch(Exception $e) { - $template = Template::create_template($name, $info, $tags); - $name = $template->get_name(); - return new Success( - "Aktuella fält och taggar har sparats till mallen '$name'."); - } - foreach($template->get_fields() as $field) { - if(!isset($info[$field])) { - $template->remove_field($field); - } - } - $existingfields = $template->get_fields(); - foreach($info as $field) { - if(!in_array($field, $existingfields)) { - $template->add_field($field); - } - } - foreach($template->get_tags() as $tag) { - if(!in_array($tag, $tags)) { - $template->remove_tag($tag); - } - } - $existingtags = $template->get_tags(); - foreach($tags as $tag) { - if(!in_array($tag, $existingtags)) { - $template->add_tag($tag); - } - } - $name = $template->get_name(); - return new Success("Mallen '$name' uppdaterad."); - } - - private function delete_template() { - try { - $template = $_POST['template']; - Template::delete_template($template); - $name = ucfirst(strtolower($template)); - return new Success("Mallen '$name' har raderats."); - } catch(Exception $e) { - return new Failure('Det finns ingen mall med det namnet.'); - } - } - - private function suggest() { - return new Success(suggest($_POST['type'])); - } - - private function discard_product() { - $product = new Product($_POST['id']); - if(!$product->get_discardtime()) { - if($product->get_active_loan()) { - return new Failure('Artikeln har ett aktivt lån.<br/>' - .'Lånet måste avslutas innan artikeln skrotas.'); - } - $product->discard(); - return new Success('Artikeln skrotad.'); - } else { - return new Failure('Artikeln är redan skrotad.'); - } - } -} - -class QR extends Responder { - protected $product = ''; - - public function __construct() { - parent::__construct(); - if(isset($_GET['id'])) { - $this->product = new Product($_GET['id']); - } - } - - public function render() { - if(class_exists('QRcode', false)) { - QRcode::svg((string)$this->product->get_serial()); - } - } -} - -class Printer extends QR { - public function __construct() { - parent::__construct(); - } - - public function render() { - $label = replace(array('id' => $this->product->get_id(), - 'name' => $this->product->get_name(), - 'serial' => $this->product->get_serial()), - $this->fragments['product_label']); - $title = 'Etikett för artikel '.$this->product->get_serial(); - print(replace(array('title' => $title, - 'label' => $label), - $this->fragments['label_page'])); - } -} - -class Result { - private $type = ''; - private $message = ''; - - public function __construct($type, $message) { - $this->type = $type; - $this->message = $message; - } - - public function toJson() { - return json_encode(array( - 'type' => $this->type, - 'message' => $this->message - )); - } -} - -class Success extends Result { - public function __construct($message) { - parent::__construct('success', $message); - } -} - -class Failure extends Result { - public function __construct($message) { - parent::__construct('error', $message); - } -} -?> diff --git a/index.php b/index.php index b687c0b..5ad5a7d 100755 --- a/index.php +++ b/index.php @@ -1,5 +1,13 @@ <?php -require_once('./include/view.php'); + +set_include_path(get_include_path().PATH_SEPARATOR.'include/'); +spl_autoload_register(function ($class) { + if($class == 'qrcode') { + include('./phpqrcode/qrlib.php'); + } +}); +require('./config.php'); +require('functions.php'); header('Content-Type: text/html; charset=UTF-8');