diff --git a/db/mariadb.sql b/db/mariadb.sql index 74017c0..b66a1de 100644 --- a/db/mariadb.sql +++ b/db/mariadb.sql @@ -3,10 +3,12 @@ /* MariaDB Scheme Version: 1 */ -/* TODO +/* REMARKS + - there are by design no created_at, updated_at, updates_by or similar fields + + TODO - check all values if unsigned can be used or not - - implement foreign keys where missing and possible - - add referential actions where appropriate + - add referential actions where appropriate - rename provisions to provision(?) - review defaults */ @@ -66,6 +68,7 @@ CREATE TABLE dropdown ( PRIMARY KEY (ddid, ddval) ) ENGINE=InnoDB; +/* compid is signed because negative values needed for special purpose */ CREATE TABLE company ( compid smallint(6) NOT NULL AUTO_INCREMENT, compname varchar(60) NOT NULL, @@ -110,6 +113,7 @@ CREATE TABLE vessel ( PRIMARY KEY (vid), FOREIGN KEY fk_vessel_shipyard (shipyard) REFERENCES company(compid) + ON DELETE RESTRICT ) ENGINE=InnoDB; CREATE TABLE storage ( @@ -131,13 +135,15 @@ CREATE TABLE storage ( PRIMARY KEY (sid), FOREIGN KEY fk_storage_vessel (vid) REFERENCES vessel(vid) + ON DELETE RESTRICT ) ENGINE=InnoDB; /* intentionally after storage creation */ ALTER TABLE vessel ADD CONSTRAINT fk_vessel_storage FOREIGN KEY (sid_default) - REFERENCES storage(sid); + REFERENCES storage(sid) + ON DELETE RESTRICT; CREATE TABLE tag ( tagid smallint(6) UNSIGNED NOT NULL AUTO_INCREMENT, @@ -153,13 +159,14 @@ CREATE TABLE tagref ( objid int(10) UNSIGNED NOT NULL, objtype enum('equip','inv','prov','doc', 'proj', 'task', 'maint') NOT NULL, PRIMARY KEY (tagid, objid, objtype), + INDEX ix_tagref_obj (objid, objtype), FOREIGN KEY fk_tagref_tag (tagid) REFERENCES tag(tagid) ON DELETE CASCADE ) ENGINE=InnoDB; -/* TODO Boxes can be nested via parent - TODO boxsize: (LxWxH) in cm? */ +/* TODO Boxes can be nested via parent, + very low priority because perhaps rarely used */ CREATE TABLE box ( boxid smallint(6) UNSIGNED NOT NULL AUTO_INCREMENT, sid smallint(6) UNSIGNED NOT NULL, @@ -169,11 +176,18 @@ CREATE TABLE box ( color char(6) DEFAULT NULL, content varchar(60) DEFAULT NULL, weight float(5,2) UNSIGNED DEFAULT NULL, + wx smallint(6) UNSIGNED NOT NULL DEFAULT 0, + wy smallint(6) UNSIGNED NOT NULL DEFAULT 0, + wz smallint(6) UNSIGNED NOT NULL DEFAULT 0, remarks varchar(150) DEFAULT NULL, PRIMARY KEY (boxid), INDEX ix_label (label), FOREIGN KEY fk_box_storage (sid) REFERENCES storage(sid) + ON DELETE RESTRICT, + FOREIGN KEY fk_box_parent (parent) + REFERENCES box(boxid) + ON DELETE RESTRICT ) ENGINE=InnoDB; CREATE TABLE equipment ( @@ -196,6 +210,9 @@ CREATE TABLE equipment ( REFERENCES vessel(vid) ON DELETE RESTRICT, FOREIGN KEY fk_equipment_supplier (supplier) + REFERENCES company(compid) + ON DELETE RESTRICT, + FOREIGN KEY fk_equipment_manufacturer (manufacturer) REFERENCES company(compid) ON DELETE RESTRICT ) ENGINE=InnoDB; @@ -206,7 +223,7 @@ CREATE TABLE inventory ( conttype enum('storage','box') NOT NULL DEFAULT 'storage', sid smallint(6) UNSIGNED DEFAULT NULL, boxid smallint(6) UNSIGNED DEFAULT NULL, - eid smallint(6) UNSIGNED DEFAULT NULL, + eid smallint(6) UNSIGNED DEFAULT NULL, -- spare part reference to equipment number smallint(6) UNSIGNED NOT NULL DEFAULT 1, weight float(5,2) UNSIGNED DEFAULT NULL, price decimal(12,2) DEFAULT NULL, @@ -217,11 +234,14 @@ CREATE TABLE inventory ( PRIMARY KEY (invid), INDEX ix_invname (invname), FOREIGN KEY fk_inventory_storage (sid) - REFERENCES storage(sid), + REFERENCES storage(sid) + ON DELETE RESTRICT, FOREIGN KEY fk_inventory_box (boxid) - REFERENCES box(boxid), + REFERENCES box(boxid) + ON DELETE RESTRICT, FOREIGN KEY fk_inventory_equipment (eid) - REFERENCES equipment(eid), + REFERENCES equipment(eid) + ON DELETE RESTRICT, CHECK ( (sid IS NOT NULL AND boxid IS NULL) OR @@ -248,11 +268,14 @@ CREATE TABLE cable ( PRIMARY KEY (cableid), INDEX ix_cablename (vid, cablename), FOREIGN KEY fk_cable_vessel (vid) - REFERENCES vessel(vid), + REFERENCES vessel(vid) + ON DELETE RESTRICT, FOREIGN KEY fk_cable_supplier (supplier) - REFERENCES company(compid), + REFERENCES company(compid) + ON DELETE RESTRICT, FOREIGN KEY fk_cable_manufacturer (manufacturer) REFERENCES company(compid) + ON DELETE RESTRICT ) ENGINE=InnoDB; CREATE table fuse ( @@ -269,11 +292,14 @@ CREATE table fuse ( PRIMARY KEY (fuseid), UNIQUE INDEX ix_fusenumber (vid, fnumber), FOREIGN KEY fk_fuse_vessel (vid) - REFERENCES vessel(vid), + REFERENCES vessel(vid) + ON DELETE RESTRICT, FOREIGN KEY fk_fuse_cable (cableid) - REFERENCES cable(cableid), + REFERENCES cable(cableid) + ON DELETE RESTRICT, FOREIGN KEY fk_fuse_equipment (eid) REFERENCES equipment(eid) + ON DELETE RESTRICT ) ENGINE=InnoDB; -- change vals to decimal(12,4)? @@ -292,9 +318,11 @@ CREATE TABLE measurement ( note varchar(80) DEFAULT NULL, PRIMARY KEY (mid), FOREIGN KEY fk_measurement_vessel (vid) - REFERENCES vessel(vid), + REFERENCES vessel(vid) + ON DELETE RESTRICT, FOREIGN KEY fk_measurement_equipment (eid) REFERENCES equipment(eid) + ON DELETE RESTRICT ) ENGINE=InnoDB; CREATE TABLE provisions ( @@ -315,9 +343,11 @@ CREATE TABLE provisions ( remarks varchar(150) DEFAULT NULL, PRIMARY KEY (provid), FOREIGN KEY fk_provisions_storage (sid) - REFERENCES storage(sid), + REFERENCES storage(sid) + ON DELETE RESTRICT, FOREIGN KEY fk_provisions_box (boxid) REFERENCES box(boxid) + ON DELETE RESTRICT ) ENGINE=InnoDB; /* TODO @@ -345,19 +375,19 @@ CREATE TABLE document ( CREATE TABLE docref ( drid int(10) NOT NULL AUTO_INCREMENT, - reftype enum('vessel','box','equipment','project','task','user','company') NOT NULL DEFAULT 'vessel', + reftype enum('vessel','box','equipment','project','maint', 'task','user','company') NOT NULL DEFAULT 'vessel', docid smallint(6) NOT NULL, refid int(10) NOT NULL, PRIMARY KEY (drid), UNIQUE INDEX ix_docref (docid, refid, reftype), + INDEX ix_docref_ref (refid, reftype), FOREIGN KEY fk_docref_doc (docid) REFERENCES document (docid) - ON DELETE RESTRICT - ON UPDATE CASCADE + ON DELETE CASCADE ) ENGINE=InnoDB; -/* TODO optional fields: plan date, target date, completion date - interval_hours, last_hours +/* TODO optional fields: target date? + responsible? signalk: operating hours current vs maint every n operating hours in separate */ CREATE TABLE maintenance ( @@ -374,13 +404,14 @@ CREATE TABLE maintenance ( maintstate enum('new','plan','ongoing','done') NOT NULL DEFAULT 'new', PRIMARY KEY (maintid), FOREIGN KEY fk_maintenance_vessel (vid) - REFERENCES vessel(vid), + REFERENCES vessel(vid) + ON DELETE RESTRICT, FOREIGN KEY fk_maintenance_equipment (eid) REFERENCES equipment(eid) + ON DELETE RESTRICT ) ENGINE=InnoDB; -/* TODO? time recording */ - +/* TODO time recording? */ CREATE TABLE project ( projid smallint(6) NOT NULL AUTO_INCREMENT, projname varchar(40) NOT NULL, @@ -394,9 +425,11 @@ CREATE TABLE project ( projstate enum('new','plan','ongoing','paused','finished') NOT NULL DEFAULT 'new', PRIMARY KEY (projid), FOREIGN KEY fk_project_vessel (vid) - REFERENCES vessel(vid), + REFERENCES vessel(vid) + ON DELETE RESTRICT, FOREIGN KEY fk_project_user (responsible) REFERENCES user(userid) + ON DELETE RESTRICT ) ENGINE=InnoDB; /* TODO executed_by : company or user? or both? */ @@ -413,13 +446,17 @@ CREATE TABLE task ( started datetime DEFAULT NULL, finished datetime DEFAULT NULL, responsible smallint(6) NOT NULL, + remarks varchar(150) DEFAULT NULL, PRIMARY KEY (taskid), FOREIGN KEY fk_task_user (responsible) - REFERENCES user(userid), + REFERENCES user(userid) + ON DELETE RESTRICT, FOREIGN KEY fk_task_vessel (vid) - REFERENCES vessel(vid), + REFERENCES vessel(vid) + ON DELETE RESTRICT, FOREIGN KEY fk_task_project (projid) REFERENCES project(projid) + ON DELETE RESTRICT ) ENGINE=InnoDB; /* Notes can be assigned to tasks, maintenances and equipment */ @@ -428,7 +465,12 @@ CREATE TABLE note ( notetype enum('task','maint','equip') NOT NULL DEFAULT 'task', refid int(10) NOT NULL, annotation text NOT NULL, + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_by smallint(6) DEFAULT NULL, PRIMARY KEY (noteid) + FOREIGN KEY fk_note_user (created_by) + REFERENCES user(userid) + ON DELETE RESTRICT ) ENGINE=InnoDB; CREATE TABLE checklist ( @@ -439,6 +481,7 @@ CREATE TABLE checklist ( PRIMARY KEY (clid), FOREIGN KEY fk_checklist_parent (parent) REFERENCES checklist(clid) + ON DELETE RESTRICT ) ENGINE=InnoDB; CREATE TABLE checkgroup ( @@ -455,6 +498,7 @@ CREATE TABLE checkitem ( PRIMARY KEY (checkid), FOREIGN KEY fk_checkitem_group (groupid) REFERENCES checkgroup(groupid) + ON DELETE RESTRICT ) ENGINE=InnoDB; CREATE TABLE checkref ( @@ -483,6 +527,7 @@ CREATE TABLE signalk ( (vid, objtype, objid, datatype), FOREIGN KEY fk_signalk_vessel (vid) REFERENCES vessel(vid) + ON DELETE RESTRICT ) ENGINE=InnoDB; /* Token diff --git a/install.sh b/install.sh index 83d076c..241e30b 100755 --- a/install.sh +++ b/install.sh @@ -15,6 +15,13 @@ SOURCEDIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) if [ "$1" = "uninstall" ]; then echo "Uninstalling YMS..." + if [ "$(id -u)" -ne 0 ]; then + echo "Error: this script must be run as root." + echo "Please use:" + echo " sudo $0" + exit 1 + fi + rm -f "${BINDIR}/yms" rm -rf "${LIBDIR}" rm -rf "${SHAREDIR}" diff --git a/webgui/box.php b/webgui/box.php index 816ba4e..9f5b7c7 100644 --- a/webgui/box.php +++ b/webgui/box.php @@ -14,6 +14,7 @@ There can be a difference because not all items have a weight entered */ require 'globals.inc'; +require 'lib/db.inc'; require 'lib/gpc.inc'; $pagetitle = _('Boxes'); diff --git a/webgui/cable.php b/webgui/cable.php index 44bf457..a9c6818 100644 --- a/webgui/cable.php +++ b/webgui/cable.php @@ -7,6 +7,7 @@ ******************************************************************************/ require 'globals.inc'; +require 'lib/db.inc'; require 'lib/gpc.inc'; $pagetitle = _('Cables'); diff --git a/webgui/checklist.php b/webgui/checklist.php index a16b57a..9b526f9 100644 --- a/webgui/checklist.php +++ b/webgui/checklist.php @@ -7,6 +7,7 @@ ******************************************************************************/ require 'globals.inc'; +require 'lib/db.inc'; require 'lib/gpc.inc'; $pagetitle = _('Checklists'); diff --git a/webgui/company.php b/webgui/company.php index 0c80b73..855b5ae 100644 --- a/webgui/company.php +++ b/webgui/company.php @@ -7,6 +7,7 @@ ******************************************************************************/ require 'globals.inc'; +require 'lib/db.inc'; require 'lib/gpc.inc'; $pagetitle=_('Company'); diff --git a/webgui/dl.php b/webgui/dl.php index 5d5d9f6..581cf71 100644 --- a/webgui/dl.php +++ b/webgui/dl.php @@ -18,6 +18,7 @@ */ require 'globals.inc'; +require 'lib/db.inc'; require 'lib/gpc.inc'; require 'lib/fileutils.inc'; diff --git a/webgui/dropdown.php b/webgui/dropdown.php index de858a9..357f500 100644 --- a/webgui/dropdown.php +++ b/webgui/dropdown.php @@ -7,6 +7,7 @@ ******************************************************************************/ require 'globals.inc'; +require 'lib/db.inc'; require 'lib/gpc.inc'; $pagetitle = _('Lists'); diff --git a/webgui/fuse.php b/webgui/fuse.php index b177267..17ae3ef 100644 --- a/webgui/fuse.php +++ b/webgui/fuse.php @@ -7,6 +7,7 @@ ******************************************************************************/ require 'globals.inc'; +require 'lib/db.inc'; require 'lib/gpc.inc'; $pagetitle = _('Fuses'); diff --git a/webgui/globals.inc b/webgui/globals.inc index 3c1e40f..030653c 100644 --- a/webgui/globals.inc +++ b/webgui/globals.inc @@ -114,14 +114,25 @@ try { $sth = $pdo->query("SELECT valint FROM settings WHERE userid=0 AND sno=0"); } catch (PDOException $e) { if ($e->getCode() == 1146) { - echo '
';
-        echo 'Settings table not found! Perhaps database is not initialized';
-        echo '
'; + echo "
\n";
+        echo "Settings table not found! Perhaps database is not initialized?\n";
+        echo "
\n"; exit(1); } } $g_db_scheme_version = $sth->fetchColumn(); -// TODO Check version +$g_db_scheme_required = 1; +// Schema version check +if ($g_db_scheme_version !== $g_db_scheme_required) { + echo "
\n";
+    echo "Database schema is wrong: detected version $g_db_scheme_version, but required version $g_db_scheme_required!\n";
+    echo "
\n"; + exit(1); +} + +// currency symbol is global +$sth = $pdo->query("SELECT valint FROM settings WHERE userid=0 AND sno=4"); +$g_currsym = $sth->fetchColumn(); $user = User::GetInstance(); // There can be only one if ($g_scriptname != 'login.php') { @@ -1269,6 +1280,20 @@ function format_date($date) { return date($user->datefmt, $timestamp); } +function format_datetime($datetime, $seconds=false) { + // datetime is string in ISO format + global $user; + if (empty($datetime)) { + return ''; + } + $timestamp = strtotime($datetime); + if ($timestamp === false) { + return ''; + } + $timefmt = $seconds ? 'H:i:s' : 'H:i'; + return date($user->datefmt. ' ' . $timefmt, $timestamp); +} + function format_color($color) { $colstr = '', _('Add additional yacht'), "\n";
- +
@@ -602,7 +603,7 @@ form_create_select('sid', _('Default Storage'), $g_opt_none + $opt_storage, $ves ?>
- +
prepare($sql); + $sth->execute([$table, $key, $token, $userid]); + return $token; + } catch (PDOException $e) { + if ($e->errorInfo[1] != 1062) { + throw $e; + } + } + // lazy locking: lock exists but is old, so we use it + $sql = "UPDATE recordlock " + . "SET token=?, userid=?, " + . "created_at=CURRENT_TIMESTAMP, last_seen=CURRENT_TIMESTAMP " + . "WHERE lock_table=? AND lock_key=? " + . "AND last_seenprepare($sql); + $sth->execute([$token, $userid, $table, $key]); + if ($stmt->rowCount() === 1) { + return $token; + } + return null; +} + +function db_lock_refresh($token) { + global $pdo; + $sql = "UPDATE recordlock " + . "SET last_seen=CURRENT_TIMESTAMP " + . "WHERE token=?"; + $sth = $pdo->prepare($sql); + $sth->execute([$token]); + return $sth->rowCount() === 1; +} + + +function db_lock_release($token) { + global $pdo; + $sql = "DELETE FROM recordlock WHERE token=?"; + $sth = $pdo->prepare($sql); + $sth->execute([$token]); + return $sth->rowCount() === 1; +} diff --git a/webgui/maintenance.php b/webgui/maintenance.php index 76c6423..11420e2 100644 --- a/webgui/maintenance.php +++ b/webgui/maintenance.php @@ -7,6 +7,7 @@ ******************************************************************************/ require 'globals.inc'; +require 'lib/db.inc'; require 'lib/gpc.inc'; $pagetitle = _('Maintenance'); @@ -288,7 +289,7 @@ echo '
'; // Column break echo '
'; // TODO Show documents for equipment -echo "

Documents

\n"; +echo '

Documents for ', h($maint->ename), "

\n"; if (isset($docs)) { echo '