From 7165a50b4d18ed283e9626b44d0b9ffca81586ec Mon Sep 17 00:00:00 2001 From: Clemens Schwaighofer Date: Wed, 26 Aug 2020 15:42:30 +0900 Subject: [PATCH] edit* table updates, config master updates, edit js updates Add password reset time/uid for a password reset flow Add password valid regex check constants in master config Add deep copy javascript object instead of direct copy to truly create new element for attaching in the cel flow Add attach array of cel elements intead of object with cel sub block --- 4dev/database/function/edit_set_group_uid.sql | 28 ++++++++++++++++ 4dev/database/table/edit_user.sql | 5 +++ 4dev/database/trigger/trg_edit_group.sql | 5 +++ www/configs/config.master.php | 17 +++++++++- www/layout/admin/javascript/edit.jq.js | 32 ++++++++++++++++--- www/lib/autoloader.php | 2 +- 6 files changed, 82 insertions(+), 7 deletions(-) create mode 100755 4dev/database/function/edit_set_group_uid.sql diff --git a/4dev/database/function/edit_set_group_uid.sql b/4dev/database/function/edit_set_group_uid.sql new file mode 100755 index 00000000..8f957bd0 --- /dev/null +++ b/4dev/database/function/edit_set_group_uid.sql @@ -0,0 +1,28 @@ +-- add uid add for edit_group table + +CREATE OR REPLACE FUNCTION set_edit_group_uid() RETURNS TRIGGER AS +$$ + DECLARE + myrec RECORD; + v_uid VARCHAR; + BEGIN + -- skip if NEW.name is not set + IF NEW.name IS NOT NULL AND NEW.name <> '' THEN + -- use NEW.name as base, remove all spaces + -- name data is already unique, so we do not need to worry about this here + v_uid := REPLACE(NEW.name, ' ', ''); + IF TG_OP = 'INSERT' THEN + -- always set + NEW.uid := v_uid; + ELSIF TG_OP = 'UPDATE' THEN + -- check if not set, then set + SELECT INTO myrec t.* FROM edit_group t WHERE edit_group_id = NEW.edit_group_id; + IF FOUND THEN + NEW.uid := v_uid; + END IF; + END IF; + END IF; + RETURN NEW; + END; +$$ + LANGUAGE 'plpgsql'; diff --git a/4dev/database/table/edit_user.sql b/4dev/database/table/edit_user.sql index 50ab8d03..e5f7c834 100644 --- a/4dev/database/table/edit_user.sql +++ b/4dev/database/table/edit_user.sql @@ -38,5 +38,10 @@ CREATE TABLE edit_user ( locked SMALLINT DEFAULT 0, password_change_date TIMESTAMP WITHOUT TIME ZONE, -- only when password is first set or changed password_change_interval INTERVAL, -- null if no change is needed, or d/m/y time interval + password_reset_time TIMESTAMP WITHOUT TIME ZONE, -- when the password reset was requested + password_reset_uid VARCHAR, -- the uid to access the password reset page additional_acl JSONB -- additional ACL as JSON string (can be set by other pages) ) INHERITS (edit_generic) WITHOUT OIDS; + +COMMENT ON COLUMN edit_user.password_reset_time IS 'When the password reset was requested. For reset page uid valid check'; +COMMENT ON COLUMN edit_user.password_reset_uid IS 'Password reset page uid'; diff --git a/4dev/database/trigger/trg_edit_group.sql b/4dev/database/trigger/trg_edit_group.sql index c53d277d..dea71524 100644 --- a/4dev/database/trigger/trg_edit_group.sql +++ b/4dev/database/trigger/trg_edit_group.sql @@ -2,3 +2,8 @@ DROP TRIGGER IF EXISTS trg_edit_group ON edit_group; CREATE TRIGGER trg_edit_group BEFORE INSERT OR UPDATE ON edit_group FOR EACH ROW EXECUTE PROCEDURE set_edit_generic(); + +DROP TRIGGER IF EXISTS trg_set_edit_group_uid ON edit_group; +CREATE TRIGGER trg_set_edit_group_uid +BEFORE INSERT OR UPDATE ON edit_group +FOR EACH ROW EXECUTE PROCEDURE set_edit_group_uid(); diff --git a/www/configs/config.master.php b/www/configs/config.master.php index 6ff5d447..c8cd89cb 100644 --- a/www/configs/config.master.php +++ b/www/configs/config.master.php @@ -101,8 +101,23 @@ define('LOGOUT_TARGET', ''); define('PASSWORD_CHANGE', false); define('PASSWORD_FORGOT', false); // min/max password length -define('PASSWORD_MIN_LENGTH', 8); +define('PASSWORD_MIN_LENGTH', 9); define('PASSWORD_MAX_LENGTH', 255); +// defines allowed special characters +DEFINE('PASSWORD_SPECIAL_RANGE', '@$!%*?&'); +// password must have upper case, lower case, number, special +// comment out for not mandatory +DEFINE('PASSWORD_LOWER', '(?=.*[a-z])'); +DEFINE('PASSWORD_UPPER', '(?=.*[A-Z])'); +DEFINE('PASSWORD_NUMBER', '(?=.*\d)'); +DEFINE('PASSWORD_SPECIAL', "(?=.*[".PASSWORD_SPECIAL_RANGE."])"); +// define full regex +DEFINE('PASSWORD_REGEX', "/^". + (defined('PASSWORD_LOWER') ? PASSWORD_LOWER : ''). + (defined('PASSWORD_UPPER') ? PASSWORD_UPPER : ''). + (defined('PASSWORD_NUMBER') ? PASSWORD_NUMBER : ''). + (defined('PASSWORD_SPECIAL') ? PASSWORD_SPECIAL : ''). + "[A-Za-z\d".PASSWORD_SPECIAL_RANGE."]{".PASSWORD_MIN_LENGTH.",".PASSWORD_MAX_LENGTH."}$/"); /************* AJAX / ACCESS *************/ // ajax request type diff --git a/www/layout/admin/javascript/edit.jq.js b/www/layout/admin/javascript/edit.jq.js index 99de37de..fc4bacc8 100644 --- a/www/layout/admin/javascript/edit.jq.js +++ b/www/layout/admin/javascript/edit.jq.js @@ -607,7 +607,9 @@ function showActionIndicator(loc) el.id = 'indicator'; $('body').append(el); } else if (!$('#indicator').hasClass('progress')) { - $('#indicator').addClass('progress'); + // if I add a class it will not be hidden anymore + // hide it + $('#indicator').addClass('progress').hide(); } // indicator not visible if (!$('#indicator').is(':visible')) { @@ -772,7 +774,8 @@ function ael(base, attach, id = '') if (id) { // base id match already if (base.id == id) { - base.sub.push(Object.assign({}, attach)); + // base.sub.push(Object.assign({}, attach)); + base.sub.push(deepCopyFunction(attach)); } else { // sub check if (isObject(base.sub) && base.sub.length > 0) { @@ -783,7 +786,8 @@ function ael(base, attach, id = '') } } } else { - base.sub.push(Object.assign({}, attach)); + // base.sub.push(Object.assign({}, attach)); + base.sub.push(deepCopyFunction(attach)); } return base; } @@ -798,7 +802,8 @@ function ael(base, attach, id = '') function aelx(base, ...attach) { for (var i = 0; i < attach.length; i ++) { - base.sub.push(Object.assign({}, attach[i])); + // base.sub.push(Object.assign({}, attach[i])); + base.sub.push(deepCopyFunction(attach[i])); } return base; } @@ -813,7 +818,8 @@ function aelx(base, ...attach) function aelxar(base, attach) { for (var i = 0; i < attach.length; i ++) { - base.sub.push(Object.assign({}, attach[i])); + // base.sub.push(Object.assign({}, attach[i])); + base.sub.push(deepCopyFunction(attach[i])); } return base; } @@ -937,6 +943,22 @@ function phfo(tree) // combine to string return content.join(''); } + +/** + * Create HTML elements from array list + * as a flat element without master object file + * Is like tree.sub call + * @param {Array} list Array of cel created objects + * @return {String} HTML String + */ +function phfa(list) +{ + var content = []; + for (i = 0; i < list.length; i ++) { + content.push(phfo(list[i])); + } + return content.join(''); +} // *** DOM MANAGEMENT FUNCTIONS // BLOCK: html wrappers for quickly creating html data blocks diff --git a/www/lib/autoloader.php b/www/lib/autoloader.php index 8f89e1c1..0705ea55 100644 --- a/www/lib/autoloader.php +++ b/www/lib/autoloader.php @@ -44,7 +44,7 @@ if (class_exists('Autoload', false) === false) { // print "(2) Class clean: $path
"; // if path is set and a valid file if ($path !== false && is_file($path)) { - // echo "(3) Load Path: $path
"; + // print "(3) Load Path: $path
"; // we should sub that // self::loadFile($path); include $path;