diff --git a/webgui/config.inc-sample b/webgui/config.inc-sample
index f234a40..404ec15 100644
--- a/webgui/config.inc-sample
+++ b/webgui/config.inc-sample
@@ -35,6 +35,13 @@ $g_shapedir = 'shapes';
// documents and images
$g_doc_basepath = '/var/local/yms';
$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
diff --git a/webgui/documents.php b/webgui/documents.php
index a46993a..fb32aef 100644
--- a/webgui/documents.php
+++ b/webgui/documents.php
@@ -42,6 +42,17 @@ switch ($submit = form_get_action()) {
case 'insert':
// WIP New standalone document
// 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']) ) {
$g_warning->Add(_('No file for upload submitted. Try again by selecting a file first.'));
$action = ACT_ADD;
@@ -117,7 +128,7 @@ switch ($submit = form_get_action()) {
$p[':doctype'] = gpc_get_string($_POST, 'doctype');
$p[':filename'] = gpc_get_string($_POST, 'filename');
$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');
$action = ACT_VIEW;
break;
diff --git a/webgui/globals.inc b/webgui/globals.inc
index 0318b9c..4b9148a 100644
--- a/webgui/globals.inc
+++ b/webgui/globals.inc
@@ -50,9 +50,9 @@ setlocale(LC_ALL, $g_locale);
$g_lconv = localeconv();
$g_lang = substr($g_locale, 0, 2); // short language identifier
-bindtextdomain('yms', 'locale');
-bind_textdomain_codeset('yms', 'UTF-8');
-textdomain('yms');
+bindtextdomain($g_textdomain, 'locale');
+bind_textdomain_codeset($g_textdomain, 'UTF-8');
+textdomain($g_textdomain);
date_default_timezone_set($g_timezone);
@@ -63,12 +63,18 @@ if ($g_scriptname != 'login.php') {
$_SESSION['prelogin'] = $_SERVER['REQUEST_URI'];
header_location('login.php');
}
- $g_referrer = $_SESSION['coming_from'];
+ $g_referrer = $_SESSION['coming_from'] ?? $g_scriptname;
$_SESSION['coming_from'] = $g_scriptname;
}
// 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 '
';
+ print_r($e);
+ echo '
';
+}
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
# $pdo->query("SET lc_time_names='de_DE'");
@@ -87,6 +93,10 @@ $valid = FALSE;
// document storage
$g_doc_mimetypes = ['image/png', 'image/jpeg', 'image/svg+xml', 'application/pdf'];
+// form option lists
+$g_opt_all = array(-2 => _('― all ―'));
+$g_opt_none = array(-1 => _('― none ―'));
+
// Initialize message system
$g_message = new Message;
$g_success = new MessageSuccess;
@@ -105,6 +115,10 @@ class Message {
function __construct() {
$this->caption = _('Information');
$this->alertclass = 'alert-info';
+ if (isset($_SESSION['message']['info'])) {
+ $this->Add($_SESSION['message']['info']);
+ unset($_SESSION['message']['info']);
+ }
}
function SetCaption($str) {
@@ -140,6 +154,10 @@ class MessageSuccess extends Message {
function __construct() {
$this->caption = _('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() {
$this->caption = _('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() {
$this->caption = _('Error');
$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
$_SESSION['userid'] = $row->userid;
$this->loggedin = TRUE;
- header_location($_SESSION['prelogin'] ?? 'index.php');
+ $target = $_SESSION['prelogin'] ?? 'index.php';
+ unset($_SESSION['prelogin']);
+ header_location($target);
} else {
$this->errormessage = _('Username or password invalid');
}
@@ -344,13 +372,17 @@ function db_save_filter($flt, $sno) {
}
function get_enum($enum) {
- // Translate and beautify enums
+ // translate and beautify enums
$lookup = array(
+ 'NULL' => _('n/a'),
'bad' => _('Bad'),
'box' => _('Box'),
'cat' => _('Catamaran'),
+ 'completed' => _('Completed'),
'closed' => _('Closed'),
+ 'company' => _('Company'),
'defect' => _('Defect'),
+ 'deleted' => _('Deleted'),
'done' => _('Done'),
'drawing' => _('Drawing'),
'equipment' => _('Equipment'),
@@ -364,40 +396,52 @@ function get_enum($enum) {
'locked' => _('Locked'),
'low' => _('Low'),
'manual' => _('Manual'),
- 'mediim' => _('Medium'),
+ 'medium' => _('Medium'),
'mono' => _('Monohull'),
'new' => _('New'),
+ 'none' => _('None'),
'normal' => _('Normal'),
'ongoing' => _('Ongoing'),
'open' => _('Open'),
+ 'paused' => _('Paused'),
+ 'pending' => _('Pending'),
'picture' => _('Picture'),
'planned' => _('Planned'),
'precise' => _('Precise'),
+ 'project' => _('Project'),
'repairable' => _('Repairable'),
'rough' => _('Rough'),
'storage' => _('Storage'),
'task' => _('Task'),
'tri' => _('Trimaran'),
'unknown' => _('Unknown'),
+ 'user' => _('User'),
'vessel' => _('Vessel'),
+ 'waiting' => _('waiting')
);
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
// 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 check_null is true the nullable-check is applied and returned
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 "
- . "WHERE table_name=? AND column_name=?";
+ . "WHERE table_schema=DATABASE() AND table_name=? AND column_name=?";
$sth = $pdo->prepare($sql);
$sth->execute([$table, $column]);
+ $row = $sth->fetch(PDO::FETCH_NUM);
// 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
- $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 ($as_dict) {
$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) {
// returns single value for dropdown
global $pdo;
@@ -428,6 +564,8 @@ function db_get_ddtext($ddid, $ddval) {
return $sth->fetchColumn();
}
+// Functions to get option lists (key/value)
+
function db_get_options($ddid, $orderby = '', $default = NULL) {
// returns list for dropdown
global $pdo;
@@ -461,7 +599,6 @@ function db_get_opt_vessel() {
return $list;
}
-// Functions to get option lists (key/value)
function db_get_opt_storage($vid) {
global $pdo;
@@ -619,10 +756,31 @@ function float_to_sql($var) {
// ========== 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) {
echo '
', "\n";
echo '
\n";
- echo '