diff --git a/INSTALL b/INSTALL index 46809af..733b242 100644 --- a/INSTALL +++ b/INSTALL @@ -11,10 +11,14 @@ YMS Installation 1.2 Native GUI - Python GTK3 + - python3-gi + - gir1.2-gtk-3.0 1.3 Web GUI - Webserver - PHP + - php-mysql + - php-xml 2. Create database diff --git a/db/mariadb.sql b/db/mariadb.sql index b0262ed..cf8ca69 100644 --- a/db/mariadb.sql +++ b/db/mariadb.sql @@ -146,11 +146,12 @@ CREATE TABLE inventory ( conttype enum('storage','box') NOT NULL DEFAULT 'storage', sid smallint(6) NOT NULL DEFAULT 1, boxid smallint(6) NOT NULL DEFAULT 1, + eid smallint(6) DEFAULT NULL, number smallint(6) UNSIGNED NOT NULL DEFAULT 1, weight float(5,2) UNSIGNED DEFAULT NULL, price decimal(12,2) DEFAULT NULL, purchdate date DEFAULT NULL, - invcond enum('unknown','good','normal','bad','repairable','defect') NOT NULL default 'unknown', + invcond enum('unknown','new','good','normal','bad','repairable','defect') NOT NULL default 'unknown', remarks varchar(150) DEFAULT NULL, PRIMARY KEY (invid), INDEX ix_invname (invname) @@ -174,6 +175,7 @@ CREATE TABLE measurement ( CREATE TABLE provisions ( provid int(10) NOT NULL AUTO_INCREMENT, provname varchar(40) NOT NULL, + provcat tinyint(3) DEFAULT NULL, sid smallint(6) DEFAULT NULL, number smallint(6) UNSIGNED NOT NULL DEFAULT 1, unit tinyint(3) DEFAULT NULL, @@ -228,7 +230,7 @@ CREATE TABLE company ( contractno varchar(20), remarks varchar(150) DEFAULT NULL, PRIMARY KEY (compid), - UNIQUE INDEX ix_compname (compname) + UNIQUE INDEX ix_compname (compname, comptype) ); diff --git a/webgui/box.php b/webgui/box.php index b26633d..64ddc95 100644 --- a/webgui/box.php +++ b/webgui/box.php @@ -157,7 +157,7 @@ echo '
Referenced in equipment:
\n"; echo "', _('No spare parts found.'), "
\n"; +} + elseif ($action == ACT_EDIT): // ========== VARIANT: edit single record ===================================== diff --git a/webgui/index.php b/webgui/index.php index 1ea7a37..5628651 100644 --- a/webgui/index.php +++ b/webgui/index.php @@ -73,6 +73,9 @@ switch ($submit = form_get_action()) { $p[':beltpos_aft'] = gpc_get_float($_POST, 'beltpos_aft'); $p[':beltpos_bow'] = gpc_get_float($_POST, 'beltpos_bow'); $p[':shapefile'] = gpc_get_string($_POST, 'shapefile'); + if ($p[':shapefile'] == '-1') { + $p[':shapefile'] = NULL; + } $p[':remarks'] = gpc_get_string($_POST, 'remarks', 150); db_exec_update('vessel', $p, 'vid'); $action = ACT_DEFAULT; @@ -93,8 +96,7 @@ require 'header.php'; if ($action == ACT_DEFAULT): // ========== VARIANT: default behavior ======================================= - -echo '
', _('User'), ': ', $user->displayname, ' (', $user->role, ')', "
\n"; @@ -108,7 +110,7 @@ $vid = ($res[0]); // Switch between vessels $sth = $pdo->query("SELECT vid, vesselname, model FROM vessel ORDER BY vid"); $res = $sth->fetchAll(); -echo '| ', _('Number')," | ", $prov->number, " | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ', _('Unit')," | ", $opt_unit[$prov->unit], " | ||||||||||||||||
| ', _('Category')," | ", $opt_category[$prov->provcat] ?? 'n/a', " | ||||||||||||||||
| ', _('Storedate')," | ", $prov->storedate, " | ||||||||||||||||
| ', _('Shelflife')," | $prov->shelflife | ||||||||||||||||
| ', _('Storage')," | ", ($opt_storage[$prov->sid] ?? ''), " | ||||||||||||||||
| ', $row['label'], " | "; - echo '', $row['color'], " | "; + echo '', format_color($row['color']), " | "; echo ''; echo " | ||||||||||||||
| ", $row['tagname'], " | \n"; echo "", $row['description'], " | \n"; - echo "", $row['color'], " | \n"; + echo "", format_color($row['color']), " | \n"; echo "";
// Action buttons
form_action_buttons($g_scriptname, $row['tagid']);
@@ -147,6 +149,50 @@ echo "\n";
elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record =====================================
+$sql = "SELECT tagname, description, color "
+ . "FROM tag "
+ . "WHERE tagid=?";
+$sth = $pdo->prepare($sql);
+$sth->execute([$id]);
+$tag = $sth->fetch(PDO::FETCH_OBJ);
+
+echo '', _('View Tag'), "\n"; + +echo '
', _('Tag usage'), "\n"; +$sql = "SELECT objid, objtype FROM tagref WHERE tagid=?"; +$sth = $pdo->prepare($sql); +$sth->execute([$id]); + +$link = array( + 'equip' => 'equipment.php', + 'inv' => 'inventory.php', + 'prov' => 'provisions.php', + 'doc' => 'documents.php', + 'proj' => 'projects.php', + 'task' => 'task.php', + 'maint' => 'maintenance.php' + ); +echo ''; +if ($sth->rowCount() > 0) { + foreach ($sth->fetchAll() as $row) { + echo '', $row['objid'], '/', $row['objtype'], "\n"; + } +} else { + echo _('Tag is not used anywhere'); +} +echo " \n"; + +echo '', _('Related tags'), "\n"; +echo '', _('Not yet implemented'), " \n"; + elseif ($action == ACT_EDIT): // ========== VARIANT: edit single record ===================================== @@ -181,6 +227,21 @@ echo "\n"; elseif ($action == ACT_DELETE): // ========== VARIANT: delete record ========================================== +echo '', _('Delete tag'), "\n"; + +$sql = "SELECT objid, objtype FROM tagref WHERE tagid=?"; +$sth = $pdo->prepare($sql); +$sth->execute([$id]); +if ($sth->rowCount() > 0) { + foreach ($sth->fetchAll() as $row) { + echo '', $row['objid'], '/', $row['objtype'], "\n"; + } +} else { + echo _('Tag is not used anywhere'); + $_SESSION['token'] = bin2hex(random_bytes(8)); + form_delete_buttons($g_scriptname, $id, $_SESSION['token']); +} + else: // ========== ERROR UNKNOWN VARIANT =========================================== diff --git a/webgui/task.php b/webgui/task.php index 24704af..b910055 100644 --- a/webgui/task.php +++ b/webgui/task.php @@ -13,6 +13,7 @@ $id = gpc_get_int($_REQUEST, 'id', 0); $opt_projects = db_get_opt_proj($user->vid, array(-1 => _('unassigned'))); $opt_priority = db_load_enum('task', 'priority', true, true); +$opt_state = db_load_enum('task', 'taskstate', true, true); // ========== ACTIONS START =================================================== @@ -25,6 +26,15 @@ switch ($submit = form_get_action()) { case 'edit': $action = ACT_EDIT; break; case 'del': $action = ACT_DELETE; break; + case 'filter': + $flt = array(); + $flt['prio'] = gpc_get_enum($_POST, 'flt_prio', array_merge(array_keys($opt_priority), ['-2', '-1'])); + $flt['stat'] = gpc_get_enum($_POST, 'flt_stat', array_merge(array_keys($opt_state), ['-2', '-1'])); + $flt['txt'] = gpc_get_string($_POST, 'flt_txt'); + db_save_filter($flt, 206); + $action = ACT_DEFAULT; + break; + case 'insert': $p[':vid'] = $user->vid; $p[':projid'] = gpc_get_int($_POST, 'projid'); @@ -39,21 +49,52 @@ switch ($submit = form_get_action()) { case 'update': $p[':taskid'] = $id; $p[':projid'] = gpc_get_int($_POST, 'projid'); - $p[':plandate'] = gpc_get_string($_POST, 'plandate'); - $p[':duedate'] = gpc_get_string($_POST, 'duedate'); + $p[':plandate'] = gpc_get_date($_POST, 'plandate'); + $p[':duedate'] = gpc_get_date($_POST, 'duedate'); if ($p[':projid'] == -1) { $p[':projid'] = NULL; } $p[':taskname'] = gpc_get_string($_POST, 'taskname'); $p[':priority'] = gpc_get_string($_POST, 'priority', 10); - if ($p[':priority'] == 'X') { - $p[':projid'] = NULL; + if ($p[':priority'] == '-1') { + $p[':priority'] = NULL; } + $p[':started'] = gpc_get_datetime($_POST, 'started'); + $p[':finished'] = gpc_get_datetime($_POST, 'finished'); + $p[':taskstate'] = gpc_get_enum($_POST, 'taskstate', array_keys($opt_state)); db_exec_update('task', $p, 'taskid'); $action = ACT_VIEW; break; case 'delete': + // Only captain is allowed to delete + if ($user->role != 'captain') { + $g_warning->Add('Only captain is allowed to delete tasks.'); + $action = ACT_VIEW; + break; + } + // Security token needed! + if (gpc_get_string($_POST, 'token', 16) != $_SESSION['token']) { + $g_error->Add(_('Delete prohibited, invalid security token!')); + $action = ACT_VIEW; + break; + } + unset($_SESSION['token']); + // get information for possible redirect + $sth = $pdo->prepare("SELECT projid FROM task WHERE taskid=?"); + $sth->execute([$id]); + $task = $sth->fetch(PDO::FETCH_OBJ); + if (isset($task->projid)) { + $backlink = 'project.php?id='.$task->projid; + } + // now really delete + $sth = $pdo->prepare("DELETE FROM task WHERE taskid=?"); + $sth->execute([$id]); + $g_success->Add(_('Task deleted')); + if (isset($backlink)) { + header_location($backlink, ['info' => _('Note deleted.')]); + } + $action = ACT_DEFAULT; break; default: @@ -71,20 +112,82 @@ require 'header.php'; if ($action == ACT_DEFAULT): // ========== VARIANT: default behavior ======================================= -echo "$pagetitle\n"; +page_caption_search($pagetitle); + +// load filter from db +$flt = db_get_filter($user->id, 206); + +$w = array('(t.vid=:vid OR t.vid IS NULL)'); +$p = array(':vid' => $user->vid); +if (strlen($flt->txt) > 1) { + $w[] = '(taskname LIKE :txt)'; + $p[':txt'] = '%'.$flt->txt.'%'; +} +if (strlen($flt->prio) > 2 ) { + $w[] = 'priority=:priority'; + $p[':priority'] = $flt->prio; +} elseif ($flt->prio == -1) { + $w[] = 'priority IS NULL'; +} +if (strlen($flt->stat) > 2 ) { + $w[] = 'taskstate=:taskstate'; + $p[':taskstate'] = $flt->stat; +} +$where = join(' AND ', $w); +$order = ' ORDER BY t.taskid'; + +// get total recond count for pagination and limit +$sql = "SELECT COUNT(*) FROM task"; +if ($where) $sql .= " WHERE $where"; -$sql = "SELECT t.taskid, t.projid, t.taskname, t.priority, p.projname " - . "FROM task AS t LEFT JOIN project AS p USING (projid) " - . "WHERE p.projid IS NULL OR p.vid=? " - . "ORDER BY t.taskid"; $sth = $pdo->prepare($sql); try { - $sth->execute([$user->vid]); + $sth->execute($p); +} catch(PDOException $e) { + $g_error->Add($e->getMessage()); + $g_error->Add($sql); + $g_error->Add(print_r($p, true)); +} +$numrows = $sth->fetchColumn(); +$lastpage = ceil($numrows/$g_rows_pp); +$page = gpc_get_int($_REQUEST, 'p', 1); + +$sql = "SELECT t.taskid, t.vid, t.projid, t.taskname, t.priority, t.taskstate," + . " p.projname " + . "FROM task AS t LEFT JOIN project AS p USING (projid) " + . "WHERE $where"; +if ($order) $sql .= $order; + +// if pagination: +// $sql .= ' LIMIT ' . ($page - 1) * $g_rows_pp . ',' . $g_rows_pp; +$sth = $pdo->prepare($sql); +try { + $sth->execute($p); } catch (PDOexception $e) { $g_error->Add('SQL-Error: '. $e->getMessage()); + $g_error->Add($sql); + $g_error->Add(print_r($p, true)); } $res = $sth->fetchAll(); +?> +
+
+Filter
+
+prio);
+filter_create_select('flt_stat', _('State'), $g_opt_all + $opt_state, $flt->stat);
+?>
+
+
+
+
+
+# | ';
echo '', _('Task'), " | ";
echo '', _('Project'), " | ";
echo '', _('Priority'), " | ";
+echo '', _('Status'), " | ";
echo "";
echo " | \n";
echo " | | ||||||
| ", $row['taskid'], " | \n"; + // mark generic tasks with braces + echo "", $row['vid'] ? $row['taskid'] : '('.$row['taskid'].')', " | \n"; echo "", $row['taskname'], " | \n"; echo "", $row['projname'], " | \n"; echo "", ($opt_priority[$row['priority']] ?? ''), " | \n"; + echo "", ($opt_state[$row['taskstate']]), " | \n"; // Action buttons form_action_buttons($g_scriptname, $row['taskid']); echo "
| ', _('Task')," | ", $task->taskname, " |
|---|---|
| ', _('Task')," | ", $task->taskname, " |
| ', _('Project')," | ", ($task->projname ?? _('unassigned')), " |
| ', _('Priority')," | ", ($task->priority ?? _('none')), " |
| ', _('Plan date')," | ", $task->plandate, " |
| ', _('Due date')," | ", $task->duedate, " |
| ', _('Started at')," | ", $task->started, " |
| ', _('Finished at')," | ", $task->finished, " |
| ', _('Status')," | ", $opt_state[$task->taskstate], " |
Not yet implemented
"; +echo '', _('Not yet implemented'), "
"; elseif ($action == ACT_EDIT): // ========== VARIANT: edit single record ===================================== -$sql = "SELECT taskname, projid, priority, plandate, duedate, started, finished " +$sql = "SELECT taskname, projid, priority, plandate, duedate, started, finished," + . " taskstate " . "FROM task " . "WHERE taskid=?"; $sth = $pdo->prepare($sql); @@ -228,13 +336,26 @@ form_create_select('priority', _('Priority'), $opt_none + $opt_priority, $task-> taskstate); + form_edit_buttons($g_scriptname, $id); echo "', sprintf(_('Task no. %d'), $id), "
\n"; +echo '', $task->taskname, "
"; + +echo '', _('Deleting a task item is final. There is no way back. Only delete if you are absolute sure.'), "
\n"; +$_SESSION['token'] = bin2hex(random_bytes(8)); +form_delete_buttons($g_scriptname, $id, $_SESSION['token']); else: // ========== ERROR UNKNOWN VARIANT ===========================================