diff --git a/4dev/database/function/set_edit_generic.sql b/4dev/database/function/set_edit_generic.sql index c4a892bd..4ec68683 100644 --- a/4dev/database/function/set_edit_generic.sql +++ b/4dev/database/function/set_edit_generic.sql @@ -9,6 +9,7 @@ BEGIN IF TG_OP = 'INSERT' THEN NEW.date_created := 'now'; NEW.cuid := random_string(random_length); + NEW.cuuid := gen_random_uuid(); ELSIF TG_OP = 'UPDATE' THEN NEW.date_updated := 'now'; END IF; diff --git a/4dev/database/table/edit_generic.sql b/4dev/database/table/edit_generic.sql index 15320aab..1be979b3 100644 --- a/4dev/database/table/edit_generic.sql +++ b/4dev/database/table/edit_generic.sql @@ -8,6 +8,7 @@ -- DROP TABLE edit_generic; CREATE TABLE edit_generic ( cuid VARCHAR, + cuuid UUID DEFAULT gen_random_uuid(), date_created TIMESTAMP WITHOUT TIME ZONE DEFAULT clock_timestamp(), date_updated TIMESTAMP WITHOUT TIME ZONE ); diff --git a/4dev/database/table/edit_log.sql b/4dev/database/table/edit_log.sql index 97e22546..0ebf2599 100644 --- a/4dev/database/table/edit_log.sql +++ b/4dev/database/table/edit_log.sql @@ -12,6 +12,8 @@ CREATE TABLE edit_log ( FOREIGN KEY (euid) REFERENCES edit_user (edit_user_id) MATCH FULL ON UPDATE CASCADE ON DELETE SET NULL, username VARCHAR, password VARCHAR, + ecuid VARCHAR, + ecuuid UUID, event_date TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP, ip VARCHAR, error TEXT, @@ -21,6 +23,7 @@ CREATE TABLE edit_log ( page VARCHAR, action VARCHAR, action_id VARCHAR, + action_sub_id VARCHAR, action_yes VARCHAR, action_flag VARCHAR, action_menu VARCHAR, diff --git a/4dev/tests/ACL/CoreLibsACLLoginTest.php b/4dev/tests/ACL/CoreLibsACLLoginTest.php index c73d12d8..675ce307 100644 --- a/4dev/tests/ACL/CoreLibsACLLoginTest.php +++ b/4dev/tests/ACL/CoreLibsACLLoginTest.php @@ -244,6 +244,7 @@ final class CoreLibsACLLoginTest extends TestCase [ 'EUID' => 1, 'ECUID' => 'abc', + 'ECUUID' => '1233456-1234-1234-1234-123456789012', ], 2, [], @@ -262,6 +263,7 @@ final class CoreLibsACLLoginTest extends TestCase [ 'EUID' => 1, 'ECUID' => 'abc', + 'ECUUID' => '1233456-1234-1234-1234-123456789012', 'USER_NAME' => '', 'GROUP_NAME' => '', 'ADMIN' => 1, diff --git a/4dev/tests/ACL/database/CoreLibsACLLogin_database_create_data.sql b/4dev/tests/ACL/database/CoreLibsACLLogin_database_create_data.sql index af0a5f67..d3a8d0ea 100644 --- a/4dev/tests/ACL/database/CoreLibsACLLogin_database_create_data.sql +++ b/4dev/tests/ACL/database/CoreLibsACLLogin_database_create_data.sql @@ -5,15 +5,15 @@ CREATE FUNCTION random_string(randomLength int) RETURNS text AS $$ SELECT array_to_string( - ARRAY( - SELECT substring( - 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', - trunc(random() * 62)::int + 1, - 1 - ) - FROM generate_series(1, randomLength) AS gs(x) - ), - '' + ARRAY( + SELECT substring( + 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', + trunc(random() * 62)::int + 1, + 1 + ) + FROM generate_series(1, randomLength) AS gs(x) + ), + '' ) $$ LANGUAGE SQL @@ -27,15 +27,16 @@ CREATE OR REPLACE FUNCTION set_edit_generic() RETURNS TRIGGER AS $$ DECLARE - random_length INT = 12; -- that should be long enough + random_length INT = 12; -- that should be long enough BEGIN - IF TG_OP = 'INSERT' THEN - NEW.date_created := 'now'; - NEW.cuid := random_string(random_length); - ELSIF TG_OP = 'UPDATE' THEN - NEW.date_updated := 'now'; - END IF; - RETURN NEW; + IF TG_OP = 'INSERT' THEN + NEW.date_created := 'now'; + NEW.cuid := random_string(random_length); + NEW.cuuid := gen_random_uuid(); + ELSIF TG_OP = 'UPDATE' THEN + NEW.date_updated := 'now'; + END IF; + RETURN NEW; END; $$ LANGUAGE 'plpgsql'; @@ -46,29 +47,29 @@ LANGUAGE 'plpgsql'; CREATE OR REPLACE FUNCTION set_edit_access_uid() RETURNS TRIGGER AS $$ DECLARE - myrec RECORD; - v_uid VARCHAR; + 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_access t WHERE edit_access_id = NEW.edit_access_id; - IF FOUND THEN - NEW.uid := v_uid; - END IF; - END IF; - END IF; - RETURN NEW; + -- 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_access t WHERE edit_access_id = NEW.edit_access_id; + IF FOUND THEN + NEW.uid := v_uid; + END IF; + END IF; + END IF; + RETURN NEW; END; $$ - LANGUAGE 'plpgsql'; + LANGUAGE 'plpgsql'; -- END: function/edit_access_set_uid.sql -- START: function/edit_group_set_uid.sql -- add uid add for edit_group table @@ -76,29 +77,29 @@ $$ CREATE OR REPLACE FUNCTION set_edit_group_uid() RETURNS TRIGGER AS $$ DECLARE - myrec RECORD; - v_uid VARCHAR; + 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; + -- 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'; + LANGUAGE 'plpgsql'; -- END: function/edit_group_set_uid.sql -- START: function/edit_log_partition_insert.sql -- AUTHOR: Clemens Schwaighofer @@ -112,142 +113,142 @@ CREATE OR REPLACE FUNCTION edit_log_insert_trigger () RETURNS TRIGGER AS $$ DECLARE - start_date DATE := '2010-01-01'; - end_date DATE; - timeformat TEXT := 'YYYY'; - selector TEXT := 'year'; - base_table TEXT := 'edit_log'; - _interval INTERVAL := '1 ' || selector; - _interval_next INTERVAL := '2 ' || selector; - table_name TEXT; - -- compare date column - compare_date DATE := NEW.event_date; - compare_date_name TEXT := 'event_date'; - -- the create commands - command_create_table TEXT := 'CREATE TABLE IF NOT EXISTS {TABLE_NAME} (CHECK({COMPARE_DATE_NAME} >= {START_DATE} AND {COMPARE_DATE_NAME} < {END_DATE})) INHERITS ({BASE_NAME})'; - command_create_primary_key TEXT := 'ALTER TABLE {TABLE_NAME} ADD PRIMARY KEY ({BASE_TABLE}_id)'; - command_create_foreign_key_1 TEXT := 'ALTER TABLE {TABLE_NAME} ADD CONSTRAINT {TABLE_NAME}_euid_fkey FOREIGN KEY (euid) REFERENCES edit_user (edit_user_id) MATCH FULL ON UPDATE CASCADE ON DELETE SET NULL'; - command_create_trigger_1 TEXT = 'CREATE TRIGGER trg_{TABLE_NAME} BEFORE INSERT OR UPDATE ON {TABLE_NAME} FOR EACH ROW EXECUTE PROCEDURE set_edit_generic()'; + start_date DATE := '2010-01-01'; + end_date DATE; + timeformat TEXT := 'YYYY'; + selector TEXT := 'year'; + base_table TEXT := 'edit_log'; + _interval INTERVAL := '1 ' || selector; + _interval_next INTERVAL := '2 ' || selector; + table_name TEXT; + -- compare date column + compare_date DATE := NEW.event_date; + compare_date_name TEXT := 'event_date'; + -- the create commands + command_create_table TEXT := 'CREATE TABLE IF NOT EXISTS {TABLE_NAME} (CHECK({COMPARE_DATE_NAME} >= {START_DATE} AND {COMPARE_DATE_NAME} < {END_DATE})) INHERITS ({BASE_NAME})'; + command_create_primary_key TEXT := 'ALTER TABLE {TABLE_NAME} ADD PRIMARY KEY ({BASE_TABLE}_id)'; + command_create_foreign_key_1 TEXT := 'ALTER TABLE {TABLE_NAME} ADD CONSTRAINT {TABLE_NAME}_euid_fkey FOREIGN KEY (euid) REFERENCES edit_user (edit_user_id) MATCH FULL ON UPDATE CASCADE ON DELETE SET NULL'; + command_create_trigger_1 TEXT = 'CREATE TRIGGER trg_{TABLE_NAME} BEFORE INSERT OR UPDATE ON {TABLE_NAME} FOR EACH ROW EXECUTE PROCEDURE set_edit_generic()'; BEGIN - -- we are in valid start time area - IF (NEW.event_date >= start_date) THEN - -- current table name - table_name := base_table || '_' || to_char(NEW.event_date, timeformat); - BEGIN - EXECUTE 'INSERT INTO ' || quote_ident(table_name) || ' SELECT ($1).*' USING NEW; - -- if insert failed because of missing table, create new below - EXCEPTION - WHEN undefined_table THEN - -- another block, so in case the creation fails here too - BEGIN - -- create new table here + all indexes - start_date := date_trunc(selector, NEW.event_date); - end_date := date_trunc(selector, NEW.event_date + _interval); - -- creat table - EXECUTE format(REPLACE( -- end date - REPLACE( -- start date - REPLACE( -- compare date name - REPLACE( -- base name (inherit) - REPLACE( -- table name - command_create_table, - '{TABLE_NAME}', - table_name - ), - '{BASE_NAME}', - base_table - ), - '{COMPARE_DATE_NAME}', - compare_date_name - ), - '{START_DATE}', - quote_literal(start_date) - ), - '{END_DATE}', - quote_literal(end_date) - )); - -- create all indexes and triggers - EXECUTE format(REPLACE( - REPLACE( - command_create_primary_key, - '{TABLE_NAME}', - table_name - ), - '{BASE_TABLE}', - base_table - )); - -- FK constraints - EXECUTE format(REPLACE(command_create_foreign_key_1, '{TABLE_NAME}', table_name)); - -- generic trigger - EXECUTE format(REPLACE(command_create_trigger_1, '{TABLE_NAME}', table_name)); + -- we are in valid start time area + IF (NEW.event_date >= start_date) THEN + -- current table name + table_name := base_table || '_' || to_char(NEW.event_date, timeformat); + BEGIN + EXECUTE 'INSERT INTO ' || quote_ident(table_name) || ' SELECT ($1).*' USING NEW; + -- if insert failed because of missing table, create new below + EXCEPTION + WHEN undefined_table THEN + -- another block, so in case the creation fails here too + BEGIN + -- create new table here + all indexes + start_date := date_trunc(selector, NEW.event_date); + end_date := date_trunc(selector, NEW.event_date + _interval); + -- creat table + EXECUTE format(REPLACE( -- end date + REPLACE( -- start date + REPLACE( -- compare date name + REPLACE( -- base name (inherit) + REPLACE( -- table name + command_create_table, + '{TABLE_NAME}', + table_name + ), + '{BASE_NAME}', + base_table + ), + '{COMPARE_DATE_NAME}', + compare_date_name + ), + '{START_DATE}', + quote_literal(start_date) + ), + '{END_DATE}', + quote_literal(end_date) + )); + -- create all indexes and triggers + EXECUTE format(REPLACE( + REPLACE( + command_create_primary_key, + '{TABLE_NAME}', + table_name + ), + '{BASE_TABLE}', + base_table + )); + -- FK constraints + EXECUTE format(REPLACE(command_create_foreign_key_1, '{TABLE_NAME}', table_name)); + -- generic trigger + EXECUTE format(REPLACE(command_create_trigger_1, '{TABLE_NAME}', table_name)); - -- insert try again - EXECUTE 'INSERT INTO ' || quote_ident(table_name) || ' SELECT ($1).*' USING NEW; - EXCEPTION - WHEN OTHERS THEN - -- if this faled, throw it into the overflow table (so we don't loose anything) - INSERT INTO edit_log_overflow VALUES (NEW.*); - END; - -- other errors, insert into overlow - WHEN OTHERS THEN - -- if this faled, throw it into the overflow table (so we don't loose anything) - INSERT INTO edit_log_overflow VALUES (NEW.*); - END; - -- main insert run done, check if we have to create next months table - BEGIN - -- check if next month table exists - table_name := base_table || '_' || to_char((SELECT NEW.event_date + _interval)::DATE, timeformat); - -- RAISE NOTICE 'SEARCH NEXT: %', table_name; - IF (SELECT to_regclass(table_name)) IS NULL THEN - -- move inner interval same - start_date := date_trunc(selector, NEW.event_date + _interval); - end_date := date_trunc(selector, NEW.event_date + _interval_next); - -- RAISE NOTICE 'CREATE NEXT: %', table_name; - -- create table - EXECUTE format(REPLACE( -- end date - REPLACE( -- start date - REPLACE( -- compare date name - REPLACE( -- base name (inherit) - REPLACE( -- table name - command_create_table, - '{TABLE_NAME}', - table_name - ), - '{BASE_NAME}', - base_table - ), - '{COMPARE_DATE_NAME}', - compare_date_name - ), - '{START_DATE}', - quote_literal(start_date) - ), - '{END_DATE}', - quote_literal(end_date) - )); - -- create all indexes and triggers - EXECUTE format(REPLACE( - REPLACE( - command_create_primary_key, - '{TABLE_NAME}', - table_name - ), - '{BASE_TABLE}', - base_table - )); - -- FK constraints - EXECUTE format(REPLACE(command_create_foreign_key_1, '{TABLE_NAME}', table_name)); - -- generic trigger - EXECUTE format(REPLACE(command_create_trigger_1, '{TABLE_NAME}', table_name)); - END IF; - EXCEPTION - WHEN OTHERS THEN - RAISE NOTICE 'Failed to create next table: %', table_name; - END; - ELSE - -- if outside valid date, insert into overflow - INSERT INTO edit_log_overflow VALUES (NEW.*); - END IF; - RETURN NULL; + -- insert try again + EXECUTE 'INSERT INTO ' || quote_ident(table_name) || ' SELECT ($1).*' USING NEW; + EXCEPTION + WHEN OTHERS THEN + -- if this faled, throw it into the overflow table (so we don't loose anything) + INSERT INTO edit_log_overflow VALUES (NEW.*); + END; + -- other errors, insert into overlow + WHEN OTHERS THEN + -- if this faled, throw it into the overflow table (so we don't loose anything) + INSERT INTO edit_log_overflow VALUES (NEW.*); + END; + -- main insert run done, check if we have to create next months table + BEGIN + -- check if next month table exists + table_name := base_table || '_' || to_char((SELECT NEW.event_date + _interval)::DATE, timeformat); + -- RAISE NOTICE 'SEARCH NEXT: %', table_name; + IF (SELECT to_regclass(table_name)) IS NULL THEN + -- move inner interval same + start_date := date_trunc(selector, NEW.event_date + _interval); + end_date := date_trunc(selector, NEW.event_date + _interval_next); + -- RAISE NOTICE 'CREATE NEXT: %', table_name; + -- create table + EXECUTE format(REPLACE( -- end date + REPLACE( -- start date + REPLACE( -- compare date name + REPLACE( -- base name (inherit) + REPLACE( -- table name + command_create_table, + '{TABLE_NAME}', + table_name + ), + '{BASE_NAME}', + base_table + ), + '{COMPARE_DATE_NAME}', + compare_date_name + ), + '{START_DATE}', + quote_literal(start_date) + ), + '{END_DATE}', + quote_literal(end_date) + )); + -- create all indexes and triggers + EXECUTE format(REPLACE( + REPLACE( + command_create_primary_key, + '{TABLE_NAME}', + table_name + ), + '{BASE_TABLE}', + base_table + )); + -- FK constraints + EXECUTE format(REPLACE(command_create_foreign_key_1, '{TABLE_NAME}', table_name)); + -- generic trigger + EXECUTE format(REPLACE(command_create_trigger_1, '{TABLE_NAME}', table_name)); + END IF; + EXCEPTION + WHEN OTHERS THEN + RAISE NOTICE 'Failed to create next table: %', table_name; + END; + ELSE + -- if outside valid date, insert into overflow + INSERT INTO edit_log_overflow VALUES (NEW.*); + END IF; + RETURN NULL; END $$ LANGUAGE 'plpgsql'; @@ -260,22 +261,22 @@ CREATE OR REPLACE FUNCTION set_login_user_id_set_date() RETURNS TRIGGER AS $$ BEGIN - -- if new is not null/empty - -- and old one is null or old one different new one - -- set NOW() - -- if new one is NULL - -- set NULL - IF - NEW.login_user_id IS NOT NULL AND NEW.login_user_id <> '' AND - (OLD.login_user_id IS NULL OR NEW.login_user_id <> OLD.login_user_id) - THEN - NEW.login_user_id_set_date = NOW(); - NEW.login_user_id_last_revalidate = NOW(); - ELSIF NEW.login_user_id IS NULL OR NEW.login_user_id = '' THEN - NEW.login_user_id_set_date = NULL; - NEW.login_user_id_last_revalidate = NULL; - END IF; - RETURN NEW; + -- if new is not null/empty + -- and old one is null or old one different new one + -- set NOW() + -- if new one is NULL + -- set NULL + IF + NEW.login_user_id IS NOT NULL AND NEW.login_user_id <> '' AND + (OLD.login_user_id IS NULL OR NEW.login_user_id <> OLD.login_user_id) + THEN + NEW.login_user_id_set_date = NOW(); + NEW.login_user_id_last_revalidate = NOW(); + ELSIF NEW.login_user_id IS NULL OR NEW.login_user_id = '' THEN + NEW.login_user_id_set_date = NULL; + NEW.login_user_id_last_revalidate = NULL; + END IF; + RETURN NEW; END; $$ LANGUAGE 'plpgsql'; @@ -290,8 +291,8 @@ LANGUAGE 'plpgsql'; -- DROP TABLE temp_files; CREATE TABLE temp_files ( - filename VARCHAR, - folder VARCHAR + filename VARCHAR, + folder VARCHAR ); -- END: table/edit_temp_files.sql -- START: table/edit_generic.sql @@ -304,9 +305,10 @@ CREATE TABLE temp_files ( -- DROP TABLE edit_generic; CREATE TABLE edit_generic ( - cuid VARCHAR, - date_created TIMESTAMP WITHOUT TIME ZONE DEFAULT clock_timestamp(), - date_updated TIMESTAMP WITHOUT TIME ZONE + cuid VARCHAR, + cuuid UUID, + date_created TIMESTAMP WITHOUT TIME ZONE DEFAULT clock_timestamp(), + date_updated TIMESTAMP WITHOUT TIME ZONE ); -- END: table/edit_generic.sql -- START: table/edit_visible_group.sql @@ -319,9 +321,9 @@ CREATE TABLE edit_generic ( -- DROP TABLE edit_visible_group; CREATE TABLE edit_visible_group ( - edit_visible_group_id SERIAL PRIMARY KEY, - name VARCHAR, - flag VARCHAR + edit_visible_group_id SERIAL PRIMARY KEY, + name VARCHAR, + flag VARCHAR ) INHERITS (edit_generic) WITHOUT OIDS; -- END: table/edit_visible_group.sql -- START: table/edit_menu_group.sql @@ -334,10 +336,10 @@ CREATE TABLE edit_visible_group ( -- DROP TABLE edit_menu_group; CREATE TABLE edit_menu_group ( - edit_menu_group_id SERIAL PRIMARY KEY, - name VARCHAR, - flag VARCHAR, - order_number INT NOT NULL + edit_menu_group_id SERIAL PRIMARY KEY, + name VARCHAR, + flag VARCHAR, + order_number INT NOT NULL ) INHERITS (edit_generic) WITHOUT OIDS; @@ -352,18 +354,18 @@ CREATE TABLE edit_menu_group ( -- DROP TABLE edit_page; CREATE TABLE edit_page ( - edit_page_id SERIAL PRIMARY KEY, - content_alias_edit_page_id INT, -- alias for page content, if the page content is defined on a different page, ege for ajax backend pages - FOREIGN KEY (content_alias_edit_page_id) REFERENCES edit_page (edit_page_id) MATCH FULL ON DELETE RESTRICT ON UPDATE CASCADE, - filename VARCHAR, - name VARCHAR UNIQUE, - order_number INT NOT NULL, - online SMALLINT NOT NULL DEFAULT 0, - menu SMALLINT NOT NULL DEFAULT 0, - popup SMALLINT NOT NULL DEFAULT 0, - popup_x SMALLINT, - popup_y SMALLINT, - hostname VARCHAR + edit_page_id SERIAL PRIMARY KEY, + content_alias_edit_page_id INT, -- alias for page content, if the page content is defined on a different page, ege for ajax backend pages + FOREIGN KEY (content_alias_edit_page_id) REFERENCES edit_page (edit_page_id) MATCH FULL ON DELETE RESTRICT ON UPDATE CASCADE, + filename VARCHAR, + name VARCHAR UNIQUE, + order_number INT NOT NULL, + online SMALLINT NOT NULL DEFAULT 0, + menu SMALLINT NOT NULL DEFAULT 0, + popup SMALLINT NOT NULL DEFAULT 0, + popup_x SMALLINT, + popup_y SMALLINT, + hostname VARCHAR ) INHERITS (edit_generic) WITHOUT OIDS; -- END: table/edit_page.sql -- START: table/edit_query_string.sql @@ -376,13 +378,13 @@ CREATE TABLE edit_page ( -- DROP TABLE edit_query_string; CREATE TABLE edit_query_string ( - edit_query_string_id SERIAL PRIMARY KEY, - edit_page_id INT NOT NULL, - FOREIGN KEY (edit_page_id) REFERENCES edit_page (edit_page_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - enabled SMALLINT NOT NULL DEFAULT 0, - name VARCHAR, - value VARCHAR, - dynamic SMALLINT NOT NULL DEFAULT 0 + edit_query_string_id SERIAL PRIMARY KEY, + edit_page_id INT NOT NULL, + FOREIGN KEY (edit_page_id) REFERENCES edit_page (edit_page_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + enabled SMALLINT NOT NULL DEFAULT 0, + name VARCHAR, + value VARCHAR, + dynamic SMALLINT NOT NULL DEFAULT 0 ) INHERITS (edit_generic) WITHOUT OIDS; -- END: table/edit_query_string.sql -- START: table/edit_page_visible_group.sql @@ -395,10 +397,10 @@ CREATE TABLE edit_query_string ( -- DROP TABLE edit_page_visible_group; CREATE TABLE edit_page_visible_group ( - edit_page_id INT NOT NULL, - FOREIGN KEY (edit_page_id) REFERENCES edit_page (edit_page_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - edit_visible_group_id INT NOT NULL, - FOREIGN KEY (edit_visible_group_id) REFERENCES edit_visible_group (edit_visible_group_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE + edit_page_id INT NOT NULL, + FOREIGN KEY (edit_page_id) REFERENCES edit_page (edit_page_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + edit_visible_group_id INT NOT NULL, + FOREIGN KEY (edit_visible_group_id) REFERENCES edit_visible_group (edit_visible_group_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE ); -- END: table/edit_page_visible_group.sql -- START: table/edit_page_menu_group.sql @@ -411,10 +413,10 @@ CREATE TABLE edit_page_visible_group ( -- DROP TABLE edit_page_menu_group; CREATE TABLE edit_page_menu_group ( - edit_page_id INT NOT NULL, - FOREIGN KEY (edit_page_id) REFERENCES edit_page (edit_page_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - edit_menu_group_id INT NOT NULL, - FOREIGN KEY (edit_menu_group_id) REFERENCES edit_menu_group (edit_menu_group_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE + edit_page_id INT NOT NULL, + FOREIGN KEY (edit_page_id) REFERENCES edit_page (edit_page_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + edit_menu_group_id INT NOT NULL, + FOREIGN KEY (edit_menu_group_id) REFERENCES edit_menu_group (edit_menu_group_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE ); -- END: table/edit_page_menu_group.sql -- START: table/edit_access_right.sql @@ -428,11 +430,11 @@ CREATE TABLE edit_page_menu_group ( -- DROP TABLE edit_access_right; CREATE TABLE edit_access_right ( - edit_access_right_id SERIAL PRIMARY KEY, - name VARCHAR, - level SMALLINT, - type VARCHAR, - UNIQUE (level,type) + edit_access_right_id SERIAL PRIMARY KEY, + name VARCHAR, + level SMALLINT, + type VARCHAR, + UNIQUE (level,type) ) INHERITS (edit_generic) WITHOUT OIDS; -- END: table/edit_access_right.sql -- START: table/edit_scheme.sql @@ -445,12 +447,12 @@ CREATE TABLE edit_access_right ( -- DROP TABLE edit_scheme; CREATE TABLE edit_scheme ( - edit_scheme_id SERIAL PRIMARY KEY, - enabled SMALLINT NOT NULL DEFAULT 0, - name VARCHAR, - header_color VARCHAR, - css_file VARCHAR, - template VARCHAR + edit_scheme_id SERIAL PRIMARY KEY, + enabled SMALLINT NOT NULL DEFAULT 0, + name VARCHAR, + header_color VARCHAR, + css_file VARCHAR, + template VARCHAR ) INHERITS (edit_generic) WITHOUT OIDS; -- END: table/edit_scheme.sql -- START: table/edit_language.sql @@ -464,13 +466,13 @@ CREATE TABLE edit_scheme ( -- DROP TABLE edit_language; CREATE TABLE edit_language ( - edit_language_id SERIAL PRIMARY KEY, - enabled SMALLINT NOT NULL DEFAULT 0, - lang_default SMALLINT NOT NULL DEFAULT 0, - long_name VARCHAR, - short_name VARCHAR, -- en_US, en or en_US@latin without encoding - iso_name VARCHAR, -- should actually be encoding - order_number INT + edit_language_id SERIAL PRIMARY KEY, + enabled SMALLINT NOT NULL DEFAULT 0, + lang_default SMALLINT NOT NULL DEFAULT 0, + long_name VARCHAR, + short_name VARCHAR, -- en_US, en or en_US@latin without encoding + iso_name VARCHAR, -- should actually be encoding + order_number INT ) INHERITS (edit_generic) WITHOUT OIDS; -- END: table/edit_language.sql -- START: table/edit_group.sql @@ -483,16 +485,16 @@ CREATE TABLE edit_language ( -- DROP TABLE edit_group; CREATE TABLE edit_group ( - edit_group_id SERIAL PRIMARY KEY, - edit_scheme_id INT, - FOREIGN KEY (edit_scheme_id) REFERENCES edit_scheme (edit_scheme_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - edit_access_right_id INT NOT NULL, - FOREIGN KEY (edit_access_right_id) REFERENCES edit_access_right (edit_access_right_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - enabled SMALLINT NOT NULL DEFAULT 0, - deleted SMALLINT DEFAULT 0, - uid VARCHAR, - name VARCHAR, - additional_acl JSONB + edit_group_id SERIAL PRIMARY KEY, + edit_scheme_id INT, + FOREIGN KEY (edit_scheme_id) REFERENCES edit_scheme (edit_scheme_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + edit_access_right_id INT NOT NULL, + FOREIGN KEY (edit_access_right_id) REFERENCES edit_access_right (edit_access_right_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + enabled SMALLINT NOT NULL DEFAULT 0, + deleted SMALLINT DEFAULT 0, + uid VARCHAR, + name VARCHAR, + additional_acl JSONB ) INHERITS (edit_generic) WITHOUT OIDS; -- END: table/edit_group.sql -- START: table/edit_page_access.sql @@ -505,14 +507,14 @@ CREATE TABLE edit_group ( -- DROP TABLE edit_page_access; CREATE TABLE edit_page_access ( - edit_page_access_id SERIAL PRIMARY KEY, - edit_group_id INT NOT NULL, - FOREIGN KEY (edit_group_id) REFERENCES edit_group (edit_group_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - edit_page_id INT NOT NULL, - FOREIGN KEY (edit_page_id) REFERENCES edit_page (edit_page_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - edit_access_right_id INT NOT NULL, - FOREIGN KEY (edit_access_right_id) REFERENCES edit_access_right (edit_access_right_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - enabled SMALLINT NOT NULL DEFAULT 0 + edit_page_access_id SERIAL PRIMARY KEY, + edit_group_id INT NOT NULL, + FOREIGN KEY (edit_group_id) REFERENCES edit_group (edit_group_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + edit_page_id INT NOT NULL, + FOREIGN KEY (edit_page_id) REFERENCES edit_page (edit_page_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + edit_access_right_id INT NOT NULL, + FOREIGN KEY (edit_access_right_id) REFERENCES edit_access_right (edit_access_right_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + enabled SMALLINT NOT NULL DEFAULT 0 ) INHERITS (edit_generic) WITHOUT OIDS; @@ -528,15 +530,15 @@ CREATE TABLE edit_page_access ( -- DROP TABLE edit_page_content; CREATE TABLE edit_page_content ( - edit_page_content_id SERIAL PRIMARY KEY, - edit_page_id INT NOT NULL, - FOREIGN KEY (edit_page_id) REFERENCES edit_page (edit_page_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - edit_access_right_id INT NOT NULL, - FOREIGN KEY (edit_access_right_id) REFERENCES edit_access_right (edit_access_right_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - uid VARCHAR UNIQUE, - name VARCHAR, - order_number INT NOT NULL, - online SMALLINT NOT NULL DEFAULT 0 + edit_page_content_id SERIAL PRIMARY KEY, + edit_page_id INT NOT NULL, + FOREIGN KEY (edit_page_id) REFERENCES edit_page (edit_page_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + edit_access_right_id INT NOT NULL, + FOREIGN KEY (edit_access_right_id) REFERENCES edit_access_right (edit_access_right_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + uid VARCHAR UNIQUE, + name VARCHAR, + order_number INT NOT NULL, + online SMALLINT NOT NULL DEFAULT 0 ) INHERITS (edit_generic) WITHOUT OIDS; -- END: table/edit_page_content.sql -- START: table/edit_user.sql @@ -549,63 +551,63 @@ CREATE TABLE edit_page_content ( -- DROP TABLE edit_user; CREATE TABLE edit_user ( - edit_user_id SERIAL PRIMARY KEY, - connect_edit_user_id INT, -- possible reference to other user - FOREIGN KEY (connect_edit_user_id) REFERENCES edit_user (edit_user_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - edit_language_id INT NOT NULL, - FOREIGN KEY (edit_language_id) REFERENCES edit_language (edit_language_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - edit_group_id INT NOT NULL, - FOREIGN KEY (edit_group_id) REFERENCES edit_group (edit_group_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - edit_scheme_id INT, - FOREIGN KEY (edit_scheme_id) REFERENCES edit_scheme (edit_scheme_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - edit_access_right_id INT NOT NULL, - FOREIGN KEY (edit_access_right_id) REFERENCES edit_access_right (edit_access_right_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - -- username/password - username VARCHAR UNIQUE, - password VARCHAR, - -- name block - first_name VARCHAR, - last_name VARCHAR, - first_name_furigana VARCHAR, - last_name_furigana VARCHAR, - -- email - email VARCHAR, - -- eanbled/deleted flag - enabled SMALLINT NOT NULL DEFAULT 0, - deleted SMALLINT NOT NULL DEFAULT 0, - -- general flags - strict SMALLINT DEFAULT 0, - locked SMALLINT DEFAULT 0, - protected SMALLINT NOT NULL DEFAULT 0, - -- legacy, debug flags - debug SMALLINT NOT NULL DEFAULT 0, - db_debug SMALLINT NOT NULL DEFAULT 0, - -- is admin user - admin SMALLINT NOT NULL DEFAULT 0, - -- last login log - last_login TIMESTAMP WITHOUT TIME ZONE, - -- login error - login_error_count INT DEFAULT 0, - login_error_date_last TIMESTAMP WITHOUT TIME ZONE, - login_error_date_first TIMESTAMP WITHOUT TIME ZONE, - -- time locked - lock_until TIMESTAMP WITHOUT TIME ZONE, - lock_after TIMESTAMP WITHOUT TIME ZONE, - -- password change - 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 - -- _GET login id for direct login - login_user_id VARCHAR UNIQUE, -- the loginUserId, at least 32 chars - login_user_id_set_date TIMESTAMP WITHOUT TIME ZONE, -- when above uid was set - login_user_id_last_revalidate TIMESTAMP WITHOUT TIME ZONE, -- when the last login was done with user name and password - 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, -- user must login to revalidated loginUserId after set days, 0 for forever - login_user_id_locked SMALLINT DEFAULT 0, -- lock for loginUserId, but still allow normal login - -- additional ACL json block - additional_acl JSONB -- additional ACL as JSON string (can be set by other pages) + edit_user_id SERIAL PRIMARY KEY, + connect_edit_user_id INT, -- possible reference to other user + FOREIGN KEY (connect_edit_user_id) REFERENCES edit_user (edit_user_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + edit_language_id INT NOT NULL, + FOREIGN KEY (edit_language_id) REFERENCES edit_language (edit_language_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + edit_group_id INT NOT NULL, + FOREIGN KEY (edit_group_id) REFERENCES edit_group (edit_group_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + edit_scheme_id INT, + FOREIGN KEY (edit_scheme_id) REFERENCES edit_scheme (edit_scheme_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + edit_access_right_id INT NOT NULL, + FOREIGN KEY (edit_access_right_id) REFERENCES edit_access_right (edit_access_right_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + -- username/password + username VARCHAR UNIQUE, + password VARCHAR, + -- name block + first_name VARCHAR, + last_name VARCHAR, + first_name_furigana VARCHAR, + last_name_furigana VARCHAR, + -- email + email VARCHAR, + -- eanbled/deleted flag + enabled SMALLINT NOT NULL DEFAULT 0, + deleted SMALLINT NOT NULL DEFAULT 0, + -- general flags + strict SMALLINT DEFAULT 0, + locked SMALLINT DEFAULT 0, + protected SMALLINT NOT NULL DEFAULT 0, + -- legacy, debug flags + debug SMALLINT NOT NULL DEFAULT 0, + db_debug SMALLINT NOT NULL DEFAULT 0, + -- is admin user + admin SMALLINT NOT NULL DEFAULT 0, + -- last login log + last_login TIMESTAMP WITHOUT TIME ZONE, + -- login error + login_error_count INT DEFAULT 0, + login_error_date_last TIMESTAMP WITHOUT TIME ZONE, + login_error_date_first TIMESTAMP WITHOUT TIME ZONE, + -- time locked + lock_until TIMESTAMP WITHOUT TIME ZONE, + lock_after TIMESTAMP WITHOUT TIME ZONE, + -- password change + 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 + -- _GET login id for direct login + login_user_id VARCHAR UNIQUE, -- the loginUserId, at least 32 chars + login_user_id_set_date TIMESTAMP WITHOUT TIME ZONE, -- when above uid was set + login_user_id_last_revalidate TIMESTAMP WITHOUT TIME ZONE, -- when the last login was done with user name and password + 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, -- user must login to revalidated loginUserId after set days, 0 for forever + login_user_id_locked SMALLINT DEFAULT 0, -- lock for loginUserId, 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 @@ -650,37 +652,40 @@ COMMENT ON COLUMN edit_user.additional_acl IS 'Additional Access Control List st -- DROP TABLE edit_log; CREATE TABLE edit_log ( - edit_log_id SERIAL PRIMARY KEY, - euid INT, -- this is a foreign key, but I don't nedd to reference to it - FOREIGN KEY (euid) REFERENCES edit_user (edit_user_id) MATCH FULL ON UPDATE CASCADE ON DELETE SET NULL, - username VARCHAR, - password VARCHAR, - event_date TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP, - ip VARCHAR, - error TEXT, - event TEXT, - data_binary BYTEA, - data TEXT, - page VARCHAR, - action VARCHAR, - action_id VARCHAR, - action_yes VARCHAR, - action_flag VARCHAR, - action_menu VARCHAR, - action_loaded VARCHAR, - action_value VARCHAR, - action_type VARCHAR, - action_error VARCHAR, - user_agent VARCHAR, - referer VARCHAR, - script_name VARCHAR, - query_string VARCHAR, - server_name VARCHAR, - http_host VARCHAR, - http_accept VARCHAR, - http_accept_charset VARCHAR, - http_accept_encoding VARCHAR, - session_id VARCHAR + edit_log_id SERIAL PRIMARY KEY, + euid INT, -- this is a foreign key, but I don't nedd to reference to it + ecuid VARCHAR, + ecuuid UUID, + FOREIGN KEY (euid) REFERENCES edit_user (edit_user_id) MATCH FULL ON UPDATE CASCADE ON DELETE SET NULL, + username VARCHAR, + password VARCHAR, + event_date TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP, + ip VARCHAR, + error TEXT, + event TEXT, + data_binary BYTEA, + data TEXT, + page VARCHAR, + action VARCHAR, + action_id VARCHAR, + action_sub_id VARCHAR, + action_yes VARCHAR, + action_flag VARCHAR, + action_menu VARCHAR, + action_loaded VARCHAR, + action_value VARCHAR, + action_type VARCHAR, + action_error VARCHAR, + user_agent VARCHAR, + referer VARCHAR, + script_name VARCHAR, + query_string VARCHAR, + server_name VARCHAR, + http_host VARCHAR, + http_accept VARCHAR, + http_accept_charset VARCHAR, + http_accept_encoding VARCHAR, + session_id VARCHAR ) INHERITS (edit_generic) WITHOUT OIDS; -- END: table/edit_log.sql -- START: table/edit_log_overflow.sql @@ -707,15 +712,15 @@ ALTER TABLE edit_log_overflow ADD CONSTRAINT edit_log_overflow_euid_fkey FOREIGN -- DROP TABLE edit_access; CREATE TABLE edit_access ( - edit_access_id SERIAL PRIMARY KEY, - enabled SMALLINT NOT NULL DEFAULT 0, - protected SMALLINT DEFAULT 0, - deleted SMALLINT DEFAULT 0, - uid VARCHAR, - name VARCHAR UNIQUE, - description VARCHAR, - color VARCHAR, - additional_acl JSONB + edit_access_id SERIAL PRIMARY KEY, + enabled SMALLINT NOT NULL DEFAULT 0, + protected SMALLINT DEFAULT 0, + deleted SMALLINT DEFAULT 0, + uid VARCHAR, + name VARCHAR UNIQUE, + description VARCHAR, + color VARCHAR, + additional_acl JSONB ) INHERITS (edit_generic) WITHOUT OIDS; -- END: table/edit_access.sql -- START: table/edit_access_user.sql @@ -728,15 +733,15 @@ CREATE TABLE edit_access ( -- DROP TABLE edit_access_user; CREATE TABLE edit_access_user ( - edit_access_user_id SERIAL PRIMARY KEY, - edit_access_id INT NOT NULL, - FOREIGN KEY (edit_access_id) REFERENCES edit_access (edit_access_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - edit_user_id INT NOT NULL, - FOREIGN KEY (edit_user_id) REFERENCES edit_user (edit_user_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - edit_access_right_id INT NOT NULL, - FOREIGN KEY (edit_access_right_id) REFERENCES edit_access_right (edit_access_right_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - edit_default SMALLINT DEFAULT 0, - enabled SMALLINT NOT NULL DEFAULT 0 + edit_access_user_id SERIAL PRIMARY KEY, + edit_access_id INT NOT NULL, + FOREIGN KEY (edit_access_id) REFERENCES edit_access (edit_access_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + edit_user_id INT NOT NULL, + FOREIGN KEY (edit_user_id) REFERENCES edit_user (edit_user_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + edit_access_right_id INT NOT NULL, + FOREIGN KEY (edit_access_right_id) REFERENCES edit_access_right (edit_access_right_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + edit_default SMALLINT DEFAULT 0, + enabled SMALLINT NOT NULL DEFAULT 0 ) INHERITS (edit_generic) WITHOUT OIDS; -- END: table/edit_access_user.sql -- START: table/edit_access_data.sql @@ -749,12 +754,12 @@ CREATE TABLE edit_access_user ( -- DROP TABLE edit_access_data; CREATE TABLE edit_access_data ( - edit_access_data_id SERIAL PRIMARY KEY, - edit_access_id INT NOT NULL, - FOREIGN KEY (edit_access_id) REFERENCES edit_access (edit_access_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, - enabled SMALLINT NOT NULL DEFAULT 0, - name VARCHAR, - value VARCHAR + edit_access_data_id SERIAL PRIMARY KEY, + edit_access_id INT NOT NULL, + FOREIGN KEY (edit_access_id) REFERENCES edit_access (edit_access_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE, + enabled SMALLINT NOT NULL DEFAULT 0, + name VARCHAR, + value VARCHAR ) INHERITS (edit_generic) WITHOUT OIDS; -- create a unique index for each attached data block for each edit access can diff --git a/4dev/update/20241203_update_edit_tables/edit_tables_cuid_cuuid_update_add.sql b/4dev/update/20241203_update_edit_tables/edit_tables_cuid_cuuid_update_add.sql new file mode 100644 index 00000000..f4e36ec3 --- /dev/null +++ b/4dev/update/20241203_update_edit_tables/edit_tables_cuid_cuuid_update_add.sql @@ -0,0 +1,26 @@ +-- 20241203: update edit tables +ALTER TABLE edit_generic ADD cuuid UUID DEFAULT gen_random_uuid(); +ALTER TABLE edit_log ADD ecuid VARCHAR; +ALTER TABLE edit_log ADD ecuuid VARCHAR; +ALTER TABLE edit_log ADD action_sub_id VARCHAR; + +-- update set_edit_gneric +-- adds the created or updated date tags + +CREATE OR REPLACE FUNCTION set_edit_generic() +RETURNS TRIGGER AS +$$ +DECLARE + random_length INT = 25; -- that should be long enough +BEGIN + IF TG_OP = 'INSERT' THEN + NEW.date_created := 'now'; + NEW.cuid := random_string(random_length); + NEW.cuuid := gen_random_uuid(); + ELSIF TG_OP = 'UPDATE' THEN + NEW.date_updated := 'now'; + END IF; + RETURN NEW; +END; +$$ +LANGUAGE 'plpgsql'; diff --git a/www/admin/class_test.admin.backend.php b/www/admin/class_test.admin.backend.php index c117aec1..492bbd8e 100644 --- a/www/admin/class_test.admin.backend.php +++ b/www/admin/class_test.admin.backend.php @@ -42,6 +42,20 @@ $backend = new CoreLibs\Admin\Backend( $l10n, DEFAULT_ACL_LEVEL ); +$login = new CoreLibs\ACL\Login( + $db, + $log, + $session, + [ + 'auto_login' => false, + 'default_acl_level' => DEFAULT_ACL_LEVEL, + 'logout_target' => '', + 'site_locale' => SITE_LOCALE, + 'site_domain' => SITE_DOMAIN, + 'site_encoding' => SITE_ENCODING, + 'locale_path' => BASE . INCLUDES . LOCALE, + ] +); use CoreLibs\Debug\Support; $PAGE_NAME = 'TEST CLASS: ADMIN BACKEND'; @@ -55,10 +69,30 @@ print '

' . $PAGE_NAME . '

'; print "SETACL[]:
"; $backend->setACL(['EMPTY' => 'EMPTY']); print "ADBEDITLOG:
"; -$backend->adbEditLog('CLASSTEST-ADMIN-BINARY', 'Some info string', 'BINARY'); -$backend->adbEditLog('CLASSTEST-ADMIN-ZLIB', 'Some info string', 'ZLIB'); -$backend->adbEditLog('CLASSTEST-ADMIN-SERIAL', 'Some info string', 'SERIAL'); -$backend->adbEditLog('CLASSTEST-ADMIN-INVALID', 'Some info string', 'INVALID'); +$login->writeLog( + 'CLASSTEST-ADMIN-BINARY', + 'Some info string', + $backend->adbGetActionSet(), + write_type:'BINARY' +); +$login->writeLog( + 'CLASSTEST-ADMIN-ZLIB', + 'Some info string', + $backend->adbGetActionSet(), + write_type:'ZLIB' +); +$login->writeLog( + 'CLASSTEST-ADMIN-SERIAL', + 'Some info string', + $backend->adbGetActionSet(), + write_type:'SERIAL' +); +$login->writeLog( + 'CLASSTEST-ADMIN-INVALID', + 'Some info string', + $backend->adbGetActionSet(), + write_type:'INVALID' +); // test with various $backend->action = 'TEST ACTION'; $backend->action_id = 'TEST ACTION ID'; @@ -69,10 +103,10 @@ $backend->action_loaded = 'TEST ACTION LOADED'; $backend->action_value = 'TEST ACTION VALUE'; $backend->action_type = 'TEST ACTION TYPE'; $backend->action_error = 'TEST ACTION ERROR'; -$backend->adbEditLog('CLASSTEST-ADMIN-JSON', [ +$login->writeLog('CLASSTEST-ADMIN-JSON', [ "_GET" => $_GET, "_POST" => $_POST, -], 'JSON'); +], $backend->adbGetActionSet(), write_type:'JSON'); print "ADBTOPMENU(0): " . Support::printAr($backend->adbTopMenu(CONTENT_PATH)) . "
"; print "ADBMSG:
"; diff --git a/www/admin/class_test.login.php b/www/admin/class_test.login.php index af400089..3d1327d5 100644 --- a/www/admin/class_test.login.php +++ b/www/admin/class_test.login.php @@ -58,4 +58,16 @@ echo "ACL: " . \CoreLibs\Debug\Support::printAr($login->loginGetAcl()) . "
"; echo "ACL (MIN): " . \CoreLibs\Debug\Support::printAr($login->loginGetAcl()['min'] ?? []) . "
"; echo "LOCALE: " . \CoreLibs\Debug\Support::printAr($login->loginGetLocale()) . "
"; +echo "ECUID: " . $login->loginGetEcuid() . "
"; +echo "ECUUID: " . $login->loginGetEcuuid() . "
"; + +$login->writeLog( + 'TEST LOG', + [ + 'test' => 'TEST A' + ], + error:'No Error', + write_type:'JSON' +); + print ""; diff --git a/www/admin/class_test.php b/www/admin/class_test.php index a6355cec..3b75efc8 100644 --- a/www/admin/class_test.php +++ b/www/admin/class_test.php @@ -205,6 +205,9 @@ print "HOST: " . HOST_NAME . " => DB HOST: " . DB_CONFIG_NAME . " => " . Support print "DS is: " . DIRECTORY_SEPARATOR . "
"; print "SERVER HOST: " . $_SERVER['HTTP_HOST'] . "
"; +print "ECUID: " . $_SESSION['ECUID'] . "
"; +print "ECUUID: " . $_SESSION['ECUUID'] . "
"; + print ""; # __END__ diff --git a/www/includes/admin_header.php b/www/includes/admin_header.php index 50797179..d6176102 100644 --- a/www/includes/admin_header.php +++ b/www/includes/admin_header.php @@ -116,7 +116,7 @@ $data = [ // log action // no log if login if (!$login->loginActionRun()) { - $cms->adbEditLog('Submit', $data, 'BINARY'); + $login->writeLog('Submit', $data, $cms->adbGetActionSet(), 'BINARY'); } //------------------------------ logging end diff --git a/www/lib/CoreLibs/ACL/Login.php b/www/lib/CoreLibs/ACL/Login.php index dcbee940..48a73282 100644 --- a/www/lib/CoreLibs/ACL/Login.php +++ b/www/lib/CoreLibs/ACL/Login.php @@ -69,6 +69,7 @@ declare(strict_types=1); namespace CoreLibs\ACL; use CoreLibs\Security\Password; +use CoreLibs\Create\Uids; use CoreLibs\Convert\Json; class Login @@ -77,6 +78,8 @@ class Login private ?int $euid; /** @var ?string the user cuid (note will be super seeded with uuid v4 later) */ private ?string $ecuid; + /** @var ?string UUIDv4, will superseed the ecuid and replace euid as login id */ + private ?string $ecuuid; /** @var string _GET/_POST loginUserId parameter for non password login */ private string $login_user_id = ''; /** @var string source, either _GET or _POST or empty */ @@ -195,6 +198,12 @@ class Login /** @var bool */ private bool $login_is_ajax_page = false; + // logging + /** @var array list of allowed types for edit log write */ + private const WRITE_TYPES = ['BINARY', 'BZIP2', 'LZIP', 'STRING', 'SERIAL', 'JSON']; + /** @var array list of available write types for log */ + private array $write_types_available = []; + // settings /** @var array options */ private array $options = []; @@ -381,6 +390,8 @@ class Login $_SESSION['DEFAULT_ACL_LIST'] = $this->default_acl_list; $_SESSION['DEFAULT_ACL_LIST_TYPE'] = $this->default_acl_list_type; + $this->loginSetEditLogWriteTypeAvailable(); + // this will be deprecated if ($this->options['auto_login'] === true) { $this->loginMainCall(); @@ -759,7 +770,7 @@ class Login } // have to get the global stuff here for setting it later // we have to get the themes in here too - $q = "SELECT eu.edit_user_id, eu.cuid, eu.username, eu.password, " + $q = "SELECT eu.edit_user_id, eu.cuid, eu.cuuid, eu.username, eu.password, " . "eu.edit_group_id, " . "eg.name AS edit_group_name, eu.admin, " // additinal acl lists @@ -892,6 +903,7 @@ class Login // set class var and session var $_SESSION['EUID'] = $this->euid = (int)$res['edit_user_id']; $_SESSION['ECUID'] = $this->ecuid = (string)$res['cuid']; + $_SESSION['ECUUID'] = $this->ecuuid = (string)$res['cuuid']; // check if user is okay $this->loginCheckPermissions(); if ($this->login_error == 0) { @@ -1137,6 +1149,7 @@ class Login $this->acl['group_name'] = $_SESSION['GROUP_NAME']; // edit user cuid $this->acl['ecuid'] = $_SESSION['ECUID']; + $this->acl['ecuuid'] = $_SESSION['ECUUID']; // set additional acl $this->acl['additional_acl'] = [ 'user' => $_SESSION['USER_ADDITIONAL_ACL'], @@ -1430,7 +1443,7 @@ class Login $data = 'Illegal user for password change: ' . $this->pw_username; } // log this password change attempt - $this->writeLog($event, $data, $this->login_error, $this->pw_username); + $this->writeEditLog($event, $data, $this->login_error, $this->pw_username); } /** @@ -1571,7 +1584,7 @@ class Login $username = $res['username']; } } // if euid is set, get username (or try) - $this->writeLog($event, '', $this->login_error, $username); + $this->writeEditLog($event, '', $this->login_error, $username); } // write log under certain settings // now close DB connection // $this->error_msg = $this->_login(); @@ -1727,6 +1740,8 @@ HTML; } } + // MARK: LOGGING + /** * writes detailed data into the edit user log table (keep log what user does) * @@ -1736,7 +1751,7 @@ HTML; * @param string $username login user username * @return void has no return */ - private function writeLog( + private function writeEditLog( string $event, string $data, string|int $error = '', @@ -1754,50 +1769,191 @@ HTML; '_GET' => $_GET, '_POST' => $_POST, '_FILES' => $_FILES, - 'error' => $this->login_error + 'error' => $this->login_error, + 'data' => $data, ]; - $data_binary = $this->db->dbEscapeBytea((string)bzcompress(serialize($_data_binary))); - // SQL querie for log entry - $q = "INSERT INTO edit_log " - . "(username, password, euid, event_date, event, error, data, data_binary, page, " - . "ip, user_agent, referer, script_name, query_string, server_name, http_host, " - . "http_accept, http_accept_charset, http_accept_encoding, session_id, " - . "action, action_id, action_yes, action_flag, action_menu, action_loaded, " - . "action_value, action_error) " - . "VALUES ('" . $this->db->dbEscapeString($username) . "', 'PASSWORD', " - . ($this->euid ? $this->euid : 'NULL') . ", " - . "NOW(), '" . $this->db->dbEscapeString($event) . "', " - . "'" . $this->db->dbEscapeString((string)$error) . "', " - . "'" . $this->db->dbEscapeString($data) . "', '" . $data_binary . "', " - . "'" . $this->page_name . "', "; - foreach ( - [ - 'REMOTE_ADDR', 'HTTP_USER_AGENT', 'HTTP_REFERER', 'SCRIPT_FILENAME', - 'QUERY_STRING', 'SERVER_NAME', 'HTTP_HOST', 'HTTP_ACCEPT', - 'HTTP_ACCEPT_CHARSET', 'HTTP_ACCEPT_ENCODING' - ] as $server_code - ) { - if (array_key_exists($server_code, $_SERVER)) { - $q .= "'" . $this->db->dbEscapeString($_SERVER[$server_code]) . "', "; - } else { - $q .= "NULL, "; - } + $_action_set = [ + 'action' => $this->action, + 'action_id' => $this->username, + 'action_flag' => (string)$this->login_error, + 'action_value' => (string)$this->permission_okay, + ]; + + $this->writeLog($event, $_data_binary, $_action_set, $error, $username); + } + + /** + * writes all action vars plus other info into edit_log table + * this is for public class + * + * phpcs:disable Generic.Files.LineLength + * @param string $event [default=''] any kind of event description, + * @param string|array $data [default=''] any kind of data related to that event + * @param array{action?:?string,action_id?:null|string|int,action_sub_id?:null|string|int,action_yes?:null|string|int|bool,action_flag?:?string,action_menu?:?string,action_loaded?:?string,action_value?:?string,action_type?:?string,action_error?:?string} $action_set [default=[]] action set names + * @param string|int $error error id (mostly an int) + * @param string $write_type [default=JSON] write type can be + * JSON, STRING/SERIEAL, BINARY/BZIP or ZLIB + * @param string|null $db_schema [default=null] override target schema + * @return void + * phpcs:enable Generic.Files.LineLength + */ + public function writeLog( + string $event = '', + string|array $data = '', + array $action_set = [], + string|int $error = '', + string $username = '', + string $write_type = 'JSON', + ?string $db_schema = null + ): void { + $data_binary = ''; + $data_write = ''; + + // check if write type is valid, if not fallback to JSON + if (!in_array(strtoupper($write_type), $this->write_types_available)) { + $this->log->warning('Write type not in allowed array, fallback to JSON', context:[ + "write_type" => $write_type, + "write_list" => $this->write_types_available, + ]); + $write_type = 'JSON'; + } + switch ($write_type) { + case 'BINARY': + case 'BZIP': + $data_binary = $this->db->dbEscapeBytea((string)bzcompress(serialize($data))); + $data_write = Json::jsonConvertArrayTo([ + 'type' => 'BZIP', + 'message' => 'see bzip compressed data_binary field' + ]); + break; + case 'ZLIB': + $data_binary = $this->db->dbEscapeBytea((string)gzcompress(serialize($data))); + $data_write = Json::jsonConvertArrayTo([ + 'type' => 'ZLIB', + 'message' => 'see zlib compressed data_binary field' + ]); + break; + case 'STRING': + case 'SERIAL': + $data_binary = $this->db->dbEscapeBytea(Json::jsonConvertArrayTo([ + 'type' => 'SERIAL', + 'message' => 'see serial string data field' + ])); + $data_write = serialize($data); + break; + case 'JSON': + $data_binary = $this->db->dbEscapeBytea(Json::jsonConvertArrayTo([ + 'type' => 'JSON', + 'message' => 'see json string data field' + ])); + // must be converted to array + if (!is_array($data)) { + $data = ["data" => $data]; + } + $data_write = Json::jsonConvertArrayTo($data); + break; + default: + $this->log->alert('Invalid type for data compression was set', context:[ + "write_type" => $write_type + ]); + break; + } + + /** @var string $DB_SCHEMA check schema */ + $DB_SCHEMA = 'public'; + if ($db_schema !== null) { + $DB_SCHEMA = $db_schema; + } elseif (!empty($this->db->dbGetSchema())) { + $DB_SCHEMA = $this->db->dbGetSchema(); + } + $q = <<db->dbExecParams( + str_replace( + ['{DB_SCHEMA}'], + [$DB_SCHEMA], + $q + ), + [ + // row 1 + empty($username) ? $_SESSION['USER_NAME'] ?? '' : $username, + !empty($_SESSION['EUID']) && is_numeric($_SESSION['EUID']) ? + $_SESSION['EUID'] : null, + !empty($_SESSION['ECUID']) && is_string($_SESSION['ECUID']) ? + $_SESSION['ECUID'] : null, + !empty($_SESSION['ECUUID']) && Uids::validateUuuidv4($_SESSION['ECUUID']) ? + $_SESSION['ECUUID'] : null, + (string)$event, + (string)$error, + $data_write, + $data_binary, + (string)$this->page_name, + // row 2 + $_SERVER["REMOTE_ADDR"] ?? null, + $_SERVER['HTTP_USER_AGENT'] ?? null, + $_SERVER['HTTP_REFERER'] ?? null, + $_SERVER['SCRIPT_FILENAME'] ?? null, + $_SERVER['QUERY_STRING'] ?? null, + $_SERVER['SERVER_NAME'] ?? null, + $_SERVER['HTTP_HOST'] ?? null, + // row 3 + $_SERVER['HTTP_ACCEPT'] ?? null, + $_SERVER['HTTP_ACCEPT_CHARSET'] ?? null, + $_SERVER['HTTP_ACCEPT_ENCODING'] ?? null, + $this->session->getSessionId() !== false ? + $this->session->getSessionId() : null, + // row 4 + $action_set['action'] ?? null, + $action_set['action_id'] ?? null, + $action_set['action_sub_id'] ?? null, + $action_set['action_yes'] ?? null, + $action_set['action_flag'] ?? null, + $action_set['action_menu'] ?? null, + $action_set['action_loaded'] ?? null, + $action_set['action_value'] ?? null, + $action_set['action_type'] ?? null, + $action_set['action_error'] ?? null, + ], + 'NULL' + ); + } + + /** + * set the write types that are allowed + * + * @return void + */ + private function loginSetEditLogWriteTypeAvailable() + { + // check what edit log data write types are allowed + $this->write_types_available = self::WRITE_TYPES; + if (!function_exists('bzcompress')) { + $this->write_types_available = array_diff($this->write_types_available, ['BINARY', 'BZIP']); + } + if (!function_exists('gzcompress')) { + $this->write_types_available = array_diff($this->write_types_available, ['LZIP']); } - $q .= "'" . $this->session->getSessionId() . "', "; - $q .= "'" . $this->db->dbEscapeString($this->action) . "', "; - $q .= "'" . $this->db->dbEscapeString($this->username) . "', "; - $q .= "NULL, "; - $q .= "'" . $this->db->dbEscapeString((string)$this->login_error) . "', "; - $q .= "NULL, NULL, "; - $q .= "'" . $this->db->dbEscapeString((string)$this->permission_okay) . "', "; - $q .= "NULL)"; - $this->db->dbExec($q, 'NULL'); } // ************************************************************************* // **** PUBLIC INTERNAL // ************************************************************************* + // MARK: LOGIN CALL + /** * Main call that needs to be run to actaully check for login * If this is not called, no login checks are done, unless the class @@ -1869,6 +2025,7 @@ HTML; $this->euid = array_key_exists('EUID', $_SESSION) ? (int)$_SESSION['EUID'] : 0; // TODO: allow load from cuid // $this->ecuid = array_key_exists('ECUID', $_SESSION) ? (string)$_SESSION['ECUID'] : ''; + // $this->ecuuid = array_key_exists('ECUUID', $_SESSION) ? (string)$_SESSION['ECUUID'] : ''; // get login vars, are so, can't be changed // prepare // pass on vars to Object vars @@ -1949,6 +2106,8 @@ HTML; $this->loginSetAcl(); } + // MARK: setters/getters + /** * Returns current set login_html content * @@ -2119,6 +2278,7 @@ HTML; // unset euid $this->euid = null; $this->ecuid = null; + $this->ecuuid = null; // then prints the login screen again $this->permission_okay = false; } @@ -2136,12 +2296,12 @@ HTML; if (empty($this->euid)) { return $this->permission_okay; } - // euid must match ecuid + // euid must match ecuid and ecuuid // bail for previous wrong page match, eg if method is called twice if ($this->login_error == 103) { return $this->permission_okay; } - $q = "SELECT ep.filename, eu.cuid, " + $q = "SELECT ep.filename, eu.cuid, eu.cuuid, " // base lock flags . "eu.deleted, eu.enabled, eu.locked, " // date based lock @@ -2209,6 +2369,7 @@ HTML; } // set ECUID $_SESSION['ECUID'] = $this->ecuid = (string)$res['cuid']; + $_SESSION['ECUUID'] = $this->ecuuid = (string)$res['cuuid']; // if called from public, so we can check if the permissions are ok return $this->permission_okay; } @@ -2520,10 +2681,20 @@ HTML; * * @return string ECUID as string */ - public function loginGetEcid(): string + public function loginGetEcuid(): string { return (string)$this->ecuid; } + + /** + * Get the current set ECUUID (edit user cuuid) + * + * @return string ECUUID as string + */ + public function loginGetEcuuid(): string + { + return (string)$this->ecuuid; + } } // __END__ diff --git a/www/lib/CoreLibs/Admin/Backend.php b/www/lib/CoreLibs/Admin/Backend.php index 5fb2918b..1c088cae 100644 --- a/www/lib/CoreLibs/Admin/Backend.php +++ b/www/lib/CoreLibs/Admin/Backend.php @@ -31,6 +31,7 @@ declare(strict_types=1); namespace CoreLibs\Admin; +use CoreLibs\Create\Uids; use CoreLibs\Convert\Json; class Backend @@ -258,6 +259,27 @@ class Backend } } + /** + * return all the action data, if not set, sets entry to null + * + * @return array{action:?string,action_id:null|string|int,action_sub_id:null|string|int,action_yes:null|string|int|bool,action_flag:?string,action_menu:?string,action_loaded:?string,action_value:?string,action_type:?string,action_error:?string} + */ + public function adbGetActionSet(): array + { + return [ + 'action' => $this->action ?? null, + 'action_id' => $this->action_id ?? null, + 'action_sub_id' => $this->action_sub_id ?? null, + 'action_yes' => $this->action_yes ?? null, + 'action_flag' => $this->action_flag ?? null, + 'action_menu' => $this->action_menu ?? null, + 'action_loaded' => $this->action_loaded ?? null, + 'action_value' => $this->action_value ?? null, + 'action_type' => $this->action_type ?? null, + 'action_error' => $this->action_error ?? null, + ]; + } + /** * writes all action vars plus other info into edit_log table * @@ -267,6 +289,7 @@ class Backend * JSON, STRING/SERIEAL, BINARY/BZIP or ZLIB * @param string|null $db_schema [default=null] override target schema * @return void + * @deprecated Use $login->writeLog() and set action_set from ->adbGetActionSet() */ public function adbEditLog( string $event = '', @@ -335,17 +358,17 @@ class Backend } $q = <<db->dbExecParams( @@ -356,9 +379,15 @@ class Backend ), [ // row 1 - isset($_SESSION['EUID']) && is_numeric($_SESSION['EUID']) ? + '', + !empty($_SESSION['EUID']) && is_numeric($_SESSION['EUID']) ? $_SESSION['EUID'] : null, + !empty($_SESSION['ECUID']) && is_string($_SESSION['ECUID']) ? + $_SESSION['ECUID'] : null, + !empty($_SESSION['ECUUID']) && Uids::validateUuuidv4($_SESSION['ECUID']) ? + $_SESSION['ECUID'] : null, (string)$event, + '', $data_write, $data_binary, (string)$this->page_name, @@ -379,6 +408,7 @@ class Backend // row 4 $this->action ?? '', $this->action_id ?? '', + $this->action_sub_id ?? '', $this->action_yes ?? '', $this->action_flag ?? '', $this->action_menu ?? '',