From 4600f8f7bfab1c346c2b1ec6cd73d3de56f638ef Mon Sep 17 00:00:00 2001 From: Clemens Schwaighofer Date: Wed, 22 Jun 2022 15:50:07 +0900 Subject: [PATCH] Update edit_user form page and also minor updates to Form and ArraIO login_user_id is unique if not null (as index, constraint only with PostgreSQL 15) login_user_id_revalidate_after is not longer not null and default set, no need for this DB\Extended\ArrayIO: add sql_read for datetime fields to change amount of data (eg only up to minute) with to_char() method. sample: YYYY-MM-DD HH24:MI Add date/datetime/emptynull for setting empty fields to null and not empty string Output\From\Generate: Remove all fill for spacer and change them to placeholder html types. Add datetime check next to date, time only checks edit_user Admin Form: add all new columns there --- 4dev/database/database_create_data.sql | 5 +- 4dev/database/table/edit_user.sql | 5 +- .../20220617-edit_user_login_user_id_add.sql | 4 +- .../CoreLibsACLLogin_database_create_data.sql | 5 +- www/includes/edit_base.php | 9 ++ .../table_arrays/array_edit_users.php | 95 ++++++++++++++++--- .../templates/admin/edit_elements.tpl | 5 +- www/lib/CoreLibs/ACL/Login.php | 10 +- www/lib/CoreLibs/DB/Extended/ArrayIO.php | 17 +++- www/lib/CoreLibs/Output/Form/Generate.php | 24 +++-- 10 files changed, 148 insertions(+), 31 deletions(-) diff --git a/4dev/database/database_create_data.sql b/4dev/database/database_create_data.sql index d8f4bc61..d0553cb8 100644 --- a/4dev/database/database_create_data.sql +++ b/4dev/database/database_create_data.sql @@ -599,12 +599,15 @@ CREATE TABLE edit_user ( login_user_id_set_date TIMESTAMP WITHOUT TIME ZONE, -- when above uid was set login_user_id_valid_from TIMESTAMP WITHOUT TIME ZONE, -- if set, from when the above uid is valid login_user_id_valid_until TIMESTAMP WITHOUT TIME ZONE, -- if set, until when the above uid is valid - login_user_id_revalidate_after INTERVAL DEFAULT '0 days', -- user must login to revalidated login id after set days, 0 for forever + login_user_id_revalidate_after INTERVAL, -- user must login to revalidated login id after set days, 0 for forever login_user_id_locked SMALLINT DEFAULT 0, -- lock for login user id, but still allow normal login -- additional ACL json block additional_acl JSONB -- additional ACL as JSON string (can be set by other pages) ) INHERITS (edit_generic) WITHOUT OIDS; +-- create unique index +CREATE UNIQUE INDEX edit_user_login_user_id_key ON edit_user (login_user_id) WHERE login_user_id IS NOT NULL; + COMMENT ON COLUMN edit_user.username IS 'Login username, must set'; COMMENT ON COLUMN edit_user.password IS 'Login password, must set'; COMMENT ON COLUMN edit_user.enabled IS 'Login is enabled (master switch)'; diff --git a/4dev/database/table/edit_user.sql b/4dev/database/table/edit_user.sql index 91b508f7..030f059f 100644 --- a/4dev/database/table/edit_user.sql +++ b/4dev/database/table/edit_user.sql @@ -59,12 +59,15 @@ CREATE TABLE edit_user ( login_user_id_set_date TIMESTAMP WITHOUT TIME ZONE, -- when above uid was set login_user_id_valid_from TIMESTAMP WITHOUT TIME ZONE, -- if set, from when the above uid is valid login_user_id_valid_until TIMESTAMP WITHOUT TIME ZONE, -- if set, until when the above uid is valid - login_user_id_revalidate_after INTERVAL DEFAULT '0 days', -- user must login to revalidated login id after set days, 0 for forever + login_user_id_revalidate_after INTERVAL, -- user must login to revalidated login id after set days, 0 for forever login_user_id_locked SMALLINT DEFAULT 0, -- lock for login user id, but still allow normal login -- additional ACL json block additional_acl JSONB -- additional ACL as JSON string (can be set by other pages) ) INHERITS (edit_generic) WITHOUT OIDS; +-- create unique index +CREATE UNIQUE INDEX edit_user_login_user_id_key ON edit_user (login_user_id) WHERE login_user_id IS NOT NULL; + COMMENT ON COLUMN edit_user.username IS 'Login username, must set'; COMMENT ON COLUMN edit_user.password IS 'Login password, must set'; COMMENT ON COLUMN edit_user.enabled IS 'Login is enabled (master switch)'; diff --git a/4dev/database/update/20220617-edit_user_login_user_id_add.sql b/4dev/database/update/20220617-edit_user_login_user_id_add.sql index 016835dd..d3377ecb 100644 --- a/4dev/database/update/20220617-edit_user_login_user_id_add.sql +++ b/4dev/database/update/20220617-edit_user_login_user_id_add.sql @@ -2,13 +2,14 @@ -- the login uid, at least 32 chars ALTER TABLE edit_user ADD login_user_id VARCHAR; +CREATE UNIQUE INDEX edit_user_login_user_id_key ON edit_user (login_user_id) WHERE login_user_id IS NOT NULL; -- when above uid was set ALTER TABLE edit_user ADD login_user_id_set_date TIMESTAMP WITHOUT TIME ZONE; -- if set, from/until when the above uid is valid ALTER TABLE edit_user ADD login_user_id_valid_from TIMESTAMP WITHOUT TIME ZONE; ALTER TABLE edit_user ADD login_user_id_valid_until TIMESTAMP WITHOUT TIME ZONE; -- user must login to revalidated login id after set days, 0 for forever -ALTER TABLE edit_user ADD login_user_id_revalidate_after INTERVAL NOT NULL DEFAULT '0 days'; +ALTER TABLE edit_user ADD login_user_id_revalidate_after INTERVAL; -- lock for login user id, but still allow normal login ALTER TABLE edit_user ADD login_user_id_locked SMALLINT NOT NULL DEFAULT 0; @@ -39,7 +40,6 @@ END; $$ LANGUAGE 'plpgsql'; - CREATE TRIGGER trg_edit_user_set_login_user_id_set_date BEFORE INSERT OR UPDATE ON edit_user FOR EACH ROW EXECUTE PROCEDURE set_login_user_id_set_date(); diff --git a/4dev/tests/database/CoreLibsACLLogin_database_create_data.sql b/4dev/tests/database/CoreLibsACLLogin_database_create_data.sql index d8f4bc61..d0553cb8 100644 --- a/4dev/tests/database/CoreLibsACLLogin_database_create_data.sql +++ b/4dev/tests/database/CoreLibsACLLogin_database_create_data.sql @@ -599,12 +599,15 @@ CREATE TABLE edit_user ( login_user_id_set_date TIMESTAMP WITHOUT TIME ZONE, -- when above uid was set login_user_id_valid_from TIMESTAMP WITHOUT TIME ZONE, -- if set, from when the above uid is valid login_user_id_valid_until TIMESTAMP WITHOUT TIME ZONE, -- if set, until when the above uid is valid - login_user_id_revalidate_after INTERVAL DEFAULT '0 days', -- user must login to revalidated login id after set days, 0 for forever + login_user_id_revalidate_after INTERVAL, -- user must login to revalidated login id after set days, 0 for forever login_user_id_locked SMALLINT DEFAULT 0, -- lock for login user id, but still allow normal login -- additional ACL json block additional_acl JSONB -- additional ACL as JSON string (can be set by other pages) ) INHERITS (edit_generic) WITHOUT OIDS; +-- create unique index +CREATE UNIQUE INDEX edit_user_login_user_id_key ON edit_user (login_user_id) WHERE login_user_id IS NOT NULL; + COMMENT ON COLUMN edit_user.username IS 'Login username, must set'; COMMENT ON COLUMN edit_user.password IS 'Login password, must set'; COMMENT ON COLUMN edit_user.enabled IS 'Login is enabled (master switch)'; diff --git a/www/includes/edit_base.php b/www/includes/edit_base.php index 46c7d394..93573b8a 100644 --- a/www/includes/edit_base.php +++ b/www/includes/edit_base.php @@ -397,10 +397,17 @@ if ($form->my_page_name == 'edit_order') { $elements[] = $form->formCreateElement('login_error_date_last'); $elements[] = $form->formCreateElement('login_error_date_first'); $elements[] = $form->formCreateElement('enabled'); + $elements[] = $form->formCreateElement('deleted'); $elements[] = $form->formCreateElement('protected'); $elements[] = $form->formCreateElement('username'); $elements[] = $form->formCreateElement('password'); $elements[] = $form->formCreateElement('password_change_interval'); + $elements[] = $form->formCreateElement('login_user_id'); + $elements[] = $form->formCreateElement('login_user_id_set_date'); + $elements[] = $form->formCreateElement('login_user_id_locked'); + $elements[] = $form->formCreateElement('login_user_id_revalidate_after'); + $elements[] = $form->formCreateElement('login_user_id_valid_from'); + $elements[] = $form->formCreateElement('login_user_id_valid_until'); $elements[] = $form->formCreateElement('email'); $elements[] = $form->formCreateElement('last_name'); $elements[] = $form->formCreateElement('first_name'); @@ -408,6 +415,8 @@ if ($form->my_page_name == 'edit_order') { $elements[] = $form->formCreateElement('edit_access_right_id'); $elements[] = $form->formCreateElement('strict'); $elements[] = $form->formCreateElement('locked'); + $elements[] = $form->formCreateElement('lock_until'); + $elements[] = $form->formCreateElement('lock_after'); $elements[] = $form->formCreateElement('admin'); $elements[] = $form->formCreateElement('debug'); $elements[] = $form->formCreateElement('db_debug'); diff --git a/www/includes/table_arrays/array_edit_users.php b/www/includes/table_arrays/array_edit_users.php index 94abbe10..21b91607 100644 --- a/www/includes/table_arrays/array_edit_users.php +++ b/www/includes/table_arrays/array_edit_users.php @@ -53,6 +53,16 @@ $edit_users = [ '0' => 'No' ], ], + 'deleted' => [ + 'value' => $GLOBALS['deleted'] ?? '', + 'output_name' => 'Deleted', + 'type' => 'binary', + 'int' => 1, + 'element_list' => [ + '1' => 'Yes', + '0' => 'No' + ], + ], 'strict' => [ 'value' => $GLOBALS['strict'] ?? '', 'output_name' => 'Strict (Lock after errors)', @@ -119,6 +129,71 @@ $edit_users = [ 'output_name' => 'First Name', 'type' => 'text' ], + 'lock_until' => [ + 'value' => $GLOBALS['lock_until'] ?? '', + 'output_name' => 'Lock account until', + 'type' => 'datetime', + 'error_check' => 'datetime', + 'sql_read' => 'YYYY-MM-DD HH24:MI', + 'datetime' => 1, + ], + 'lock_after' => [ + 'value' => $GLOBALS['lock_after'] ?? '', + 'output_name' => 'Lock account after', + 'type' => 'datetime', + 'error_check' => 'datetime', + 'sql_read' => 'YYYY-MM-DD HH24:MI', + 'datetime' => 1, + ], + 'login_user_id' => [ + 'value' => $GLOBALS['login_user_id'] ?? '', + 'output_name' => '_GET/_POST loginUserId direct login ID', + 'type' => 'text', + 'error_check' => 'unique|custom', + 'error_regex' => "/^[A-Za-z0-9]+$/", + 'emptynull' => 1, + ], + 'login_user_id_set_date' => [ + 'output_name' => 'loginUserId set date', + 'value' => $GLOBALS['login_user_id_set_date'] ?? '', + 'type' => 'view', + 'empty' => '-' + ], + 'login_user_id_locked' => [ + 'value' => $GLOBALS['login_user_id_locked'] ?? '', + 'output_name' => 'loginUserId usage locked', + 'type' => 'binary', + 'int' => 1, + 'element_list' => [ + '1' => 'Yes', + '0' => 'No' + ], + ], + 'login_user_id_revalidate_after' => [ + 'value' => $GLOBALS['login_user_id_revalidate_after'] ?? '', + 'output_name' => 'loginUserId, User must login after n days', + 'type' => 'text', + 'error_check' => 'intervalshort', + 'interval' => 1, // interval needs NULL write for empty + 'size' => 5, // make it 5 chars long + 'length' => 5 + ], + 'login_user_id_valid_from' => [ + 'value' => $GLOBALS['login_user_id_valid_from'] ?? '', + 'output_name' => 'loginUserId valid from', + 'type' => 'datetime', + 'error_check' => 'datetime', + 'sql_read' => 'YYYY-MM-DD HH24:MI', + 'datetime' => 1, + ], + 'login_user_id_valid_until' => [ + 'value' => $GLOBALS['login_user_id_valid_until'] ?? '', + 'output_name' => 'loginUserId valid until', + 'type' => 'datetime', + 'error_check' => 'datetime', + 'sql_read' => 'YYYY-MM-DD HH24:MI', + 'datetime' => 1, + ], 'edit_language_id' => [ 'value' => $GLOBALS['edit_language_id'] ?? '', 'output_name' => 'Language', @@ -187,7 +262,8 @@ $edit_users = [ 'cols' => 60 ], ], - 'load_query' => "SELECT edit_user_id, username, enabled, debug, db_debug, strict, locked, login_error_count " + 'load_query' => "SELECT edit_user_id, username, enabled, deleted, " + . "strict, locked, login_error_count " . "FROM edit_user ORDER BY username", 'table_name' => 'edit_user', 'show_fields' => [ @@ -197,31 +273,26 @@ $edit_users = [ [ 'name' => 'enabled', 'binary' => ['Yes', 'No'], - 'before_value' => 'Enabled: ' + 'before_value' => 'ENBL: ' ], [ - 'name' => 'debug', + 'name' => 'deleted', 'binary' => ['Yes', 'No'], - 'before_value' => 'Debug: ' - ], - [ - 'name' => 'db_debug', - 'binary' => ['Yes', 'No'], - 'before_value' => 'DB Debug: ' + 'before_value' => 'DEL: ' ], [ 'name' => 'strict', 'binary' => ['Yes', 'No'], - 'before_value' => 'Strict: ' + 'before_value' => 'STRC: ' ], [ 'name' => 'locked', 'binary' => ['Yes', 'No'], - 'before_value' => 'Locked: ' + 'before_value' => 'LCK: ' ], [ 'name' => 'login_error_count', - 'before_value' => 'Errors: ' + 'before_value' => 'ERR: ' ], ], 'element_list' => [ diff --git a/www/includes/templates/admin/edit_elements.tpl b/www/includes/templates/admin/edit_elements.tpl index 521de423..be8c0ef3 100644 --- a/www/includes/templates/admin/edit_elements.tpl +++ b/www/includes/templates/admin/edit_elements.tpl @@ -32,7 +32,10 @@ {/if} {if $element.type == 'date'} - + + {/if} + {if $element.type == 'datetime'} + {/if} {if $element.type == 'textarea'} diff --git a/www/lib/CoreLibs/ACL/Login.php b/www/lib/CoreLibs/ACL/Login.php index 4231dd65..b2ae2c7d 100644 --- a/www/lib/CoreLibs/ACL/Login.php +++ b/www/lib/CoreLibs/ACL/Login.php @@ -75,9 +75,9 @@ class Login /** @var string the user id var*/ private $euid; /** @var string _GET/_POST loginUserId parameter for non password login */ - private $login_user_id; + private $login_user_id = ''; /** @var string source, either _GET or _POST or empty */ - private $login_user_id_source; + private $login_user_id_source = ''; /** @var bool set to true if illegal characters where found in the login user id string */ private $login_unclear = false; // is set to one if login okay, or EUID is set and user is okay to access this page @@ -548,7 +548,8 @@ class Login . "OR (eu.login_user_id_valid_until IS NOT NULL AND NOW() <= eu.login_user_id_valid_until))" . ") THEN 1::INT ELSE 0::INT END AS login_user_id_valid_date, " // check if user must login - . "CASE WHEN eu.login_user_id_revalidate_after > '0 days'::INTERVAL " + . "CASE WHEN eu.login_user_id_revalidate_after IS NOT NULL " + . "AND eu.login_user_id_revalidate_after > '0 days'::INTERVAL " . "AND (eu.login_user_id_set_date + eu.login_user_id_revalidate_after)::DATE " . "<= NOW()::DATE " . "THEN 1::INT ELSE 0::INT END AS login_user_id_revalidate, " @@ -1888,7 +1889,8 @@ EOM; . "OR (eu.login_user_id_valid_until IS NOT NULL AND NOW() <= eu.login_user_id_valid_until))" . ") THEN 1::INT ELSE 0::INT END AS login_user_id_valid_date, " // check if user must login - . "CASE WHEN eu.login_user_id_revalidate_after > '0 days'::INTERVAL " + . "CASE WHEN eu.login_user_id_revalidate_after IS NOT NULL " + . "AND eu.login_user_id_revalidate_after > '0 days'::INTERVAL " . "AND eu.login_user_id_set_date + eu.login_user_id_revalidate_after <= NOW()::DATE " . "THEN 1::INT ELSE 0::INT END AS login_user_id_revalidate, " . "eu.login_user_id_locked " diff --git a/www/lib/CoreLibs/DB/Extended/ArrayIO.php b/www/lib/CoreLibs/DB/Extended/ArrayIO.php index 346b44eb..8e49914c 100644 --- a/www/lib/CoreLibs/DB/Extended/ArrayIO.php +++ b/www/lib/CoreLibs/DB/Extended/ArrayIO.php @@ -271,7 +271,15 @@ class ArrayIO extends \CoreLibs\DB\IO if ($q_select) { $q_select .= ', '; } - $q_select .= $column; + if ( + !empty($data_array['type']) && $data_array['type'] == 'datetime' && + !empty($data_array['sql_read']) + ) { + // convert tom different timestamp type + $q_select .= "TO_CHAR($column, '" . $data_array['sql_read'] . "') AS $column"; + } else { + $q_select .= $column; + } // check FK ... if (isset($this->table_array[$column]['fk']) && isset($this->table_array[$column]['value'])) { @@ -450,7 +458,12 @@ class ArrayIO extends \CoreLibs\DB\IO } elseif (isset($this->table_array[$column]['bool'])) { // boolean storeage (reverse check on ifset) $q_data .= "'" . $this->dbBoolean($this->table_array[$column]['value'], true) . "'"; - } elseif (isset($this->table_array[$column]['interval'])) { + } elseif ( + isset($this->table_array[$column]['interval']) || + isset($this->table_array[$column]['date']) || + isset($this->table_array[$column]['datetime']) || + isset($this->table_array[$column]['emptynull']) + ) { // for interval we check if no value, then we set null if ( !isset($this->table_array[$column]['value']) || diff --git a/www/lib/CoreLibs/Output/Form/Generate.php b/www/lib/CoreLibs/Output/Form/Generate.php index 66c46558..e2dbd413 100644 --- a/www/lib/CoreLibs/Output/Form/Generate.php +++ b/www/lib/CoreLibs/Output/Form/Generate.php @@ -969,11 +969,13 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO } // date (YYYY-MM-DD) if ($this->table_array[$element_name]['type'] == 'date') { - if (!$this->table_array[$element_name]['value']) { - $this->table_array[$element_name]['value'] = 'YYYY-MM-DD'; - } $data['name'] = $element_name; - $data['value'] = $this->table_array[$element_name]['value']; + $data['value'] = $this->table_array[$element_name]['value'] ?? ''; + } + // date time (no sec) (YYYY-MM-DD HH:mm) + if ($this->table_array[$element_name]['type'] == 'datetime') { + $data['name'] = $element_name; + $data['value'] = $this->table_array[$element_name]['value'] ?? ''; } // textarea if ($this->table_array[$element_name]['type'] == 'textarea') { @@ -1168,7 +1170,7 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO if (!\CoreLibs\Combined\DateTime::checkDate($this->table_array[$key]['value'])) { $this->msg .= sprintf( $this->l->__( - 'Please enter a vailid date (YYYY-MM-DD) for the %s Field!
' + 'Please enter a valid date (YYYY-MM-DD) for the %s Field!
' ), $this->table_array[$key]['output_name'] ); @@ -1178,14 +1180,22 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO if (!\CoreLibs\Combined\DateTime::checkDateTime($this->table_array[$key]['value'])) { $this->msg .= sprintf( $this->l->__( - 'Please enter a vailid time (HH:MM[:SS]) for the %s Field!
' + 'Please enter a valid time (HH:mm[:SS]) for the %s Field!
' ), $this->table_array[$key]['output_name'] ); } break; case 'datetime': // YYYY-MM-DD HH:MM[:SS] - // not implemented + if (!\CoreLibs\Combined\DateTime::checkDateTime($this->table_array[$key]['value'])) { + $this->msg .= sprintf( + $this->l->__( + 'Please enter a valid date time (YYYY-MM-DD HH:mm) ' + . 'for the %s Field!
' + ), + $this->table_array[$key]['output_name'] + ); + } break; case 'intervalshort': // ony interval n [Y/M/D] only if (preg_match("/^\d{1,3}\ ?[YMDymd]{1}$/", $this->table_array[$key]['value'])) {