Webgui programming

This commit is contained in:
2025-05-09 10:22:08 +02:00
parent c293ca1caa
commit fb93c83388
11 changed files with 340 additions and 85 deletions
+2
View File
@@ -1,3 +1,5 @@
YMS - Yacht Management System YMS - Yacht Management System
Prototype Prototype
Many features are incomplete, buggy or missing.
Use at your own risk!
+4 -1
View File
@@ -217,6 +217,7 @@ CREATE TABLE company (
compid smallint(6) NOT NULL AUTO_INCREMENT, compid smallint(6) NOT NULL AUTO_INCREMENT,
compname varchar(60) NOT NULL, compname varchar(60) NOT NULL,
comptype tinyint(3) NOT NULL DEFAULT 1, comptype tinyint(3) NOT NULL DEFAULT 1,
comptype2 tinyint(3) DEFAULT NULL,
shortname varchar(20) DEFAULT NULL, shortname varchar(20) DEFAULT NULL,
street varchar(30), street varchar(30),
zip varchar(10), zip varchar(10),
@@ -258,7 +259,7 @@ CREATE TABLE project (
costs_plan decimal(12,2) DEFAULT NULL, costs_plan decimal(12,2) DEFAULT NULL,
costs_final decimal(12,2) DEFAULT NULL, costs_final decimal(12,2) DEFAULT NULL,
remarks varchar(150) DEFAULT NULL, remarks varchar(150) DEFAULT NULL,
projstate enum('new','plan','ongoing','finished') NOT NULL DEFAULT 'new', projstate enum('new','plan','ongoing','paused','finished') NOT NULL DEFAULT 'new',
PRIMARY KEY (projid) PRIMARY KEY (projid)
); );
@@ -273,6 +274,8 @@ CREATE TABLE task (
duedate date DEFAULT NULL, duedate date DEFAULT NULL,
started datetime DEFAULT NULL, started datetime DEFAULT NULL,
finished datetime DEFAULT NULL, finished datetime DEFAULT NULL,
responsible smallint(6) NOT NULL,
/* TODO executed_by : company or user? or both? */
PRIMARY KEY (taskid) PRIMARY KEY (taskid)
); );
+1 -1
View File
@@ -6,4 +6,4 @@ mv /var/www/html/config.inc-sample /var/www/html/config.inc
chmod 640 /var/www/html/config.inc chmod 640 /var/www/html/config.inc
chgrp www-data /var/www/html/config.inc chgrp www-data /var/www/html/config.inc
rm /var/www/html/index.html rm /var/www/html/index.html
rm /var/www/html/locale/dc_DE.po rm /var/www/html/locale/de_DE.po
+20 -3
View File
@@ -43,6 +43,7 @@ switch ($submit = form_get_action()) {
$p[':compname'] = gpc_get_string($_POST, 'compname'); $p[':compname'] = gpc_get_string($_POST, 'compname');
$p[':shortname'] = gpc_get_string($_POST, 'shortname', 20); $p[':shortname'] = gpc_get_string($_POST, 'shortname', 20);
$p[':comptype'] = gpc_get_int($_POST, 'comptype'); $p[':comptype'] = gpc_get_int($_POST, 'comptype');
$p[':comptype2'] = gpc_get_int($_POST, 'comptype2');
$p[':street'] = gpc_get_string($_POST, 'street', 30); $p[':street'] = gpc_get_string($_POST, 'street', 30);
$p[':zip'] = gpc_get_string($_POST, 'zip', 10); $p[':zip'] = gpc_get_string($_POST, 'zip', 10);
$p[':city'] = gpc_get_string($_POST, 'city', 30); $p[':city'] = gpc_get_string($_POST, 'city', 30);
@@ -228,8 +229,8 @@ echo '<h2>', _('Add Company'), "</h2>\n";
elseif ($action == ACT_VIEW): elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record ===================================== // ========== VARIANT: view single record =====================================
$sql = "SELECT compname, comptype, shortname, street, zip, city, country," $sql = "SELECT compname, comptype, comptype2, shortname, street, zip, city,"
. " contact, phone, email, web, customerno, contractno, remarks " . " country, contact, phone, email, web, customerno, contractno, remarks "
. "FROM company " . "FROM company "
. "WHERE compid=?"; . "WHERE compid=?";
$sth = $pdo->prepare($sql); $sth = $pdo->prepare($sql);
@@ -242,6 +243,7 @@ echo '<table class="table">', "\n";
echo '<tr><th scope="row" style="width:20%">', _('Name'),"</th><td>", $company->compname, "</td></tr>\n"; echo '<tr><th scope="row" style="width:20%">', _('Name'),"</th><td>", $company->compname, "</td></tr>\n";
echo '<tr><th scope="row">', _('Short name'),"</th><td>", $company->shortname, "</td></tr>\n"; echo '<tr><th scope="row">', _('Short name'),"</th><td>", $company->shortname, "</td></tr>\n";
echo '<tr><th scope="row">', _('Type'),"</th><td>", $opt_comptype[$company->comptype], "</td></tr>\n"; echo '<tr><th scope="row">', _('Type'),"</th><td>", $opt_comptype[$company->comptype], "</td></tr>\n";
echo '<tr><th scope="row">', _('Secondary type'),"</th><td>", $company->comptype2 ? $opt_comptype[$company->comptype2] : '-', "</td></tr>\n";
echo '<tr><th scope="row">', _('Street'),"</th><td>", $company->street, "</td></tr>\n"; echo '<tr><th scope="row">', _('Street'),"</th><td>", $company->street, "</td></tr>\n";
echo '<tr><th scope="row">', _('Zip, City'),"</th><td>", $company->zip, ' ', $company->city, "</td></tr>\n"; echo '<tr><th scope="row">', _('Zip, City'),"</th><td>", $company->zip, ' ', $company->city, "</td></tr>\n";
echo '<tr><th scope="row">', _('Country'),"</th><td>", $company->country, "</td></tr>\n"; echo '<tr><th scope="row">', _('Country'),"</th><td>", $company->country, "</td></tr>\n";
@@ -299,7 +301,7 @@ elseif ($action == ACT_EDIT):
echo '<h2>', _('Edit Company'), "</h2>\n"; echo '<h2>', _('Edit Company'), "</h2>\n";
$sql = "SELECT compname, comptype, street, zip, city, country," $sql = "SELECT compname, comptype, comptype2, street, zip, city, country,"
. " contact, phone, email, web, customerno, contractno, remarks " . " contact, phone, email, web, customerno, contractno, remarks "
. "FROM company " . "FROM company "
. "WHERE compid=?"; . "WHERE compid=?";
@@ -332,6 +334,21 @@ foreach ($opt_comptype as $k => $v) {
?> ?>
</select> </select>
</div> </div>
<div class="mb-3">
<label for="comptype2" class="form-label"><?=_('Secondary company type')?></label>
<select name="comptype2" class="form-control">
<?php
echo '<option value="">--- kein ---', "</option>\n";
foreach ($opt_comptype as $k => $v) {
echo '<option value="', $k ,'"';
if ($company->comptype2 == $k) {
echo ' selected';
}
echo '>', $v, "</option>\n";
}
?>
</select>
</div>
<div class="mb-3"> <div class="mb-3">
<label for="street" class="form-label"><?=_('Street')?></label> <label for="street" class="form-label"><?=_('Street')?></label>
<input type="text" class="form-control" id="street" name="street" value="<?=$company->street ?>"> <input type="text" class="form-control" id="street" name="street" value="<?=$company->street ?>">
+7
View File
@@ -35,6 +35,13 @@ $g_shapedir = 'shapes';
// documents and images // documents and images
$g_doc_basepath = '/var/local/yms'; $g_doc_basepath = '/var/local/yms';
$g_doc_maxsize = 1024*1024*16; // 16 MB $g_doc_maxsize = 1024*1024*16; // 16 MB
$g_doc_typemap = array(
'generic' => 'doc',
'manual' => 'doc',
'invoice' => 'doc',
'picture' => 'pic',
'drawing' => 'drw'
);
$g_storage_limit = 1024; // MB $g_storage_limit = 1024; // MB
+12 -1
View File
@@ -42,6 +42,17 @@ switch ($submit = form_get_action()) {
case 'insert': case 'insert':
// WIP New standalone document // WIP New standalone document
// debug $g_message->Add(print_r($_FILES, true)); // debug $g_message->Add(print_r($_FILES, true));
// check for possible errors
if (!isset($_FILES['files']['error']) || is_array($_FILES['files']['error'])) {
$g_error->Add(_("Invalid file upload parameters."));
$action = ACT_ADD;
break;
}
if (($_FILES['files']['error'] == UPLOAD_ERR_INI_SIZE) || ($_FILES['files']['error'] == UPLOAD_ERR_FORM_SIZE)) {
$g_error->Add(_("Exceeded filesize limit."));
$action = ACT_ADD;
break;
}
if (empty($_FILES['files']['tmp_name']) ) { if (empty($_FILES['files']['tmp_name']) ) {
$g_warning->Add(_('No file for upload submitted. Try again by selecting a file first.')); $g_warning->Add(_('No file for upload submitted. Try again by selecting a file first.'));
$action = ACT_ADD; $action = ACT_ADD;
@@ -117,7 +128,7 @@ switch ($submit = form_get_action()) {
$p[':doctype'] = gpc_get_string($_POST, 'doctype'); $p[':doctype'] = gpc_get_string($_POST, 'doctype');
$p[':filename'] = gpc_get_string($_POST, 'filename'); $p[':filename'] = gpc_get_string($_POST, 'filename');
$p[':title'] = gpc_get_string($_POST, 'title', 40); $p[':title'] = gpc_get_string($_POST, 'title', 40);
$p['remarks'] = gpc_get_string($_POST, 'remarks', 150); $p[':remarks'] = gpc_get_string($_POST, 'remarks', 150);
db_exec_update('document', $p, 'docid'); db_exec_update('document', $p, 'docid');
$action = ACT_VIEW; $action = ACT_VIEW;
break; break;
+262 -52
View File
@@ -50,9 +50,9 @@ setlocale(LC_ALL, $g_locale);
$g_lconv = localeconv(); $g_lconv = localeconv();
$g_lang = substr($g_locale, 0, 2); // short language identifier $g_lang = substr($g_locale, 0, 2); // short language identifier
bindtextdomain('yms', 'locale'); bindtextdomain($g_textdomain, 'locale');
bind_textdomain_codeset('yms', 'UTF-8'); bind_textdomain_codeset($g_textdomain, 'UTF-8');
textdomain('yms'); textdomain($g_textdomain);
date_default_timezone_set($g_timezone); date_default_timezone_set($g_timezone);
@@ -63,12 +63,18 @@ if ($g_scriptname != 'login.php') {
$_SESSION['prelogin'] = $_SERVER['REQUEST_URI']; $_SESSION['prelogin'] = $_SERVER['REQUEST_URI'];
header_location('login.php'); header_location('login.php');
} }
$g_referrer = $_SESSION['coming_from']; $g_referrer = $_SESSION['coming_from'] ?? $g_scriptname;
$_SESSION['coming_from'] = $g_scriptname; $_SESSION['coming_from'] = $g_scriptname;
} }
// database // database
$pdo = new PDO("mysql:host=$g_db_host;dbname=$g_db_schema;charset=utf8mb4", $g_db_username, $g_db_password); try {
$pdo = new PDO("mysql:host=$g_db_host;dbname=$g_db_schema;charset=utf8mb4", $g_db_username, $g_db_password);
} catch (PDOException $e) {
echo '<pre>';
print_r($e);
echo '</pre>';
}
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
# $pdo->query("SET lc_time_names='de_DE'"); # $pdo->query("SET lc_time_names='de_DE'");
@@ -87,6 +93,10 @@ $valid = FALSE;
// document storage // document storage
$g_doc_mimetypes = ['image/png', 'image/jpeg', 'image/svg+xml', 'application/pdf']; $g_doc_mimetypes = ['image/png', 'image/jpeg', 'image/svg+xml', 'application/pdf'];
// form option lists
$g_opt_all = array(-2 => _('&horbar; all &horbar;'));
$g_opt_none = array(-1 => _('&horbar; none &horbar;'));
// Initialize message system // Initialize message system
$g_message = new Message; $g_message = new Message;
$g_success = new MessageSuccess; $g_success = new MessageSuccess;
@@ -105,6 +115,10 @@ class Message {
function __construct() { function __construct() {
$this->caption = _('Information'); $this->caption = _('Information');
$this->alertclass = 'alert-info'; $this->alertclass = 'alert-info';
if (isset($_SESSION['message']['info'])) {
$this->Add($_SESSION['message']['info']);
unset($_SESSION['message']['info']);
}
} }
function SetCaption($str) { function SetCaption($str) {
@@ -140,6 +154,10 @@ class MessageSuccess extends Message {
function __construct() { function __construct() {
$this->caption = _('Success'); $this->caption = _('Success');
$this->alertclass = 'alert-success'; $this->alertclass = 'alert-success';
if (isset($_SESSION['message']['succ'])) {
$this->Add($_SESSION['message']['succ']);
unset($_SESSION['message']['succ']);
}
} }
} }
@@ -147,6 +165,10 @@ class MessageWarning extends Message {
function __construct() { function __construct() {
$this->caption = _('Warning'); $this->caption = _('Warning');
$this->alertclass = 'alert-warning'; $this->alertclass = 'alert-warning';
if (isset($_SESSION['message']['warn'])) {
$this->Add($_SESSION['message']['warn']);
unset($_SESSION['message']['warn']);
}
} }
} }
@@ -154,6 +176,10 @@ class MessageError extends Message {
function __construct() { function __construct() {
$this->caption = _('Error'); $this->caption = _('Error');
$this->alertclass = 'alert-danger'; $this->alertclass = 'alert-danger';
if (isset($_SESSION['message']['err'])) {
$this->Add($_SESSION['message']['err']);
unset($_SESSION['message']['err']);
}
} }
} }
@@ -209,7 +235,9 @@ class User {
// password check successful // password check successful
$_SESSION['userid'] = $row->userid; $_SESSION['userid'] = $row->userid;
$this->loggedin = TRUE; $this->loggedin = TRUE;
header_location($_SESSION['prelogin'] ?? 'index.php'); $target = $_SESSION['prelogin'] ?? 'index.php';
unset($_SESSION['prelogin']);
header_location($target);
} else { } else {
$this->errormessage = _('Username or password invalid'); $this->errormessage = _('Username or password invalid');
} }
@@ -344,13 +372,17 @@ function db_save_filter($flt, $sno) {
} }
function get_enum($enum) { function get_enum($enum) {
// Translate and beautify enums // translate and beautify enums
$lookup = array( $lookup = array(
'NULL' => _('n/a'),
'bad' => _('Bad'), 'bad' => _('Bad'),
'box' => _('Box'), 'box' => _('Box'),
'cat' => _('Catamaran'), 'cat' => _('Catamaran'),
'completed' => _('Completed'),
'closed' => _('Closed'), 'closed' => _('Closed'),
'company' => _('Company'),
'defect' => _('Defect'), 'defect' => _('Defect'),
'deleted' => _('Deleted'),
'done' => _('Done'), 'done' => _('Done'),
'drawing' => _('Drawing'), 'drawing' => _('Drawing'),
'equipment' => _('Equipment'), 'equipment' => _('Equipment'),
@@ -364,40 +396,52 @@ function get_enum($enum) {
'locked' => _('Locked'), 'locked' => _('Locked'),
'low' => _('Low'), 'low' => _('Low'),
'manual' => _('Manual'), 'manual' => _('Manual'),
'mediim' => _('Medium'), 'medium' => _('Medium'),
'mono' => _('Monohull'), 'mono' => _('Monohull'),
'new' => _('New'), 'new' => _('New'),
'none' => _('None'),
'normal' => _('Normal'), 'normal' => _('Normal'),
'ongoing' => _('Ongoing'), 'ongoing' => _('Ongoing'),
'open' => _('Open'), 'open' => _('Open'),
'paused' => _('Paused'),
'pending' => _('Pending'),
'picture' => _('Picture'), 'picture' => _('Picture'),
'planned' => _('Planned'), 'planned' => _('Planned'),
'precise' => _('Precise'), 'precise' => _('Precise'),
'project' => _('Project'),
'repairable' => _('Repairable'), 'repairable' => _('Repairable'),
'rough' => _('Rough'), 'rough' => _('Rough'),
'storage' => _('Storage'), 'storage' => _('Storage'),
'task' => _('Task'), 'task' => _('Task'),
'tri' => _('Trimaran'), 'tri' => _('Trimaran'),
'unknown' => _('Unknown'), 'unknown' => _('Unknown'),
'user' => _('User'),
'vessel' => _('Vessel'), 'vessel' => _('Vessel'),
'waiting' => _('waiting')
); );
return $lookup[$enum] ?? $enum; return $lookup[$enum] ?? $enum;
} }
function db_load_enum($table, $column, $lookup=false, $as_dict=false) { function db_load_enum($table, $column, $lookup=false, $as_dict=false, $check_null=false) {
// returns array of enum-values as defined in database // returns array of enum-values as defined in database
// if lookup is true the name lookup and translaton is applied // if lookup is true the name lookup and translaton is applied
// if as_dict is true the enum value is returned as the array key // if as_dict is true the enum value is returned as the array key
// if check_null is true the nullable-check is applied and returned
global $pdo; global $pdo;
$sql = "SELECT TRIM(TRAILING ')' FROM SUBSTRING(column_type,6)) " $sql = "SELECT TRIM(TRAILING ')' FROM SUBSTRING(column_type,6)), is_nullable "
. "FROM information_schema.columns " . "FROM information_schema.columns "
. "WHERE table_name=? AND column_name=?"; . "WHERE table_schema=DATABASE() AND table_name=? AND column_name=?";
$sth = $pdo->prepare($sql); $sth = $pdo->prepare($sql);
$sth->execute([$table, $column]); $sth->execute([$table, $column]);
$row = $sth->fetch(PDO::FETCH_NUM);
// for PHP < 7.4 // for PHP < 7.4
// return array_map(function($x) { return trim($x, "'"); }, explode(',', $sth->fetchColumn())); // return array_map(function($x) { return trim($x, "'"); }, explode(',', $row[0]));
// for PHP => 7.4 // for PHP => 7.4
$arr = array_map(fn($x) => trim($x, "'"), explode(',', $sth->fetchColumn())); $arr = array_map(fn($x) => trim($x, "'"), explode(',', $row[0]));
// prepend special value NULL if column is nullable
if ($check_null and $row[1] == 'YES') {
array_unshift($arr, 'NULL');
}
if ($lookup) { if ($lookup) {
if ($as_dict) { if ($as_dict) {
$dict = array(); $dict = array();
@@ -413,6 +457,98 @@ function db_load_enum($table, $column, $lookup=false, $as_dict=false) {
} }
} }
function db_load_taglist($objtype, $objid) {
// returns comma separated list for object
global $pdo;
global $g_error;
$taglist = '';
$sql = "SELECT GROUP_CONCAT(tagname) "
. "FROM tagref JOIN tag USING (tagid) "
. "WHERE objtype=? AND objid=?";
$sth = $pdo->prepare($sql);
try {
$sth->execute([$objtype, $objid]);
$taglist = $sth->fetchColumn();
} catch(PDOException $e) {
$g_error->Add($e->getMessage());
}
return $taglist;
}
function db_save_taglist($objtype, $objid, $taglist) {
global $pdo;
global $g_error;
// WIP
// - taglist is comma separated string
// - create not existing tags
// - update tagref: create new, remove unused
$tags = array_filter(explode(',', preg_replace('/\s+/u', '', $taglist)));
if (empty($tags)) {
// remove all from tagref
$sth = $pdo->prepare("DELETE FROM tagref WHERE objtype=? AND objid=?");
try {
$sth->execute([$objtype, $objid]);
} catch(PDOException $e) {
$g_error->Add($e->getMessage());
}
} else {
// get list of non existing tags
$in = str_repeat('?,', count($tags) - 1) . '?';
$sql = "SELECT tagid, tagname FROM tag WHERE tagname IN ($in)";
$sth = $pdo->prepare($sql);
try {
$sth->execute(array_values($tags));
} catch(PDOException $e) {
$g_error->Add($e->getMessage());
}
$tagids = array();
$existing = array();
foreach ($sth->fetchAll() as $row) {
$existing[] = $row['tagname'];
$tagids[] = $row['tagid'];
}
$newtags = array_diff($tags, $existing);
$sth = $pdo->prepare("INSERT INTO tag (tagname) VALUES (?)");
foreach ($newtags as $t) {
// maxlength 20 for each tag!
$sth->execute([substr($t, 0, 20)]);
$tagids[] = $pdo->LastInsertId();
}
// update references
$sql = "SELECT tagid FROM tagref WHERE objtype=? AND objid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$objtype, $objid]);
$refids = array();
$obsolete = array();
foreach ($sth->fetchAll() as $row) {
if (in_array($row['tagid'], $tagids)) {
// mark existing used references
$refids[] = $row['tagid'];
} else {
// obsolete reference
$obsolete[] = $row['tagid'];
}
}
// create missing references
$missing = array_diff($tagids, $refids);
if (! empty($missing)) {
$sql = "INSERT INTO tagref (tagid, objid, objtype) VALUES (?, ?, ?)";
$sth = $pdo->prepare($sql);
foreach ($missing as $m) {
$sth->execute([$m, $objid, $objtype]);
}
}
// remove obsolete references
if (! empty($obsolete)) {
$sql = "DELETE FROM tagref WHERE tagid=? AND objid=? and objtype=?";
$sth = $pdo->prepare($sql);
foreach ($obsolete as $o) {
$sth->execute([$o, $objid, $objtype]);
}
}
}
}
function db_get_ddtext($ddid, $ddval) { function db_get_ddtext($ddid, $ddval) {
// returns single value for dropdown // returns single value for dropdown
global $pdo; global $pdo;
@@ -428,6 +564,8 @@ function db_get_ddtext($ddid, $ddval) {
return $sth->fetchColumn(); return $sth->fetchColumn();
} }
// Functions to get option lists (key/value)
function db_get_options($ddid, $orderby = '', $default = NULL) { function db_get_options($ddid, $orderby = '', $default = NULL) {
// returns list for dropdown // returns list for dropdown
global $pdo; global $pdo;
@@ -461,7 +599,6 @@ function db_get_opt_vessel() {
return $list; return $list;
} }
// Functions to get option lists (key/value)
function db_get_opt_storage($vid) { function db_get_opt_storage($vid) {
global $pdo; global $pdo;
@@ -619,10 +756,31 @@ function float_to_sql($var) {
// ========== FORM FUNCTIONS ================================================== // ========== FORM FUNCTIONS ==================================================
function form_get_action() {
if (!isset($_POST['submit'])) {
if (isset($_GET['f'])) {
$submit = $_GET['f'];
// strip parameters
/* $pos = strpos($submit, '?');
if ($pos > 2) {
$submit = substr($submit, 0, $pos);
} */
} else {
$submit = NULL;
}
} else {
$submit = $_POST['submit'];
}
if (is_array($submit)) {
$submit = key($submit);
}
return strtolower($submit);
}
function form_create_select($fieldname, $label, $optlist, $selval=NULL) { function form_create_select($fieldname, $label, $optlist, $selval=NULL) {
echo '<div class="mb-3">', "\n"; echo '<div class="mb-3">', "\n";
echo '<label for="', $fieldname, '">', $label, "</label>\n"; echo '<label for="', $fieldname, '">', $label, "</label>\n";
echo '<select class="form-select" name="', $fieldname,'" id="', $fieldname,'">'; echo '<select class="form-select" name="', $fieldname,'" id="', $fieldname, '">', "\n";
foreach ($optlist as $k => $v) { foreach ($optlist as $k => $v) {
echo '<option value="', $k, '"'; echo '<option value="', $k, '"';
if (isset($selval) and ($k == $selval)) { if (isset($selval) and ($k == $selval)) {
@@ -686,60 +844,40 @@ function form_delete_buttons($script, $id, $token) {
echo "</div>\n"; echo "</div>\n";
} }
function form_tag_assignment($script, $id) { function form_tag_assignment($script, $id, $tags) {
echo '<tr>'; echo '<tr>';
echo '<th>', _('Tags'), "</th>\n"; echo '<th>', _('Tags'), "</th>\n";
echo '<td>', $tags, '</td>';
echo "</tr>\n<tr>"; echo "</tr>\n<tr>";
echo '<th>', _('Tag assignment'), "</th>\n"; echo '<th>', _('Tag assignment'), "</th>\n";
echo '<td><form method="post" action="', $script, '">', "\n"; echo '<td><form method="post" action="', $script, '">', "\n";
echo '<div class="form-floating">'; echo '<div class="form-floating">';
echo '<input type="hidden" name="id" value="', $id .'">', "\n"; echo '<input type="hidden" name="id" value="', $id .'">', "\n";
echo '<label>', _('(Separate by comma)'), '</label>', "\n"; echo '<label>', _('(Separate by comma)'), '</label>', "\n";
echo '<input type="text" maxlength="80" class="form-control" name="tagstring">', "\n"; echo '<input type="text" maxlength="80" class="form-control" name="tagstring" value="', $tags, '">', "\n";
echo '<input type="submit">', "\n"; echo '<input type="submit">', "\n";
echo "</div></form></td></td>\n"; echo "</div></form></td></td>\n";
echo "</tr>"; echo "</tr>";
} }
// ========== COMMON FUNCTIONS ================================================ function filter_create_select($fieldname, $label, $optlist, $selval=NULL) {
echo '<label for="', $fieldname,'">', $label,'</label>', "\n";
function header_location($location) { echo '<select id="', $fieldname, '" name="', $fieldname, '">', "\n";
header("Location: $location"); foreach ($optlist as $k => $v) {
exit; echo '<option value="', $k, '"';
if ($k == $selval) {
echo ' selected';
}
echo '>', $v, '</option>', "\n";
}
echo "</select>\n";
} }
function form_get_action() { // ========== GPC FUNCTIONS ===================================================
if (!isset($_POST['submit'])) {
if (isset($_GET['f'])) {
$submit = $_GET['f'];
// strip parameters
/* $pos = strpos($submit, '?');
if ($pos > 2) {
$submit = substr($submit, 0, $pos);
} */
} else {
$submit = NULL;
}
} else {
$submit = $_POST['submit'];
}
if (is_array($submit)) {
$submit = key($submit);
}
return strtolower($submit);
}
function get_color_brightness($color) {
// returns a value between 0 and 1
// color is a 6 char hex string
list($red, $green, $blue) = array_map('hexdec', str_split($color, 2));
$red = $red / 255 * 0.2126;
$green = $green / 255 * 0.7152;
$blue = $blue / 255 * 0.0722;
return $red + $green + $blue;
}
function gpc_get_string(&$GPC, $varname, $maxlen = NULL, $default = NULL) { function gpc_get_string(&$GPC, $varname, $maxlen = NULL, $default = NULL) {
// TODO Parameter nullval: single value or array of values which considered as null
// Default value for nullval is "-1"
if (!isset($GPC[$varname]) or (strlen(trim($GPC[$varname])) == 0)) { if (!isset($GPC[$varname]) or (strlen(trim($GPC[$varname])) == 0)) {
return $default; return $default;
} }
@@ -799,6 +937,15 @@ function gpc_get_bool(&$GPC, $varname, $default = FALSE) {
} }
function gpc_get_date(&$GPC, $varname, $default = NULL) { function gpc_get_date(&$GPC, $varname, $default = NULL) {
// TODO improve
if (!isset($GPC[$varname]) || $GPC[$varname] == '') {
return $default;
}
return $GPC[$varname];
}
function gpc_get_datetime(&$GPC, $varname, $default = NULL) {
// TODO improve
if (!isset($GPC[$varname]) || $GPC[$varname] == '') { if (!isset($GPC[$varname]) || $GPC[$varname] == '') {
return $default; return $default;
} }
@@ -829,6 +976,8 @@ function gpc_get_enum(&$GPC, $varname, $values, $default = NULL) {
return $GPC[$varname]; return $GPC[$varname];
} }
// ========== FORMAT FUNCTIONS ================================================
function format_float($val, $decimals = 2, $suffix = '') { function format_float($val, $decimals = 2, $suffix = '') {
global $g_lconv; global $g_lconv;
if (!isset($val) || $val == '') { if (!isset($val) || $val == '') {
@@ -910,6 +1059,67 @@ function format_measurement($n, $unit, $v1, $v2, $v3) {
return $m; return $m;
} }
// ========== COMMON FUNCTIONS ================================================
function header_location($location, $message=NULL) {
if (is_array($message)) {
$valid_keys = array('succ', 'info', 'warn', 'err');
foreach ($message as $k => $v) {
if (in_array($k, $valid_keys)) {
$_SESSION['message'][$k] = $v;
}
}
}
header("Location: $location");
exit;
}
function pgettext($context, $msgid) {
// implement missing function
global $g_textdomain;
$ctxstr = "{$context}\004{$msgid}";
$translation = dcgettext($g_textdomain, $ctxstr, LC_MESSAGES);
if ($translation == $ctxstr) {
return $msgid;
} else {
return $translation;
}
}
function get_color_brightness($color, $default=0.5) {
// returns a value between 0 and 1
// color is a 6 char hex string
if (strlen($color) != 6) {
return $default;
}
list($red, $green, $blue) = array_map('hexdec', str_split($color, 2));
$red = $red / 255 * 0.2126;
$green = $green / 255 * 0.7152;
$blue = $blue / 255 * 0.0722;
return $red + $green + $blue;
}
function page_caption_search($caption) {
// print page caption with searchbox
?>
<div class="row align-items-center">
<div class="col">
<h1><?=$caption?></h1>
</div>
<div class="col-4">
<form class="form-inline" method="post" action="search.php">
<div class="input-group input-group-sm">
<input name="needle" type="search" class="form-control" placeholder="<?=_('Search')?>">
<div class="input-group-append">
<button class="btn btn-sm btn-primary" type="submit"><i class="bi bi-search"></i></button>
</div>
</div>
</form>
</div>
</div>
<?php
}
function get_pagination($script, $param, $page, $lastpage, $small=false) { function get_pagination($script, $param, $page, $lastpage, $small=false) {
// no direct output, returns string for multiple output // no direct output, returns string for multiple output
+7
View File
@@ -9,6 +9,13 @@
<link href="bootstrap/bootstrap-icons.min.css" rel="stylesheet"> <link href="bootstrap/bootstrap-icons.min.css" rel="stylesheet">
<script src="bootstrap/js/bootstrap.bundle.min.js"></script> <script src="bootstrap/js/bootstrap.bundle.min.js"></script>
<link rel="stylesheet" href="default.css"> <link rel="stylesheet" href="default.css">
<?php
if (isset($GLOBALS['local_script'])) {
echo '<script type="text/javascript">', "\n";
echo $GLOBALS['local_script'];
echo "</script>\n";
}
?>
</head> </head>
<body> <body>
<div class="container-xxl"> <div class="container-xxl">
+10 -1
View File
@@ -138,6 +138,14 @@ $sql = "SELECT vesselname, model, loa, lwl, beam, draught, draught_min,"
$sth = $pdo->prepare($sql); $sth = $pdo->prepare($sql);
$sth->execute([$vid]); $sth->execute([$vid]);
$vessel = $sth->fetch(PDO::FETCH_OBJ); $vessel = $sth->fetch(PDO::FETCH_OBJ);
// Show remarks first
if (strlen($vessel->remarks) > 0) {
echo "<p>";
echo $vessel->remarks;
echo "</p>\n";
}
// get vessel shape // get vessel shape
// test for predefined base shape // test for predefined base shape
$shapefilepath = dirname(__FILE__).'/'.$g_shapedir.'/'.$vessel->shapefile; $shapefilepath = dirname(__FILE__).'/'.$g_shapedir.'/'.$vessel->shapefile;
@@ -146,7 +154,8 @@ if (isset($vessel->shapefile) and file_exists($shapefilepath)) {
} else { } else {
// use internal default shape // use internal default shape
$baseshape = <<<EOT $baseshape = <<<EOT
<svg version="1.1" width="1024" height="350" viewBox="0 0 1024 350" id="svg1"> <svg version="1.1" width="1024" height="350" viewBox="0 0 1024 350" id="svg1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="g1"> <g id="g1">
<path id="path1" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:8, 4, 2, 4;stroke-dashoffset:0;stroke-opacity:1" d="M 3.3e-6,174.91172 1023.9982,174.90837" /> <path id="path1" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:8, 4, 2, 4;stroke-dashoffset:0;stroke-opacity:1" d="M 3.3e-6,174.91172 1023.9982,174.90837" />
<path id="path2" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" d="m 1.1002728,174.9708 c 0,0 0.150828,-90.157538 0.02448,-103.853791 C 66.951611,46.573152 247.6267,3.4573666 430.56326,3.8276086 670.30694,4.3128215 758.66035,44.913257 838.18466,74.965511 917.70898,105.01776 1022.8821,175.00227 1022.8821,175.00227" /> <path id="path2" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" d="m 1.1002728,174.9708 c 0,0 0.150828,-90.157538 0.02448,-103.853791 C 66.951611,46.573152 247.6267,3.4573666 430.56326,3.8276086 670.30694,4.3128215 758.66035,44.913257 838.18466,74.965511 917.70898,105.01776 1022.8821,175.00227 1022.8821,175.00227" />
+16 -27
View File
@@ -1,7 +1,7 @@
<?php <?php
/****************************************************************************** /******************************************************************************
* YMS - Yacht Management Software * YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge * Copyright (C) 2024-2025 Thomas Hooge
* *
* SPDX-License-Identifier: WTFPL * SPDX-License-Identifier: WTFPL
******************************************************************************/ ******************************************************************************/
@@ -17,6 +17,7 @@ $opt_user = array();
foreach ($sth->fetchAll() as $row) { foreach ($sth->fetchAll() as $row) {
$opt_user[$row['userid']] = $row['displayname']; $opt_user[$row['userid']] = $row['displayname'];
} }
$opt_state = db_load_enum('project', 'projstate', true, true);
// ========== ACTIONS START =================================================== // ========== ACTIONS START ===================================================
@@ -37,11 +38,11 @@ switch ($submit = form_get_action()) {
break; break;
case 'insert': case 'insert':
$p['vid'] = $user->id; $p[':vid'] = $user->vid;
$p[':projname'] = gpc_get_string($_POST, 'projname'); $p[':projname'] = gpc_get_string($_POST, 'projname');
$p[':responsible'] = gpc_get_int($_POST, 'responsible'); $p[':responsible'] = gpc_get_int($_POST, 'responsible');
$p[':remarks'] = gpc_get_string($_POST, 'remarks', 150); $p[':remarks'] = gpc_get_string($_POST, 'remarks', 150);
$id = db_exec_insert('company', $p); $id = db_exec_insert('project', $p);
$action = ACT_VIEW; $action = ACT_VIEW;
break; break;
@@ -50,6 +51,7 @@ switch ($submit = form_get_action()) {
$p[':projname'] = gpc_get_string($_POST, 'projname'); $p[':projname'] = gpc_get_string($_POST, 'projname');
$p[':startdate'] = gpc_get_date($_POST, 'startdate'); $p[':startdate'] = gpc_get_date($_POST, 'startdate');
$p[':duration'] = gpc_get_int($_POST, 'duration'); $p[':duration'] = gpc_get_int($_POST, 'duration');
$p[':projstate'] = gpc_get_string($_POST, 'projstate');
$p[':remarks'] = gpc_get_string($_POST, 'remarks', 150); $p[':remarks'] = gpc_get_string($_POST, 'remarks', 150);
db_exec_update('project', $p, 'projid'); db_exec_update('project', $p, 'projid');
$action = ACT_VIEW; $action = ACT_VIEW;
@@ -121,9 +123,10 @@ echo "<h1>", _('Generic Tasks'), "</h1>\n";
echo "<p>", _('Tasks not assigned to any project'), "</p>\n"; echo "<p>", _('Tasks not assigned to any project'), "</p>\n";
$sql = "SELECT taskid, taskname " $sql = "SELECT taskid, taskname "
. "FROM task " . "FROM task "
. "WHERE projid IS NULL " . "WHERE vid=? AND projid IS NULL "
. "ORDER BY taskid"; . "ORDER BY taskid";
$sth = $pdo->query($sql); $sth = $pdo->prepare($sql);
$sth->execute([$user->vid]);
$res = $sth->fetchAll(); $res = $sth->fetchAll();
echo '<table class="table table-striped">', "\n"; echo '<table class="table table-striped">', "\n";
echo "<thead>\n"; echo "<thead>\n";
@@ -156,16 +159,9 @@ echo '<h2>', _('Add Project'), "</h2>\n";
<label for="projname" class="form-label"><?=_('Name')?></label> <label for="projname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="projname" name="projname"> <input type="text" class="form-control" id="projname" name="projname">
</div> </div>
<div class="mb-3">
<label for="responsible" class="form-label"><?=_('Responsible')?></label>
<select name="responsible" class="form-control">
<?php <?php
foreach ($opt_user as $k => $v) { form_create_select('responsible', _('Responsible'), $opt_user, $project->responsible);
echo '<option value="', $k ,'">', $v, "</option>\n";
}
?> ?>
</select>
</div>
<div class="mb-3"> <div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label> <label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"></textarea> <textarea class="form-control" id="remarks" name="remarks" rows="3"></textarea>
@@ -178,7 +174,7 @@ foreach ($opt_user as $k => $v) {
elseif ($action == ACT_VIEW): elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record ===================================== // ========== VARIANT: view single record =====================================
$sql = "SELECT projname, startdate, duration, responsible, remarks " $sql = "SELECT projname, startdate, duration, responsible, projstate, remarks "
. "FROM project " . "FROM project "
. "WHERE projid=?"; . "WHERE projid=?";
$sth = $pdo->prepare($sql); $sth = $pdo->prepare($sql);
@@ -190,6 +186,7 @@ echo '<tr><th scope="row" style="width:20%">', _('Name'),"</th><td>", $project->
echo '<tr><th scope="row">', _('Responsible'),"</th><td>", $opt_user[$project->responsible], "</td></tr>\n"; echo '<tr><th scope="row">', _('Responsible'),"</th><td>", $opt_user[$project->responsible], "</td></tr>\n";
echo '<tr><th scope="row">', _('Start date'),"</th><td>", $project->startdate, "</td></tr>\n"; echo '<tr><th scope="row">', _('Start date'),"</th><td>", $project->startdate, "</td></tr>\n";
echo '<tr><th scope="row">', _('Duration'),"</th><td>", $project->duration, "</td></tr>\n"; echo '<tr><th scope="row">', _('Duration'),"</th><td>", $project->duration, "</td></tr>\n";
echo '<tr><th scope="row">', _('State'),"</th><td>", $project->projstate, "</td></tr>\n";
echo '<tr><th scope="row">', _('Remarks'),"</th><td>", $project->remarks, "</td></tr>\n"; echo '<tr><th scope="row">', _('Remarks'),"</th><td>", $project->remarks, "</td></tr>\n";
echo "</table>\n"; echo "</table>\n";
@@ -223,7 +220,7 @@ elseif ($action == ACT_EDIT):
echo '<h2>', _('Edit Project'), "</h2>\n"; echo '<h2>', _('Edit Project'), "</h2>\n";
$sql = "SELECT projname, responsible, startdate, duration, remarks " $sql = "SELECT projname, responsible, startdate, duration, projstate, remarks "
. "FROM project " . "FROM project "
. "WHERE projid=?"; . "WHERE projid=?";
$sth = $pdo->prepare($sql); $sth = $pdo->prepare($sql);
@@ -237,20 +234,9 @@ $project = $sth->fetch(PDO::FETCH_OBJ);
<label for="projname" class="form-label"><?=_('Name')?></label> <label for="projname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="projname" name="projname" value="<?=$project->projname ?>"> <input type="text" class="form-control" id="projname" name="projname" value="<?=$project->projname ?>">
</div> </div>
<div class="mb-3">
<label for="responsible" class="form-label"><?=_('Responsible')?></label>
<select name="responsible" class="form-control">
<?php <?php
foreach ($opt_user as $k => $v) { form_create_select('responsible', _('Responsible'), $opt_user, $project->responsible);
echo '<option value="', $k ,'"';
if ($project->responsible == $k) {
echo ' selected';
}
echo '>', $v, "</option>\n";
}
?> ?>
</select>
</div>
<div class="mb-3"> <div class="mb-3">
<label for="startdate"><?=_('Startdate')?></label> <label for="startdate"><?=_('Startdate')?></label>
<input type="date" class="form-control" id="startdate" name="startdate" value="<?=$project->startdate ?>"> <input type="date" class="form-control" id="startdate" name="startdate" value="<?=$project->startdate ?>">
@@ -259,6 +245,9 @@ foreach ($opt_user as $k => $v) {
<label for="duration"><?=_('Duration, days')?></label> <label for="duration"><?=_('Duration, days')?></label>
<input type="number" class="form-control" id="duration" name="duration" min="1" value="<?=$project->duration ?>"> <input type="number" class="form-control" id="duration" name="duration" min="1" value="<?=$project->duration ?>">
</div> </div>
<?php
form_create_select('projstate', _('Status'), $opt_state, $project->projstate);
?>
<div class="mb-3"> <div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label> <label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$project->remarks ?></textarea> <textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$project->remarks ?></textarea>
+1 -1
View File
@@ -1,7 +1,7 @@
<?php <?php
/****************************************************************************** /******************************************************************************
* YMS - Yacht Management Software * YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge * Copyright (C) 2024-2025 Thomas Hooge
* *
* SPDX-License-Identifier: WTFPL * SPDX-License-Identifier: WTFPL
******************************************************************************/ ******************************************************************************/