diff --git a/README b/README index 26001cc..7724611 100644 --- a/README +++ b/README @@ -1,3 +1,5 @@ YMS - Yacht Management System Prototype +Many features are incomplete, buggy or missing. +Use at your own risk! diff --git a/db/mariadb.sql b/db/mariadb.sql index cf8ca69..69d7e18 100644 --- a/db/mariadb.sql +++ b/db/mariadb.sql @@ -217,6 +217,7 @@ CREATE TABLE company ( compid smallint(6) NOT NULL AUTO_INCREMENT, compname varchar(60) NOT NULL, comptype tinyint(3) NOT NULL DEFAULT 1, + comptype2 tinyint(3) DEFAULT NULL, shortname varchar(20) DEFAULT NULL, street varchar(30), zip varchar(10), @@ -258,7 +259,7 @@ CREATE TABLE project ( costs_plan decimal(12,2) DEFAULT NULL, costs_final decimal(12,2) 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) ); @@ -273,6 +274,8 @@ CREATE TABLE task ( duedate date DEFAULT NULL, started datetime DEFAULT NULL, finished datetime DEFAULT NULL, + responsible smallint(6) NOT NULL, + /* TODO executed_by : company or user? or both? */ PRIMARY KEY (taskid) ); diff --git a/inst_apache.sh b/inst_apache.sh index acd3374..d67791b 100755 --- a/inst_apache.sh +++ b/inst_apache.sh @@ -6,4 +6,4 @@ mv /var/www/html/config.inc-sample /var/www/html/config.inc chmod 640 /var/www/html/config.inc chgrp www-data /var/www/html/config.inc rm /var/www/html/index.html -rm /var/www/html/locale/dc_DE.po +rm /var/www/html/locale/de_DE.po diff --git a/webgui/company.php b/webgui/company.php index 90a90b1..de1fd6f 100644 --- a/webgui/company.php +++ b/webgui/company.php @@ -43,6 +43,7 @@ switch ($submit = form_get_action()) { $p[':compname'] = gpc_get_string($_POST, 'compname'); $p[':shortname'] = gpc_get_string($_POST, 'shortname', 20); $p[':comptype'] = gpc_get_int($_POST, 'comptype'); + $p[':comptype2'] = gpc_get_int($_POST, 'comptype2'); $p[':street'] = gpc_get_string($_POST, 'street', 30); $p[':zip'] = gpc_get_string($_POST, 'zip', 10); $p[':city'] = gpc_get_string($_POST, 'city', 30); @@ -228,8 +229,8 @@ echo '

', _('Add Company'), "

\n"; elseif ($action == ACT_VIEW): // ========== VARIANT: view single record ===================================== -$sql = "SELECT compname, comptype, shortname, street, zip, city, country," - . " contact, phone, email, web, customerno, contractno, remarks " +$sql = "SELECT compname, comptype, comptype2, shortname, street, zip, city," + . " country, contact, phone, email, web, customerno, contractno, remarks " . "FROM company " . "WHERE compid=?"; $sth = $pdo->prepare($sql); @@ -242,6 +243,7 @@ echo '', "\n"; echo '\n"; echo '\n"; echo '\n"; +echo '\n"; echo '\n"; echo '\n"; echo '\n"; @@ -299,7 +301,7 @@ elseif ($action == ACT_EDIT): echo '

', _('Edit Company'), "

\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 " . "FROM company " . "WHERE compid=?"; @@ -332,6 +334,21 @@ foreach ($opt_comptype as $k => $v) { ?> +
+ + +
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 '', "\n"; foreach ($optlist as $k => $v) { echo '
'; echo '\n"; + echo ''; echo "\n"; echo '\n"; echo '\n"; echo ""; } -// ========== COMMON FUNCTIONS ================================================ - -function header_location($location) { - header("Location: $location"); - exit; -} - -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; +function filter_create_select($fieldname, $label, $optlist, $selval=NULL) { + echo '', "\n"; + echo '\n"; } -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; -} +// ========== GPC FUNCTIONS =================================================== 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)) { return $default; } @@ -799,6 +937,15 @@ function gpc_get_bool(&$GPC, $varname, $default = FALSE) { } 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] == '') { return $default; } @@ -829,6 +976,8 @@ function gpc_get_enum(&$GPC, $varname, $values, $default = NULL) { return $GPC[$varname]; } +// ========== FORMAT FUNCTIONS ================================================ + function format_float($val, $decimals = 2, $suffix = '') { global $g_lconv; if (!isset($val) || $val == '') { @@ -910,6 +1059,67 @@ function format_measurement($n, $unit, $v1, $v2, $v3) { 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 +?> +
+
+

+
+
+
+
+ +
+ +
+
+ +
+
+ +', "\n"; + echo $GLOBALS['local_script']; + echo "\n"; +} +?>
diff --git a/webgui/index.php b/webgui/index.php index 5628651..a43e27c 100644 --- a/webgui/index.php +++ b/webgui/index.php @@ -138,6 +138,14 @@ $sql = "SELECT vesselname, model, loa, lwl, beam, draught, draught_min," $sth = $pdo->prepare($sql); $sth->execute([$vid]); $vessel = $sth->fetch(PDO::FETCH_OBJ); + +// Show remarks first +if (strlen($vessel->remarks) > 0) { + echo "

"; + echo $vessel->remarks; + echo "

\n"; +} + // get vessel shape // test for predefined base shape $shapefilepath = dirname(__FILE__).'/'.$g_shapedir.'/'.$vessel->shapefile; @@ -146,7 +154,8 @@ if (isset($vessel->shapefile) and file_exists($shapefilepath)) { } else { // use internal default shape $baseshape = << + diff --git a/webgui/projects.php b/webgui/projects.php index d7c067b..77775cf 100644 --- a/webgui/projects.php +++ b/webgui/projects.php @@ -1,7 +1,7 @@ fetchAll() as $row) { $opt_user[$row['userid']] = $row['displayname']; } +$opt_state = db_load_enum('project', 'projstate', true, true); // ========== ACTIONS START =================================================== @@ -37,11 +38,11 @@ switch ($submit = form_get_action()) { break; case 'insert': - $p['vid'] = $user->id; + $p[':vid'] = $user->vid; $p[':projname'] = gpc_get_string($_POST, 'projname'); $p[':responsible'] = gpc_get_int($_POST, 'responsible'); $p[':remarks'] = gpc_get_string($_POST, 'remarks', 150); - $id = db_exec_insert('company', $p); + $id = db_exec_insert('project', $p); $action = ACT_VIEW; break; @@ -50,6 +51,7 @@ switch ($submit = form_get_action()) { $p[':projname'] = gpc_get_string($_POST, 'projname'); $p[':startdate'] = gpc_get_date($_POST, 'startdate'); $p[':duration'] = gpc_get_int($_POST, 'duration'); + $p[':projstate'] = gpc_get_string($_POST, 'projstate'); $p[':remarks'] = gpc_get_string($_POST, 'remarks', 150); db_exec_update('project', $p, 'projid'); $action = ACT_VIEW; @@ -121,9 +123,10 @@ echo "

", _('Generic Tasks'), "

\n"; echo "

", _('Tasks not assigned to any project'), "

\n"; $sql = "SELECT taskid, taskname " . "FROM task " - . "WHERE projid IS NULL " + . "WHERE vid=? AND projid IS NULL " . "ORDER BY taskid"; -$sth = $pdo->query($sql); +$sth = $pdo->prepare($sql); +$sth->execute([$user->vid]); $res = $sth->fetchAll(); echo '
', _('Name'),"", $company->compname, "
', _('Short name'),"", $company->shortname, "
', _('Type'),"", $opt_comptype[$company->comptype], "
', _('Secondary type'),"", $company->comptype2 ? $opt_comptype[$company->comptype2] : '-', "
', _('Street'),"", $company->street, "
', _('Zip, City'),"", $company->zip, ' ', $company->city, "
', _('Country'),"", $company->country, "
', _('Tags'), "', $tags, '
', _('Tag assignment'), "
', "\n"; echo '
'; echo '', "\n"; echo '', "\n"; - echo '', "\n"; + echo '', "\n"; echo '', "\n"; echo "
', "\n"; echo "\n"; @@ -156,16 +159,9 @@ echo '

', _('Add Project'), "

\n"; -
- - -
@@ -178,7 +174,7 @@ foreach ($opt_user as $k => $v) { elseif ($action == ACT_VIEW): // ========== VARIANT: view single record ===================================== -$sql = "SELECT projname, startdate, duration, responsible, remarks " +$sql = "SELECT projname, startdate, duration, responsible, projstate, remarks " . "FROM project " . "WHERE projid=?"; $sth = $pdo->prepare($sql); @@ -190,6 +186,7 @@ echo '
\n"; echo '\n"; echo '\n"; +echo '\n"; echo '\n"; echo "
', _('Name'),"", $project-> echo '
', _('Responsible'),"", $opt_user[$project->responsible], "
', _('Start date'),"", $project->startdate, "
', _('Duration'),"", $project->duration, "
', _('State'),"", $project->projstate, "
', _('Remarks'),"", $project->remarks, "
\n"; @@ -223,7 +220,7 @@ elseif ($action == ACT_EDIT): echo '

', _('Edit Project'), "

\n"; -$sql = "SELECT projname, responsible, startdate, duration, remarks " +$sql = "SELECT projname, responsible, startdate, duration, projstate, remarks " . "FROM project " . "WHERE projid=?"; $sth = $pdo->prepare($sql); @@ -237,20 +234,9 @@ $project = $sth->fetch(PDO::FETCH_OBJ); -
- - -
@@ -259,6 +245,9 @@ foreach ($opt_user as $k => $v) {
+projstate); +?>
diff --git a/webgui/task.php b/webgui/task.php index b910055..863c66a 100644 --- a/webgui/task.php +++ b/webgui/task.php @@ -1,7 +1,7 @@