diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 455d640..5fcc903 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -101,6 +101,7 @@ jobs: TEST_DB_HOST: ${{ env.TEST_DB_HOST }} # ... (include all relevant DB_ and TEST_DB_ vars) TEST_DB_URL: ${{ env.TEST_DB_URL }} # Ensure your script uses this + ENABLE_AUDIT_LOG: false # Disable audit log for tests - name: Run Unittests # CWD is ./src @@ -118,3 +119,4 @@ jobs: TEST_DB_PASSWORD: ${{ env.TEST_DB_PASSWORD }} TEST_DB_NAME: ${{ env.TEST_DB_NAME }} TEST_DB_URL: ${{ env.TEST_DB_URL }} + ENABLE_AUDIT_LOG: false # Disable audit log for tests diff --git a/src/backend/scripts/reset.py b/src/backend/scripts/reset.py index 69dbc78..5d63999 100644 --- a/src/backend/scripts/reset.py +++ b/src/backend/scripts/reset.py @@ -1,26 +1,29 @@ from .run_all_ddls import * -def reset_dev(): +def reset_dev(no_trigger=False): main( - sql_scripts_dir, + ddl_scripts_dir, create_engine(db_config.DB_URL), refresh=True, refresh_data=False, - no_ddl=False + no_ddl=False, + no_trigger=no_trigger ) -def reset_test(): +def reset_test(no_trigger=False): main( - sql_scripts_dir, + ddl_scripts_dir, create_engine(test_db_config.DB_URL), refresh=True, refresh_data=False, - no_ddl=False + no_ddl=False, + no_trigger=no_trigger ) if __name__ == "__main__": import argparse + import os parser = argparse.ArgumentParser(description="Reset the database.") parser.add_argument( @@ -29,11 +32,20 @@ def reset_test(): default="test", help="Specify the mode to run the DDL scripts. Default is 'test'." ) + parser.add_argument( + "--no-trigger", + action="store_true", + help="Skip running trigger scripts." + ) args = parser.parse_args() + ENABLE_AUDIT_LOG = os.getenv("ENABLE_AUDIT_LOG", "false").lower() == "true" + + no_trigger = args.no_trigger or not ENABLE_AUDIT_LOG + print(f"Resetting {args.target} database: drop all tables and rerun all DDLs.") if args.target == "dev": - reset_dev() + reset_dev(no_trigger=no_trigger) elif args.target == "test": - reset_test() + reset_test(no_trigger=no_trigger) diff --git a/src/backend/scripts/run_all_ddls.py b/src/backend/scripts/run_all_ddls.py index dbeb08a..4b22b78 100644 --- a/src/backend/scripts/run_all_ddls.py +++ b/src/backend/scripts/run_all_ddls.py @@ -9,17 +9,22 @@ root_dir = Path(__file__).parent.parent drop_all_script = root_dir / "sql" / "utils" / "drop_all.sql" drop_all_data_script = root_dir / "sql" / "utils" / "drop_all_data.sql" -sql_scripts_dir = root_dir / "sql" / "ddl" +ddl_scripts_dir = root_dir / "sql" / "ddl" +trigger_scripts_dir = root_dir / "sql" / "triggers" -def execute_sql_script(engine, script_text): +def execute_sql_script(engine, script_text, split_statements=True): """ Execute a SQL script using the provided SQLAlchemy engine. """ with engine.begin() as connection: # Execute the SQL script stmt by stmt - sql_statements = script_text.split(';') + if split_statements: + # Split the script into individual statements + sql_statements = script_text.split(";") + else: + sql_statements = [script_text] for statement in sql_statements: # Strip leading/trailing whitespace statement = statement.strip() @@ -27,19 +32,21 @@ def execute_sql_script(engine, script_text): if not statement: continue try: - connection.execute(text(statement)) + stmt = text(statement) + connection.execute(stmt) except Exception as e: logger.error(f"Error executing statement: {statement}") logger.error(f"{e}") - continue + logger.info(f"stmt: {stmt}") + raise e -def execute_sql_scripts_in_order(engine, directory): +def execute_sql_scripts_in_order(engine, directory, split_statements=True): """ Execute all SQL scripts in the specified directory in order. The scripts should be named in a way that allows them to be sorted correctly (e.g., 001_create_table.sql). """ # Get a list of all SQL files in the directory - logger.info(f"Running all SQL scripts in {sql_scripts_dir}...") + logger.info(f"Running all SQL scripts in {ddl_scripts_dir}...") # Get a list of all SQL files in the directory sql_files = sorted(directory.glob("*.sql")) logger.info(f"Found {len(sql_files)} SQL files.") @@ -48,20 +55,15 @@ def execute_sql_scripts_in_order(engine, directory): for sql_file in sql_files: logger.info(f"Running script: {sql_file.name}") # Read the SQL file - with open(sql_file, 'r') as file: + with open(sql_file, "r") as file: sql_script = file.read() # Execute the SQL script - execute_sql_script(engine, sql_script) - + execute_sql_script(engine, sql_script, split_statements=split_statements) def main( - directory: Path, - engine=None, - refresh=False, - refresh_data=False, - no_ddl=False + directory: Path, engine=None, refresh=False, refresh_data=False, no_ddl=False, no_trigger=False ): """ Run all DDL scripts in the specified directory in order. @@ -70,22 +72,25 @@ def main( """ if refresh: logger.info(f"Running drop_all.sql script...") - with open(drop_all_script, 'r') as file: + with open(drop_all_script, "r") as file: drop_script = file.read() execute_sql_script(engine, drop_script) if refresh_data: logger.info(f"Running drop_all_data.sql script...") - with open(drop_all_data_script, 'r') as file: + with open(drop_all_data_script, "r") as file: drop_data_script = file.read() execute_sql_script(engine, drop_data_script) if no_ddl: logger.info("Skipping DDL scripts execution as per --no-ddl flag.") - return - - execute_sql_scripts_in_order(engine, directory) + else: + execute_sql_scripts_in_order(engine, directory) + if no_trigger: + logger.info("Skipping trigger scripts execution as per --no-trigger flag.") + else: + execute_sql_scripts_in_order(engine, trigger_scripts_dir, split_statements=False) if __name__ == "__main__": @@ -94,26 +99,23 @@ def main( "--mode", choices=["dev", "test"], default="test", - help="Specify the mode to run the DDL scripts. Default is 'test'." + help="Specify the mode to run the DDL scripts. Default is 'test'.", ) parser.add_argument( "--refresh", "-r", action="store_true", - help="Drop all tables and before running the DDL scripts." + help="Drop all tables and before running the DDL scripts.", ) parser.add_argument( "--refresh-data", "-rd", action="store_true", - help="Drop all data in the tables (after refresh, before running the DDL scripts)." + help="Drop all data in the tables (after refresh, before running the DDL scripts).", ) + parser.add_argument("--no-ddl", action="store_true", help="Skip running DDL scripts.") + parser.add_argument("--no-trigger", action="store_true", help="Skip running trigger scripts.") - parser.add_argument( - "--no-ddl", - action="store_true", - help="Skip running DDL scripts." - ) args = parser.parse_args() logger.info(f"Running in {args.mode} mode.") @@ -124,4 +126,11 @@ def main( elif args.mode == "test": _engine = create_engine(test_db_config.DB_URL) - main(sql_scripts_dir, _engine, refresh=args.refresh, refresh_data=args.refresh_data, no_ddl=args.no_ddl) + main( + ddl_scripts_dir, + _engine, + refresh=args.refresh, + refresh_data=args.refresh_data, + no_ddl=args.no_ddl, + no_trigger=args.no_trigger, + ) diff --git a/src/backend/sql/ddl/014_create_audit_log_table.sql b/src/backend/sql/ddl/014_create_audit_log_table.sql new file mode 100644 index 0000000..79c1b27 --- /dev/null +++ b/src/backend/sql/ddl/014_create_audit_log_table.sql @@ -0,0 +1,18 @@ +-- ----------------------------------------------------- +-- Table `AuditLog` (审计日志) +-- ----------------------------------------------------- +CREATE TABLE IF NOT EXISTS `AuditLog` +( + `AuditLogID` BIGINT NOT NULL AUTO_INCREMENT COMMENT '审计日志ID,主键', + `TableName` VARCHAR(128) NOT NULL COMMENT '被操作的表名', + `RowPKValue` VARCHAR(255) NULL COMMENT '被操作行的主键值 (如果是复合主键,可以考虑用JSON或拼接)', + `OperationType` ENUM ('INSERT', 'UPDATE', 'DELETE') NOT NULL COMMENT '操作类型', + `ChangedByUserID` INT NULL COMMENT '执行操作的用户ID (通过会话变量 @actor_id 获取)', + `ChangeTimestamp` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '操作发生的时间戳', + `OldValues_JSON` JSON NULL COMMENT '操作前行的完整数据 (JSON格式)', + `NewValues_JSON` JSON NULL COMMENT '操作后行的完整数据 (JSON格式)', + PRIMARY KEY (`AuditLogID`), + INDEX `idx_AuditLog_TableName_RowPK` (`TableName` ASC, `RowPKValue` ASC), + INDEX `idx_AuditLog_ChangedByUserID` (`ChangedByUserID` ASC), + INDEX `idx_AuditLog_ChangeTimestamp` (`ChangeTimestamp` ASC) +) ENGINE = InnoDB COMMENT = '通用审计日志表,记录数据变更历史'; diff --git a/src/backend/sql/trigger/001_user_audit.sql b/src/backend/sql/trigger/001_user_audit.sql new file mode 100644 index 0000000..2d31f47 --- /dev/null +++ b/src/backend/sql/trigger/001_user_audit.sql @@ -0,0 +1,141 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on User table +-- ----------------------------------------------------- +SET GLOBAL log_bin_trust_function_creators = 1; + +DELIMITER // + +CREATE TRIGGER `trg_User_Audit_Insert` + AFTER INSERT + ON `User` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` (`TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON`) + VALUES ('User', + CAST(NEW.UserID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'UserID', NEW.UserID, + 'Username', NEW.Username, + 'PasswordHash', '[SENSITIVE_DATA_LOGGED]', -- 或 NEW.PasswordHash,但请注意安全风险 + 'Email', NEW.Email, + 'PhoneNumber', NEW.PhoneNumber, + 'UserRole', NEW.UserRole, + 'RegistrationDate', NEW.RegistrationDate, + 'LastLoginDate', NEW.LastLoginDate, + 'DefaultAddressID', NEW.DefaultAddressID, + 'AccountStatus', NEW.AccountStatus + )); +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on User table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_User_Audit_Update` + AFTER UPDATE + ON `User` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + -- 注意:PasswordHash 通常不应直接比较,但如果允许更新,则需要记录 + -- LastLoginDate 和 LastUpdatedDate (如果User表有) 通常是自动更新的, + -- 您可以决定是否因为这些时间戳的变化而触发审计日志。 + -- 这里我们假设如果任何受关注的列发生变化,就记录整行的新旧值。 + IF OLD.Username <=> NEW.Username OR + OLD.Email <=> NEW.Email OR + OLD.PhoneNumber <=> NEW.PhoneNumber OR + OLD.UserRole <=> NEW.UserRole OR + OLD.LastLoginDate <=> NEW.LastLoginDate OR -- 如果应用会更新它 + OLD.DefaultAddressID <=> NEW.DefaultAddressID OR + OLD.AccountStatus <=> NEW.AccountStatus OR + OLD.PasswordHash <=> NEW.PasswordHash -- 监控密码哈希变化 + THEN + INSERT INTO `AuditLog` (`TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON`) + VALUES ('User', + CAST(NEW.UserID AS CHAR), -- 主键通常不变,使用 NEW 或 OLD 都可以 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'UserID', OLD.UserID, + 'Username', OLD.Username, + 'PasswordHash', '[SENSITIVE_DATA_LOGGED]', -- 或 OLD.PasswordHash + 'Email', OLD.Email, + 'PhoneNumber', OLD.PhoneNumber, + 'UserRole', OLD.UserRole, + 'RegistrationDate', OLD.RegistrationDate, + 'LastLoginDate', OLD.LastLoginDate, + 'DefaultAddressID', OLD.DefaultAddressID, + 'AccountStatus', OLD.AccountStatus + ), + JSON_OBJECT( + 'UserID', NEW.UserID, + 'Username', NEW.Username, + 'PasswordHash', '[SENSITIVE_DATA_LOGGED]', -- 或 NEW.PasswordHash + 'Email', NEW.Email, + 'PhoneNumber', NEW.PhoneNumber, + 'UserRole', NEW.UserRole, + 'RegistrationDate', NEW.RegistrationDate, -- 创建日期通常不变 + 'LastLoginDate', NEW.LastLoginDate, + 'DefaultAddressID', NEW.DefaultAddressID, + 'AccountStatus', NEW.AccountStatus + )); + END IF; +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on User table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_User_Audit_Delete` + AFTER DELETE + ON `User` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` (`TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON`) + VALUES ('User', + CAST(OLD.UserID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'UserID', OLD.UserID, + 'Username', OLD.Username, + 'PasswordHash', '[SENSITIVE_DATA_LOGGED]', -- 或 OLD.PasswordHash + 'Email', OLD.Email, + 'PhoneNumber', OLD.PhoneNumber, + 'UserRole', OLD.UserRole, + 'RegistrationDate', OLD.RegistrationDate, + 'LastLoginDate', OLD.LastLoginDate, + 'DefaultAddressID', OLD.DefaultAddressID, + 'AccountStatus', OLD.AccountStatus + ), + NULL -- DELETE 操作没有新值 + ); +END// + +DELIMITER ; + +SET GLOBAL log_bin_trust_function_creators = 0; diff --git a/src/backend/sql/trigger/002_user_session_audit.sql b/src/backend/sql/trigger/002_user_session_audit.sql new file mode 100644 index 0000000..4d017ef --- /dev/null +++ b/src/backend/sql/trigger/002_user_session_audit.sql @@ -0,0 +1,131 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on UserSession table +-- ----------------------------------------------------- +SET GLOBAL log_bin_trust_function_creators = 1; + +DELIMITER // + +CREATE TRIGGER `trg_UserSession_Audit_Insert` + AFTER INSERT ON `UserSession` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'UserSession', + NEW.SessionToken, -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'SessionToken', NEW.SessionToken, + 'UserID', NEW.UserID, + 'CreatedAt', NEW.CreatedAt, + 'ExpiresAt', NEW.ExpiresAt, + 'LastAccessedAt', NEW.LastAccessedAt, + 'IPAddress', NEW.IPAddress, + 'UserAgent', NEW.UserAgent + ) + ); +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on UserSession table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_UserSession_Audit_Update` + AFTER UPDATE ON `UserSession` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + IF OLD.UserID <=> NEW.UserID OR + OLD.CreatedAt <=> NEW.CreatedAt OR + OLD.ExpiresAt <=> NEW.ExpiresAt OR + OLD.LastAccessedAt <=> NEW.LastAccessedAt OR + OLD.IPAddress <=> NEW.IPAddress OR + OLD.UserAgent <=> NEW.UserAgent + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'UserSession', + NEW.SessionToken, -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'SessionToken', OLD.SessionToken, + 'UserID', OLD.UserID, + 'CreatedAt', OLD.CreatedAt, + 'ExpiresAt', OLD.ExpiresAt, + 'LastAccessedAt', OLD.LastAccessedAt, + 'IPAddress', OLD.IPAddress, + 'UserAgent', OLD.UserAgent + ), + JSON_OBJECT( + 'SessionToken', NEW.SessionToken, + 'UserID', NEW.UserID, + 'CreatedAt', NEW.CreatedAt, + 'ExpiresAt', NEW.ExpiresAt, + 'LastAccessedAt', NEW.LastAccessedAt, + 'IPAddress', NEW.IPAddress, + 'UserAgent', NEW.UserAgent + ) + ); + END IF; +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on UserSession table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_UserSession_Audit_Delete` + AFTER DELETE ON `UserSession` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'UserSession', + OLD.SessionToken, + 'DELETE', + @actor_id, + JSON_OBJECT( + 'SessionToken', OLD.SessionToken, + 'UserID', OLD.UserID, + 'CreatedAt', OLD.CreatedAt, + 'ExpiresAt', OLD.ExpiresAt, + 'LastAccessedAt', OLD.LastAccessedAt, + 'IPAddress', OLD.IPAddress, + 'UserAgent', OLD.UserAgent + ), + NULL -- DELETE 操作没有新值 + ); +END// + +DELIMITER ; + +SET GLOBAL log_bin_trust_function_creators = 0; diff --git a/src/backend/sql/trigger/003_shipping_address_audit.sql b/src/backend/sql/trigger/003_shipping_address_audit.sql new file mode 100644 index 0000000..ca17dd3 --- /dev/null +++ b/src/backend/sql/trigger/003_shipping_address_audit.sql @@ -0,0 +1,126 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on ShippingAddress table +-- ----------------------------------------------------- +SET GLOBAL log_bin_trust_function_creators = 1; + +DELIMITER // + +CREATE TRIGGER `trg_ShippingAddress_Audit_Insert` + AFTER INSERT ON `ShippingAddress` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ShippingAddress', + CAST(NEW.AddressID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'AddressID', NEW.AddressID, + 'UserID', NEW.UserID, + 'RecipientName', NEW.RecipientName, + 'PhoneNumber', NEW.PhoneNumber, + 'FullAddress_Text', NEW.FullAddress_Text, + 'IsDefault', NEW.IsDefault + ) + ); +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on ShippingAddress table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_ShippingAddress_Audit_Update` + AFTER UPDATE ON `ShippingAddress` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + IF OLD.UserID <=> NEW.UserID OR + OLD.RecipientName <=> NEW.RecipientName OR + OLD.PhoneNumber <=> NEW.PhoneNumber OR + OLD.FullAddress_Text <=> NEW.FullAddress_Text OR + OLD.IsDefault <=> NEW.IsDefault + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ShippingAddress', + CAST(NEW.AddressID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'AddressID', OLD.AddressID, + 'UserID', OLD.UserID, + 'RecipientName', OLD.RecipientName, + 'PhoneNumber', OLD.PhoneNumber, + 'FullAddress_Text', OLD.FullAddress_Text, + 'IsDefault', OLD.IsDefault + ), + JSON_OBJECT( + 'AddressID', NEW.AddressID, + 'UserID', NEW.UserID, + 'RecipientName', NEW.RecipientName, + 'PhoneNumber', NEW.PhoneNumber, + 'FullAddress_Text', NEW.FullAddress_Text, + 'IsDefault', NEW.IsDefault + ) + ); + END IF; +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on ShippingAddress table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_ShippingAddress_Audit_Delete` + AFTER DELETE ON `ShippingAddress` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ShippingAddress', + CAST(OLD.AddressID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'AddressID', OLD.AddressID, + 'UserID', OLD.UserID, + 'RecipientName', OLD.RecipientName, + 'PhoneNumber', OLD.PhoneNumber, + 'FullAddress_Text', OLD.FullAddress_Text, + 'IsDefault', OLD.IsDefault + ), + NULL -- DELETE 操作没有新值 + ); +END// + +DELIMITER ; + +SET GLOBAL log_bin_trust_function_creators = 0; diff --git a/src/backend/sql/trigger/004_store_audit.sql b/src/backend/sql/trigger/004_store_audit.sql new file mode 100644 index 0000000..331249b --- /dev/null +++ b/src/backend/sql/trigger/004_store_audit.sql @@ -0,0 +1,135 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on Store table +-- ----------------------------------------------------- +SET GLOBAL log_bin_trust_function_creators = 1; + +DELIMITER // + +CREATE TRIGGER `trg_Store_Audit_Insert` + AFTER INSERT ON `Store` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Store', + CAST(NEW.StoreID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'StoreID', NEW.StoreID, + 'StoreName', NEW.StoreName, + 'OwnerUserID', NEW.OwnerUserID, + 'Description', NEW.Description, + 'LogoURL', NEW.LogoURL, + 'StoreStatus', NEW.StoreStatus, + 'CreationDate', NEW.CreationDate, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on Store table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_Store_Audit_Update` + AFTER UPDATE ON `Store` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + -- LastUpdatedDate 通常是自动更新的,可以决定是否因为这个时间戳的变化而触发审计日志 + IF OLD.StoreName <=> NEW.StoreName OR + OLD.OwnerUserID <=> NEW.OwnerUserID OR + OLD.Description <=> NEW.Description OR + OLD.LogoURL <=> NEW.LogoURL OR + OLD.StoreStatus <=> NEW.StoreStatus + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Store', + CAST(NEW.StoreID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'StoreID', OLD.StoreID, + 'StoreName', OLD.StoreName, + 'OwnerUserID', OLD.OwnerUserID, + 'Description', OLD.Description, + 'LogoURL', OLD.LogoURL, + 'StoreStatus', OLD.StoreStatus, + 'CreationDate', OLD.CreationDate, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + JSON_OBJECT( + 'StoreID', NEW.StoreID, + 'StoreName', NEW.StoreName, + 'OwnerUserID', NEW.OwnerUserID, + 'Description', NEW.Description, + 'LogoURL', NEW.LogoURL, + 'StoreStatus', NEW.StoreStatus, + 'CreationDate', NEW.CreationDate, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); + END IF; +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on Store table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_Store_Audit_Delete` + AFTER DELETE ON `Store` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Store', + CAST(OLD.StoreID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'StoreID', OLD.StoreID, + 'StoreName', OLD.StoreName, + 'OwnerUserID', OLD.OwnerUserID, + 'Description', OLD.Description, + 'LogoURL', OLD.LogoURL, + 'StoreStatus', OLD.StoreStatus, + 'CreationDate', OLD.CreationDate, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + NULL -- DELETE 操作没有新值 + ); +END// + +DELIMITER ; + +SET GLOBAL log_bin_trust_function_creators = 0; diff --git a/src/backend/sql/trigger/005_product_category_audit.sql b/src/backend/sql/trigger/005_product_category_audit.sql new file mode 100644 index 0000000..82abc70 --- /dev/null +++ b/src/backend/sql/trigger/005_product_category_audit.sql @@ -0,0 +1,116 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on ProductCategory table +-- ----------------------------------------------------- +SET GLOBAL log_bin_trust_function_creators = 1; + +DELIMITER // + +CREATE TRIGGER `trg_ProductCategory_Audit_Insert` + AFTER INSERT ON `ProductCategory` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductCategory', + CAST(NEW.CategoryID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'CategoryID', NEW.CategoryID, + 'CategoryName', NEW.CategoryName, + 'ParentCategoryID', NEW.ParentCategoryID, + 'CategoryDescription', NEW.CategoryDescription + ) + ); +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on ProductCategory table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_ProductCategory_Audit_Update` + AFTER UPDATE ON `ProductCategory` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + IF OLD.CategoryName <=> NEW.CategoryName OR + OLD.ParentCategoryID <=> NEW.ParentCategoryID OR + OLD.CategoryDescription <=> NEW.CategoryDescription + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductCategory', + CAST(NEW.CategoryID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'CategoryID', OLD.CategoryID, + 'CategoryName', OLD.CategoryName, + 'ParentCategoryID', OLD.ParentCategoryID, + 'CategoryDescription', OLD.CategoryDescription + ), + JSON_OBJECT( + 'CategoryID', NEW.CategoryID, + 'CategoryName', NEW.CategoryName, + 'ParentCategoryID', NEW.ParentCategoryID, + 'CategoryDescription', NEW.CategoryDescription + ) + ); + END IF; +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on ProductCategory table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_ProductCategory_Audit_Delete` + AFTER DELETE ON `ProductCategory` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductCategory', + CAST(OLD.CategoryID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'CategoryID', OLD.CategoryID, + 'CategoryName', OLD.CategoryName, + 'ParentCategoryID', OLD.ParentCategoryID, + 'CategoryDescription', OLD.CategoryDescription + ), + NULL -- DELETE 操作没有新值 + ); +END// + +DELIMITER ; + +SET GLOBAL log_bin_trust_function_creators = 0; diff --git a/src/backend/sql/trigger/006_product_audit.sql b/src/backend/sql/trigger/006_product_audit.sql new file mode 100644 index 0000000..922c666 --- /dev/null +++ b/src/backend/sql/trigger/006_product_audit.sql @@ -0,0 +1,150 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on Product table +-- ----------------------------------------------------- +SET GLOBAL log_bin_trust_function_creators = 1; + +DELIMITER // + +CREATE TRIGGER `trg_Product_Audit_Insert` + AFTER INSERT ON `Product` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Product', + CAST(NEW.ProductID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'ProductID', NEW.ProductID, + 'ProductName', NEW.ProductName, + 'ProductDescription', NEW.ProductDescription, + 'Price', NEW.Price, + 'ProductStatus', NEW.ProductStatus, + 'StoreID', NEW.StoreID, + 'CategoryID', NEW.CategoryID, + 'StockQuantity', NEW.StockQuantity, + 'MainImageURL', NEW.MainImageURL, + 'CreationDate', NEW.CreationDate, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on Product table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_Product_Audit_Update` + AFTER UPDATE ON `Product` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + -- LastUpdatedDate 通常是自动更新的,可以决定是否因为这个时间戳的变化而触发审计日志 + IF OLD.ProductName <=> NEW.ProductName OR + OLD.ProductDescription <=> NEW.ProductDescription OR + OLD.Price <=> NEW.Price OR + OLD.ProductStatus <=> NEW.ProductStatus OR + OLD.StoreID <=> NEW.StoreID OR + OLD.CategoryID <=> NEW.CategoryID OR + OLD.StockQuantity <=> NEW.StockQuantity OR + OLD.MainImageURL <=> NEW.MainImageURL + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Product', + CAST(NEW.ProductID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'ProductID', OLD.ProductID, + 'ProductName', OLD.ProductName, + 'ProductDescription', OLD.ProductDescription, + 'Price', OLD.Price, + 'ProductStatus', OLD.ProductStatus, + 'StoreID', OLD.StoreID, + 'CategoryID', OLD.CategoryID, + 'StockQuantity', OLD.StockQuantity, + 'MainImageURL', OLD.MainImageURL, + 'CreationDate', OLD.CreationDate, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + JSON_OBJECT( + 'ProductID', NEW.ProductID, + 'ProductName', NEW.ProductName, + 'ProductDescription', NEW.ProductDescription, + 'Price', NEW.Price, + 'ProductStatus', NEW.ProductStatus, + 'StoreID', NEW.StoreID, + 'CategoryID', NEW.CategoryID, + 'StockQuantity', NEW.StockQuantity, + 'MainImageURL', NEW.MainImageURL, + 'CreationDate', NEW.CreationDate, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); + END IF; +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on Product table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_Product_Audit_Delete` + AFTER DELETE ON `Product` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Product', + CAST(OLD.ProductID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'ProductID', OLD.ProductID, + 'ProductName', OLD.ProductName, + 'ProductDescription', OLD.ProductDescription, + 'Price', OLD.Price, + 'ProductStatus', OLD.ProductStatus, + 'StoreID', OLD.StoreID, + 'CategoryID', OLD.CategoryID, + 'StockQuantity', OLD.StockQuantity, + 'MainImageURL', OLD.MainImageURL, + 'CreationDate', OLD.CreationDate, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + NULL -- DELETE 操作没有新值 + ); +END// + +DELIMITER ; + +SET GLOBAL log_bin_trust_function_creators = 0; diff --git a/src/backend/sql/trigger/007_product_image_audit.sql b/src/backend/sql/trigger/007_product_image_audit.sql new file mode 100644 index 0000000..a520d62 --- /dev/null +++ b/src/backend/sql/trigger/007_product_image_audit.sql @@ -0,0 +1,125 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on ProductImage table +-- ----------------------------------------------------- +SET GLOBAL log_bin_trust_function_creators = 1; + +DELIMITER // + +CREATE TRIGGER `trg_ProductImage_Audit_Insert` + AFTER INSERT ON `ProductImage` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductImage', + CAST(NEW.ImageID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'ImageID', NEW.ImageID, + 'ProductID', NEW.ProductID, + 'ImageURL', NEW.ImageURL, + 'ImageType', NEW.ImageType, + 'SortOrder', NEW.SortOrder, + 'UploadDate', NEW.UploadDate + ) + ); +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on ProductImage table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_ProductImage_Audit_Update` + AFTER UPDATE ON `ProductImage` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + IF OLD.ProductID <=> NEW.ProductID OR + OLD.ImageURL <=> NEW.ImageURL OR + OLD.ImageType <=> NEW.ImageType OR + OLD.SortOrder <=> NEW.SortOrder + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductImage', + CAST(NEW.ImageID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'ImageID', OLD.ImageID, + 'ProductID', OLD.ProductID, + 'ImageURL', OLD.ImageURL, + 'ImageType', OLD.ImageType, + 'SortOrder', OLD.SortOrder, + 'UploadDate', OLD.UploadDate + ), + JSON_OBJECT( + 'ImageID', NEW.ImageID, + 'ProductID', NEW.ProductID, + 'ImageURL', NEW.ImageURL, + 'ImageType', NEW.ImageType, + 'SortOrder', NEW.SortOrder, + 'UploadDate', NEW.UploadDate + ) + ); + END IF; +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on ProductImage table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_ProductImage_Audit_Delete` + AFTER DELETE ON `ProductImage` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductImage', + CAST(OLD.ImageID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'ImageID', OLD.ImageID, + 'ProductID', OLD.ProductID, + 'ImageURL', OLD.ImageURL, + 'ImageType', OLD.ImageType, + 'SortOrder', OLD.SortOrder, + 'UploadDate', OLD.UploadDate + ), + NULL -- DELETE 操作没有新值 + ); +END// + +DELIMITER ; + +SET GLOBAL log_bin_trust_function_creators = 0; diff --git a/src/backend/sql/trigger/008_store_change_request_audit.sql b/src/backend/sql/trigger/008_store_change_request_audit.sql new file mode 100644 index 0000000..64cb1d8 --- /dev/null +++ b/src/backend/sql/trigger/008_store_change_request_audit.sql @@ -0,0 +1,155 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on StoreChangeRequest table +-- ----------------------------------------------------- +SET GLOBAL log_bin_trust_function_creators = 1; + +DELIMITER // + +CREATE TRIGGER `trg_StoreChangeRequest_Audit_Insert` + AFTER INSERT ON `StoreChangeRequest` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'StoreChangeRequest', + CAST(NEW.ChangeRequestID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'ChangeRequestID', NEW.ChangeRequestID, + 'StoreID', NEW.StoreID, + 'RequestingUserID', NEW.RequestingUserID, + 'RequestType', NEW.RequestType, + 'ProposedData_JSON', NEW.ProposedData_JSON, + 'Status', NEW.Status, + 'SubmitterNotes', NEW.SubmitterNotes, + 'AdminReviewerID', NEW.AdminReviewerID, + 'ReviewTimestamp', NEW.ReviewTimestamp, + 'AdminNotes', NEW.AdminNotes, + 'CreationTime', NEW.CreationTime, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on StoreChangeRequest table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_StoreChangeRequest_Audit_Update` + AFTER UPDATE ON `StoreChangeRequest` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + -- LastUpdatedDate 通常是自动更新的,可以决定是否因为这个时间戳的变化而触发审计日志 + IF OLD.StoreID <=> NEW.StoreID OR + OLD.RequestingUserID <=> NEW.RequestingUserID OR + OLD.RequestType <=> NEW.RequestType OR + OLD.ProposedData_JSON <=> NEW.ProposedData_JSON OR + OLD.Status <=> NEW.Status OR + OLD.SubmitterNotes <=> NEW.SubmitterNotes OR + OLD.AdminReviewerID <=> NEW.AdminReviewerID OR + OLD.ReviewTimestamp <=> NEW.ReviewTimestamp OR + OLD.AdminNotes <=> NEW.AdminNotes + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'StoreChangeRequest', + CAST(NEW.ChangeRequestID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'ChangeRequestID', OLD.ChangeRequestID, + 'StoreID', OLD.StoreID, + 'RequestingUserID', OLD.RequestingUserID, + 'RequestType', OLD.RequestType, + 'ProposedData_JSON', OLD.ProposedData_JSON, + 'Status', OLD.Status, + 'SubmitterNotes', OLD.SubmitterNotes, + 'AdminReviewerID', OLD.AdminReviewerID, + 'ReviewTimestamp', OLD.ReviewTimestamp, + 'AdminNotes', OLD.AdminNotes, + 'CreationTime', OLD.CreationTime, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + JSON_OBJECT( + 'ChangeRequestID', NEW.ChangeRequestID, + 'StoreID', NEW.StoreID, + 'RequestingUserID', NEW.RequestingUserID, + 'RequestType', NEW.RequestType, + 'ProposedData_JSON', NEW.ProposedData_JSON, + 'Status', NEW.Status, + 'SubmitterNotes', NEW.SubmitterNotes, + 'AdminReviewerID', NEW.AdminReviewerID, + 'ReviewTimestamp', NEW.ReviewTimestamp, + 'AdminNotes', NEW.AdminNotes, + 'CreationTime', NEW.CreationTime, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); + END IF; +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on StoreChangeRequest table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_StoreChangeRequest_Audit_Delete` + AFTER DELETE ON `StoreChangeRequest` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'StoreChangeRequest', + CAST(OLD.ChangeRequestID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'ChangeRequestID', OLD.ChangeRequestID, + 'StoreID', OLD.StoreID, + 'RequestingUserID', OLD.RequestingUserID, + 'RequestType', OLD.RequestType, + 'ProposedData_JSON', OLD.ProposedData_JSON, + 'Status', OLD.Status, + 'SubmitterNotes', OLD.SubmitterNotes, + 'AdminReviewerID', OLD.AdminReviewerID, + 'ReviewTimestamp', OLD.ReviewTimestamp, + 'AdminNotes', OLD.AdminNotes, + 'CreationTime', OLD.CreationTime, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + NULL -- DELETE 操作没有新值 + ); +END// + +DELIMITER ; + +SET GLOBAL log_bin_trust_function_creators = 0; diff --git a/src/backend/sql/trigger/009_product_change_request_audit.sql b/src/backend/sql/trigger/009_product_change_request_audit.sql new file mode 100644 index 0000000..90520db --- /dev/null +++ b/src/backend/sql/trigger/009_product_change_request_audit.sql @@ -0,0 +1,160 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on ProductChangeRequest table +-- ----------------------------------------------------- +SET GLOBAL log_bin_trust_function_creators = 1; + +DELIMITER // + +CREATE TRIGGER `trg_ProductChangeRequest_Audit_Insert` + AFTER INSERT ON `ProductChangeRequest` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductChangeRequest', + CAST(NEW.ChangeRequestID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'ChangeRequestID', NEW.ChangeRequestID, + 'ProductID', NEW.ProductID, + 'MerchantUserID', NEW.MerchantUserID, + 'StoreID', NEW.StoreID, + 'RequestType', NEW.RequestType, + 'ProposedData_JSON', NEW.ProposedData_JSON, + 'Status', NEW.Status, + 'SubmitterNotes', NEW.SubmitterNotes, + 'AdminReviewerID', NEW.AdminReviewerID, + 'ReviewTimestamp', NEW.ReviewTimestamp, + 'AdminNotes', NEW.AdminNotes, + 'CreationTime', NEW.CreationTime, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on ProductChangeRequest table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_ProductChangeRequest_Audit_Update` + AFTER UPDATE ON `ProductChangeRequest` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + -- LastUpdatedDate 通常是自动更新的,可以决定是否因为这个时间戳的变化而触发审计日志 + IF OLD.ProductID <=> NEW.ProductID OR + OLD.MerchantUserID <=> NEW.MerchantUserID OR + OLD.StoreID <=> NEW.StoreID OR + OLD.RequestType <=> NEW.RequestType OR + OLD.ProposedData_JSON <=> NEW.ProposedData_JSON OR + OLD.Status <=> NEW.Status OR + OLD.SubmitterNotes <=> NEW.SubmitterNotes OR + OLD.AdminReviewerID <=> NEW.AdminReviewerID OR + OLD.ReviewTimestamp <=> NEW.ReviewTimestamp OR + OLD.AdminNotes <=> NEW.AdminNotes + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductChangeRequest', + CAST(NEW.ChangeRequestID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'ChangeRequestID', OLD.ChangeRequestID, + 'ProductID', OLD.ProductID, + 'MerchantUserID', OLD.MerchantUserID, + 'StoreID', OLD.StoreID, + 'RequestType', OLD.RequestType, + 'ProposedData_JSON', OLD.ProposedData_JSON, + 'Status', OLD.Status, + 'SubmitterNotes', OLD.SubmitterNotes, + 'AdminReviewerID', OLD.AdminReviewerID, + 'ReviewTimestamp', OLD.ReviewTimestamp, + 'AdminNotes', OLD.AdminNotes, + 'CreationTime', OLD.CreationTime, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + JSON_OBJECT( + 'ChangeRequestID', NEW.ChangeRequestID, + 'ProductID', NEW.ProductID, + 'MerchantUserID', NEW.MerchantUserID, + 'StoreID', NEW.StoreID, + 'RequestType', NEW.RequestType, + 'ProposedData_JSON', NEW.ProposedData_JSON, + 'Status', NEW.Status, + 'SubmitterNotes', NEW.SubmitterNotes, + 'AdminReviewerID', NEW.AdminReviewerID, + 'ReviewTimestamp', NEW.ReviewTimestamp, + 'AdminNotes', NEW.AdminNotes, + 'CreationTime', NEW.CreationTime, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); + END IF; +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on ProductChangeRequest table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_ProductChangeRequest_Audit_Delete` + AFTER DELETE ON `ProductChangeRequest` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductChangeRequest', + CAST(OLD.ChangeRequestID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'ChangeRequestID', OLD.ChangeRequestID, + 'ProductID', OLD.ProductID, + 'MerchantUserID', OLD.MerchantUserID, + 'StoreID', OLD.StoreID, + 'RequestType', OLD.RequestType, + 'ProposedData_JSON', OLD.ProposedData_JSON, + 'Status', OLD.Status, + 'SubmitterNotes', OLD.SubmitterNotes, + 'AdminReviewerID', OLD.AdminReviewerID, + 'ReviewTimestamp', OLD.ReviewTimestamp, + 'AdminNotes', OLD.AdminNotes, + 'CreationTime', OLD.CreationTime, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + NULL -- DELETE 操作没有新值 + ); +END// + +DELIMITER ; + +SET GLOBAL log_bin_trust_function_creators = 0; diff --git a/src/backend/sql/trigger/010_cart_item_audit.sql b/src/backend/sql/trigger/010_cart_item_audit.sql new file mode 100644 index 0000000..d7816ca --- /dev/null +++ b/src/backend/sql/trigger/010_cart_item_audit.sql @@ -0,0 +1,125 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on CartItem table +-- ----------------------------------------------------- +SET GLOBAL log_bin_trust_function_creators = 1; + +DELIMITER // + +CREATE TRIGGER `trg_CartItem_Audit_Insert` + AFTER INSERT ON `CartItem` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'CartItem', + CAST(NEW.CartItemID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'CartItemID', NEW.CartItemID, + 'UserID', NEW.UserID, + 'ProductID', NEW.ProductID, + 'Quantity', NEW.Quantity, + 'PriceAtAddition', NEW.PriceAtAddition, + 'AddedDate', NEW.AddedDate + ) + ); +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on CartItem table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_CartItem_Audit_Update` + AFTER UPDATE ON `CartItem` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + IF OLD.UserID <=> NEW.UserID OR + OLD.ProductID <=> NEW.ProductID OR + OLD.Quantity <=> NEW.Quantity OR + OLD.PriceAtAddition <=> NEW.PriceAtAddition + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'CartItem', + CAST(NEW.CartItemID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'CartItemID', OLD.CartItemID, + 'UserID', OLD.UserID, + 'ProductID', OLD.ProductID, + 'Quantity', OLD.Quantity, + 'PriceAtAddition', OLD.PriceAtAddition, + 'AddedDate', OLD.AddedDate + ), + JSON_OBJECT( + 'CartItemID', NEW.CartItemID, + 'UserID', NEW.UserID, + 'ProductID', NEW.ProductID, + 'Quantity', NEW.Quantity, + 'PriceAtAddition', NEW.PriceAtAddition, + 'AddedDate', NEW.AddedDate + ) + ); + END IF; +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on CartItem table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_CartItem_Audit_Delete` + AFTER DELETE ON `CartItem` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'CartItem', + CAST(OLD.CartItemID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'CartItemID', OLD.CartItemID, + 'UserID', OLD.UserID, + 'ProductID', OLD.ProductID, + 'Quantity', OLD.Quantity, + 'PriceAtAddition', OLD.PriceAtAddition, + 'AddedDate', OLD.AddedDate + ), + NULL -- DELETE 操作没有新值 + ); +END// + +DELIMITER ; + +SET GLOBAL log_bin_trust_function_creators = 0; diff --git a/src/backend/sql/trigger/011_payment_transaction_audit.sql b/src/backend/sql/trigger/011_payment_transaction_audit.sql new file mode 100644 index 0000000..8c74875 --- /dev/null +++ b/src/backend/sql/trigger/011_payment_transaction_audit.sql @@ -0,0 +1,140 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on PaymentTransaction table +-- ----------------------------------------------------- +SET GLOBAL log_bin_trust_function_creators = 1; + +DELIMITER // + +CREATE TRIGGER `trg_PaymentTransaction_Audit_Insert` + AFTER INSERT ON `PaymentTransaction` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'PaymentTransaction', + CAST(NEW.PaymentTransactionID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'PaymentTransactionID', NEW.PaymentTransactionID, + 'UserID', NEW.UserID, + 'TotalAmount', NEW.TotalAmount, + 'PaymentMethod', NEW.PaymentMethod, + 'ExternalGatewayTransactionID', NEW.ExternalGatewayTransactionID, + 'Status', NEW.Status, + 'CreationTime', NEW.CreationTime, + 'CompletionTime', NEW.CompletionTime, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on PaymentTransaction table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_PaymentTransaction_Audit_Update` + AFTER UPDATE ON `PaymentTransaction` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + -- LastUpdatedDate 通常是自动更新的,可以决定是否因为这个时间戳的变化而触发审计日志 + IF OLD.UserID <=> NEW.UserID OR + OLD.TotalAmount <=> NEW.TotalAmount OR + OLD.PaymentMethod <=> NEW.PaymentMethod OR + OLD.ExternalGatewayTransactionID <=> NEW.ExternalGatewayTransactionID OR + OLD.Status <=> NEW.Status OR + OLD.CompletionTime <=> NEW.CompletionTime + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'PaymentTransaction', + CAST(NEW.PaymentTransactionID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'PaymentTransactionID', OLD.PaymentTransactionID, + 'UserID', OLD.UserID, + 'TotalAmount', OLD.TotalAmount, + 'PaymentMethod', OLD.PaymentMethod, + 'ExternalGatewayTransactionID', OLD.ExternalGatewayTransactionID, + 'Status', OLD.Status, + 'CreationTime', OLD.CreationTime, + 'CompletionTime', OLD.CompletionTime, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + JSON_OBJECT( + 'PaymentTransactionID', NEW.PaymentTransactionID, + 'UserID', NEW.UserID, + 'TotalAmount', NEW.TotalAmount, + 'PaymentMethod', NEW.PaymentMethod, + 'ExternalGatewayTransactionID', NEW.ExternalGatewayTransactionID, + 'Status', NEW.Status, + 'CreationTime', NEW.CreationTime, + 'CompletionTime', NEW.CompletionTime, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); + END IF; +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on PaymentTransaction table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_PaymentTransaction_Audit_Delete` + AFTER DELETE ON `PaymentTransaction` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'PaymentTransaction', + CAST(OLD.PaymentTransactionID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'PaymentTransactionID', OLD.PaymentTransactionID, + 'UserID', OLD.UserID, + 'TotalAmount', OLD.TotalAmount, + 'PaymentMethod', OLD.PaymentMethod, + 'ExternalGatewayTransactionID', OLD.ExternalGatewayTransactionID, + 'Status', OLD.Status, + 'CreationTime', OLD.CreationTime, + 'CompletionTime', OLD.CompletionTime, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + NULL -- DELETE 操作没有新值 + ); +END// + +DELIMITER ; + +SET GLOBAL log_bin_trust_function_creators = 0; diff --git a/src/backend/sql/trigger/012_order_audit.sql b/src/backend/sql/trigger/012_order_audit.sql new file mode 100644 index 0000000..d71e01a --- /dev/null +++ b/src/backend/sql/trigger/012_order_audit.sql @@ -0,0 +1,195 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on Order table +-- ----------------------------------------------------- +SET GLOBAL log_bin_trust_function_creators = 1; + +DELIMITER // + +CREATE TRIGGER `trg_Order_Audit_Insert` + AFTER INSERT ON `Order` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Order', + CAST(NEW.OrderID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'OrderID', NEW.OrderID, + 'UserID', NEW.UserID, + 'StoreID', NEW.StoreID, + 'PaymentTransactionID', NEW.PaymentTransactionID, + 'OrderStatus', NEW.OrderStatus, + 'OrderTotalAmount', NEW.OrderTotalAmount, + 'DiscountAmount', NEW.DiscountAmount, + 'ShippingFee', NEW.ShippingFee, + 'FinalAmountForThisOrder', NEW.FinalAmountForThisOrder, + 'ShippingAddress_RecipientName', NEW.ShippingAddress_RecipientName, + 'ShippingAddress_PhoneNumber', NEW.ShippingAddress_PhoneNumber, + 'ShippingAddress_Full', NEW.ShippingAddress_Full, + 'Notes_ByUser', NEW.Notes_ByUser, + 'Notes_ByMerchant', NEW.Notes_ByMerchant, + 'CreationTime', NEW.CreationTime, + 'PaymentConfirmationTime', NEW.PaymentConfirmationTime, + 'ShippingTime', NEW.ShippingTime, + 'DeliveryTime', NEW.DeliveryTime, + 'CompletionTime', NEW.CompletionTime, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on Order table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_Order_Audit_Update` + AFTER UPDATE ON `Order` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + -- LastUpdatedDate 通常是自动更新的,可以决定是否因为这个时间戳的变化而触发审计日志 + IF OLD.UserID <=> NEW.UserID OR + OLD.StoreID <=> NEW.StoreID OR + OLD.PaymentTransactionID <=> NEW.PaymentTransactionID OR + OLD.OrderStatus <=> NEW.OrderStatus OR + OLD.OrderTotalAmount <=> NEW.OrderTotalAmount OR + OLD.DiscountAmount <=> NEW.DiscountAmount OR + OLD.ShippingFee <=> NEW.ShippingFee OR + OLD.FinalAmountForThisOrder <=> NEW.FinalAmountForThisOrder OR + OLD.ShippingAddress_RecipientName <=> NEW.ShippingAddress_RecipientName OR + OLD.ShippingAddress_PhoneNumber <=> NEW.ShippingAddress_PhoneNumber OR + OLD.ShippingAddress_Full <=> NEW.ShippingAddress_Full OR + OLD.Notes_ByUser <=> NEW.Notes_ByUser OR + OLD.Notes_ByMerchant <=> NEW.Notes_ByMerchant OR + OLD.PaymentConfirmationTime <=> NEW.PaymentConfirmationTime OR + OLD.ShippingTime <=> NEW.ShippingTime OR + OLD.DeliveryTime <=> NEW.DeliveryTime OR + OLD.CompletionTime <=> NEW.CompletionTime + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Order', + CAST(NEW.OrderID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'OrderID', OLD.OrderID, + 'UserID', OLD.UserID, + 'StoreID', OLD.StoreID, + 'PaymentTransactionID', OLD.PaymentTransactionID, + 'OrderStatus', OLD.OrderStatus, + 'OrderTotalAmount', OLD.OrderTotalAmount, + 'DiscountAmount', OLD.DiscountAmount, + 'ShippingFee', OLD.ShippingFee, + 'FinalAmountForThisOrder', OLD.FinalAmountForThisOrder, + 'ShippingAddress_RecipientName', OLD.ShippingAddress_RecipientName, + 'ShippingAddress_PhoneNumber', OLD.ShippingAddress_PhoneNumber, + 'ShippingAddress_Full', OLD.ShippingAddress_Full, + 'Notes_ByUser', OLD.Notes_ByUser, + 'Notes_ByMerchant', OLD.Notes_ByMerchant, + 'CreationTime', OLD.CreationTime, + 'PaymentConfirmationTime', OLD.PaymentConfirmationTime, + 'ShippingTime', OLD.ShippingTime, + 'DeliveryTime', OLD.DeliveryTime, + 'CompletionTime', OLD.CompletionTime, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + JSON_OBJECT( + 'OrderID', NEW.OrderID, + 'UserID', NEW.UserID, + 'StoreID', NEW.StoreID, + 'PaymentTransactionID', NEW.PaymentTransactionID, + 'OrderStatus', NEW.OrderStatus, + 'OrderTotalAmount', NEW.OrderTotalAmount, + 'DiscountAmount', NEW.DiscountAmount, + 'ShippingFee', NEW.ShippingFee, + 'FinalAmountForThisOrder', NEW.FinalAmountForThisOrder, + 'ShippingAddress_RecipientName', NEW.ShippingAddress_RecipientName, + 'ShippingAddress_PhoneNumber', NEW.ShippingAddress_PhoneNumber, + 'ShippingAddress_Full', NEW.ShippingAddress_Full, + 'Notes_ByUser', NEW.Notes_ByUser, + 'Notes_ByMerchant', NEW.Notes_ByMerchant, + 'CreationTime', NEW.CreationTime, + 'PaymentConfirmationTime', NEW.PaymentConfirmationTime, + 'ShippingTime', NEW.ShippingTime, + 'DeliveryTime', NEW.DeliveryTime, + 'CompletionTime', NEW.CompletionTime, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); + END IF; +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on Order table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_Order_Audit_Delete` + AFTER DELETE ON `Order` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Order', + CAST(OLD.OrderID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'OrderID', OLD.OrderID, + 'UserID', OLD.UserID, + 'StoreID', OLD.StoreID, + 'PaymentTransactionID', OLD.PaymentTransactionID, + 'OrderStatus', OLD.OrderStatus, + 'OrderTotalAmount', OLD.OrderTotalAmount, + 'DiscountAmount', OLD.DiscountAmount, + 'ShippingFee', OLD.ShippingFee, + 'FinalAmountForThisOrder', OLD.FinalAmountForThisOrder, + 'ShippingAddress_RecipientName', OLD.ShippingAddress_RecipientName, + 'ShippingAddress_PhoneNumber', OLD.ShippingAddress_PhoneNumber, + 'ShippingAddress_Full', OLD.ShippingAddress_Full, + 'Notes_ByUser', OLD.Notes_ByUser, + 'Notes_ByMerchant', OLD.Notes_ByMerchant, + 'CreationTime', OLD.CreationTime, + 'PaymentConfirmationTime', OLD.PaymentConfirmationTime, + 'ShippingTime', OLD.ShippingTime, + 'DeliveryTime', OLD.DeliveryTime, + 'CompletionTime', OLD.CompletionTime, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + NULL -- DELETE 操作没有新值 + ); +END// + +DELIMITER ; + +SET GLOBAL log_bin_trust_function_creators = 0; diff --git a/src/backend/sql/trigger/013_order_item_audit.sql b/src/backend/sql/trigger/013_order_item_audit.sql new file mode 100644 index 0000000..057ec90 --- /dev/null +++ b/src/backend/sql/trigger/013_order_item_audit.sql @@ -0,0 +1,141 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on OrderItem table +-- ----------------------------------------------------- +SET GLOBAL log_bin_trust_function_creators = 1; + +DELIMITER // + +CREATE TRIGGER `trg_OrderItem_Audit_Insert` + AFTER INSERT ON `OrderItem` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'OrderItem', + CAST(NEW.OrderItemID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'OrderItemID', NEW.OrderItemID, + 'OrderID', NEW.OrderID, + 'ProductID', NEW.ProductID, + 'StoreID', NEW.StoreID, + 'Quantity', NEW.Quantity, + 'PriceAtPurchase', NEW.PriceAtPurchase, + 'ProductNameAtPurchase', NEW.ProductNameAtPurchase, + 'ProductImageURLAtPurchase', NEW.ProductImageURLAtPurchase, + 'Subtotal', NEW.Subtotal + ) + ); +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on OrderItem table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_OrderItem_Audit_Update` + AFTER UPDATE ON `OrderItem` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + IF OLD.OrderID <=> NEW.OrderID OR + OLD.ProductID <=> NEW.ProductID OR + OLD.StoreID <=> NEW.StoreID OR + OLD.Quantity <=> NEW.Quantity OR + OLD.PriceAtPurchase <=> NEW.PriceAtPurchase OR + OLD.ProductNameAtPurchase <=> NEW.ProductNameAtPurchase OR + OLD.ProductImageURLAtPurchase <=> NEW.ProductImageURLAtPurchase OR + OLD.Subtotal <=> NEW.Subtotal + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'OrderItem', + CAST(NEW.OrderItemID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'OrderItemID', OLD.OrderItemID, + 'OrderID', OLD.OrderID, + 'ProductID', OLD.ProductID, + 'StoreID', OLD.StoreID, + 'Quantity', OLD.Quantity, + 'PriceAtPurchase', OLD.PriceAtPurchase, + 'ProductNameAtPurchase', OLD.ProductNameAtPurchase, + 'ProductImageURLAtPurchase', OLD.ProductImageURLAtPurchase, + 'Subtotal', OLD.Subtotal + ), + JSON_OBJECT( + 'OrderItemID', NEW.OrderItemID, + 'OrderID', NEW.OrderID, + 'ProductID', NEW.ProductID, + 'StoreID', NEW.StoreID, + 'Quantity', NEW.Quantity, + 'PriceAtPurchase', NEW.PriceAtPurchase, + 'ProductNameAtPurchase', NEW.ProductNameAtPurchase, + 'ProductImageURLAtPurchase', NEW.ProductImageURLAtPurchase, + 'Subtotal', NEW.Subtotal + ) + ); + END IF; +END// + +DELIMITER ; + +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on OrderItem table +-- ----------------------------------------------------- +DELIMITER // + +CREATE TRIGGER `trg_OrderItem_Audit_Delete` + AFTER DELETE ON `OrderItem` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'OrderItem', + CAST(OLD.OrderItemID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'OrderItemID', OLD.OrderItemID, + 'OrderID', OLD.OrderID, + 'ProductID', OLD.ProductID, + 'StoreID', OLD.StoreID, + 'Quantity', OLD.Quantity, + 'PriceAtPurchase', OLD.PriceAtPurchase, + 'ProductNameAtPurchase', OLD.ProductNameAtPurchase, + 'ProductImageURLAtPurchase', OLD.ProductImageURLAtPurchase, + 'Subtotal', OLD.Subtotal + ), + NULL -- DELETE 操作没有新值 + ); +END// + +DELIMITER ; + +SET GLOBAL log_bin_trust_function_creators = 0; diff --git a/src/backend/sql/triggers/00001_set_system_var.sql b/src/backend/sql/triggers/00001_set_system_var.sql new file mode 100644 index 0000000..7cc1e79 --- /dev/null +++ b/src/backend/sql/triggers/00001_set_system_var.sql @@ -0,0 +1 @@ +SET GLOBAL log_bin_trust_function_creators = 1; diff --git a/src/backend/sql/triggers/00101_user_audit_insert.sql b/src/backend/sql/triggers/00101_user_audit_insert.sql new file mode 100644 index 0000000..d7e88bd --- /dev/null +++ b/src/backend/sql/triggers/00101_user_audit_insert.sql @@ -0,0 +1,32 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on User table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_User_Audit_Insert` + AFTER INSERT + ON `User` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` (`TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON`) + VALUES ('User', + CAST(NEW.UserID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'UserID', NEW.UserID, + 'Username', NEW.Username, + 'PasswordHash', '[SENSITIVE_DATA_LOGGED]', -- 或 NEW.PasswordHash,但请注意安全风险 + 'Email', NEW.Email, + 'PhoneNumber', NEW.PhoneNumber, + 'UserRole', NEW.UserRole, + 'RegistrationDate', NEW.RegistrationDate, + 'LastLoginDate', NEW.LastLoginDate, + 'DefaultAddressID', NEW.DefaultAddressID, + 'AccountStatus', NEW.AccountStatus + )); +END; diff --git a/src/backend/sql/triggers/00102_user_audit_update.sql b/src/backend/sql/triggers/00102_user_audit_update.sql new file mode 100644 index 0000000..7a9b03c --- /dev/null +++ b/src/backend/sql/triggers/00102_user_audit_update.sql @@ -0,0 +1,58 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on User table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_User_Audit_Update` + AFTER UPDATE + ON `User` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + -- 注意:PasswordHash 通常不应直接比较,但如果允许更新,则需要记录 + -- LastLoginDate 和 LastUpdatedDate (如果User表有) 通常是自动更新的, + -- 您可以决定是否因为这些时间戳的变化而触发审计日志。 + -- 这里我们假设如果任何受关注的列发生变化,就记录整行的新旧值。 + IF OLD.Username <=> NEW.Username OR + OLD.Email <=> NEW.Email OR + OLD.PhoneNumber <=> NEW.PhoneNumber OR + OLD.UserRole <=> NEW.UserRole OR + OLD.LastLoginDate <=> NEW.LastLoginDate OR -- 如果应用会更新它 + OLD.DefaultAddressID <=> NEW.DefaultAddressID OR + OLD.AccountStatus <=> NEW.AccountStatus OR + OLD.PasswordHash <=> NEW.PasswordHash -- 监控密码哈希变化 + THEN + INSERT INTO `AuditLog` (`TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON`) + VALUES ('User', + CAST(NEW.UserID AS CHAR), -- 主键通常不变,使用 NEW 或 OLD 都可以 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'UserID', OLD.UserID, + 'Username', OLD.Username, + 'PasswordHash', '[SENSITIVE_DATA_LOGGED]', -- 或 OLD.PasswordHash + 'Email', OLD.Email, + 'PhoneNumber', OLD.PhoneNumber, + 'UserRole', OLD.UserRole, + 'RegistrationDate', OLD.RegistrationDate, + 'LastLoginDate', OLD.LastLoginDate, + 'DefaultAddressID', OLD.DefaultAddressID, + 'AccountStatus', OLD.AccountStatus + ), + JSON_OBJECT( + 'UserID', NEW.UserID, + 'Username', NEW.Username, + 'PasswordHash', '[SENSITIVE_DATA_LOGGED]', -- 或 NEW.PasswordHash + 'Email', NEW.Email, + 'PhoneNumber', NEW.PhoneNumber, + 'UserRole', NEW.UserRole, + 'RegistrationDate', NEW.RegistrationDate, -- 创建日期通常不变 + 'LastLoginDate', NEW.LastLoginDate, + 'DefaultAddressID', NEW.DefaultAddressID, + 'AccountStatus', NEW.AccountStatus + )); + END IF; +END; diff --git a/src/backend/sql/triggers/00103_user_audit_delete.sql b/src/backend/sql/triggers/00103_user_audit_delete.sql new file mode 100644 index 0000000..6398d8f --- /dev/null +++ b/src/backend/sql/triggers/00103_user_audit_delete.sql @@ -0,0 +1,33 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on User table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_User_Audit_Delete` + AFTER DELETE + ON `User` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` (`TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON`) + VALUES ('User', + CAST(OLD.UserID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'UserID', OLD.UserID, + 'Username', OLD.Username, + 'PasswordHash', '[SENSITIVE_DATA_LOGGED]', -- 或 OLD.PasswordHash + 'Email', OLD.Email, + 'PhoneNumber', OLD.PhoneNumber, + 'UserRole', OLD.UserRole, + 'RegistrationDate', OLD.RegistrationDate, + 'LastLoginDate', OLD.LastLoginDate, + 'DefaultAddressID', OLD.DefaultAddressID, + 'AccountStatus', OLD.AccountStatus + ), + NULL -- DELETE 操作没有新值 + ); +END; diff --git a/src/backend/sql/triggers/00201_user_session_audit_insert.sql b/src/backend/sql/triggers/00201_user_session_audit_insert.sql new file mode 100644 index 0000000..95e88ed --- /dev/null +++ b/src/backend/sql/triggers/00201_user_session_audit_insert.sql @@ -0,0 +1,32 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on UserSession table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_UserSession_Audit_Insert` + AFTER INSERT ON `UserSession` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'UserSession', + NEW.SessionToken, -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'SessionToken', NEW.SessionToken, + 'UserID', NEW.UserID, + 'CreatedAt', NEW.CreatedAt, + 'ExpiresAt', NEW.ExpiresAt, + 'LastAccessedAt', NEW.LastAccessedAt, + 'IPAddress', NEW.IPAddress, + 'UserAgent', NEW.UserAgent + ) + ); +END; diff --git a/src/backend/sql/triggers/00202_user_session_audit_update.sql b/src/backend/sql/triggers/00202_user_session_audit_update.sql new file mode 100644 index 0000000..1000d82 --- /dev/null +++ b/src/backend/sql/triggers/00202_user_session_audit_update.sql @@ -0,0 +1,49 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on UserSession table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_UserSession_Audit_Update` + AFTER UPDATE ON `UserSession` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + IF OLD.UserID <=> NEW.UserID OR + OLD.CreatedAt <=> NEW.CreatedAt OR + OLD.ExpiresAt <=> NEW.ExpiresAt OR + OLD.LastAccessedAt <=> NEW.LastAccessedAt OR + OLD.IPAddress <=> NEW.IPAddress OR + OLD.UserAgent <=> NEW.UserAgent + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'UserSession', + NEW.SessionToken, -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'SessionToken', OLD.SessionToken, + 'UserID', OLD.UserID, + 'CreatedAt', OLD.CreatedAt, + 'ExpiresAt', OLD.ExpiresAt, + 'LastAccessedAt', OLD.LastAccessedAt, + 'IPAddress', OLD.IPAddress, + 'UserAgent', OLD.UserAgent + ), + JSON_OBJECT( + 'SessionToken', NEW.SessionToken, + 'UserID', NEW.UserID, + 'CreatedAt', NEW.CreatedAt, + 'ExpiresAt', NEW.ExpiresAt, + 'LastAccessedAt', NEW.LastAccessedAt, + 'IPAddress', NEW.IPAddress, + 'UserAgent', NEW.UserAgent + ) + ); + END IF; +END; diff --git a/src/backend/sql/triggers/00203_user_session_audit_delete.sql b/src/backend/sql/triggers/00203_user_session_audit_delete.sql new file mode 100644 index 0000000..3a9f965 --- /dev/null +++ b/src/backend/sql/triggers/00203_user_session_audit_delete.sql @@ -0,0 +1,32 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on UserSession table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_UserSession_Audit_Delete` + AFTER DELETE ON `UserSession` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'UserSession', + OLD.SessionToken, + 'DELETE', + @actor_id, + JSON_OBJECT( + 'SessionToken', OLD.SessionToken, + 'UserID', OLD.UserID, + 'CreatedAt', OLD.CreatedAt, + 'ExpiresAt', OLD.ExpiresAt, + 'LastAccessedAt', OLD.LastAccessedAt, + 'IPAddress', OLD.IPAddress, + 'UserAgent', OLD.UserAgent + ), + NULL -- DELETE 操作没有新值 + ); +END; diff --git a/src/backend/sql/triggers/00301_shipping_address_audit_insert.sql b/src/backend/sql/triggers/00301_shipping_address_audit_insert.sql new file mode 100644 index 0000000..51a819c --- /dev/null +++ b/src/backend/sql/triggers/00301_shipping_address_audit_insert.sql @@ -0,0 +1,31 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on ShippingAddress table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_ShippingAddress_Audit_Insert` + AFTER INSERT ON `ShippingAddress` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ShippingAddress', + CAST(NEW.AddressID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'AddressID', NEW.AddressID, + 'UserID', NEW.UserID, + 'RecipientName', NEW.RecipientName, + 'PhoneNumber', NEW.PhoneNumber, + 'FullAddress_Text', NEW.FullAddress_Text, + 'IsDefault', NEW.IsDefault + ) + ); +END; diff --git a/src/backend/sql/triggers/00302_shipping_address_audit_update.sql b/src/backend/sql/triggers/00302_shipping_address_audit_update.sql new file mode 100644 index 0000000..b44c7e1 --- /dev/null +++ b/src/backend/sql/triggers/00302_shipping_address_audit_update.sql @@ -0,0 +1,46 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on ShippingAddress table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_ShippingAddress_Audit_Update` + AFTER UPDATE ON `ShippingAddress` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + IF OLD.UserID <=> NEW.UserID OR + OLD.RecipientName <=> NEW.RecipientName OR + OLD.PhoneNumber <=> NEW.PhoneNumber OR + OLD.FullAddress_Text <=> NEW.FullAddress_Text OR + OLD.IsDefault <=> NEW.IsDefault + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ShippingAddress', + CAST(NEW.AddressID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'AddressID', OLD.AddressID, + 'UserID', OLD.UserID, + 'RecipientName', OLD.RecipientName, + 'PhoneNumber', OLD.PhoneNumber, + 'FullAddress_Text', OLD.FullAddress_Text, + 'IsDefault', OLD.IsDefault + ), + JSON_OBJECT( + 'AddressID', NEW.AddressID, + 'UserID', NEW.UserID, + 'RecipientName', NEW.RecipientName, + 'PhoneNumber', NEW.PhoneNumber, + 'FullAddress_Text', NEW.FullAddress_Text, + 'IsDefault', NEW.IsDefault + ) + ); + END IF; +END; diff --git a/src/backend/sql/triggers/00303_shipping_address_audit_delete.sql b/src/backend/sql/triggers/00303_shipping_address_audit_delete.sql new file mode 100644 index 0000000..3baf76b --- /dev/null +++ b/src/backend/sql/triggers/00303_shipping_address_audit_delete.sql @@ -0,0 +1,31 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on ShippingAddress table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_ShippingAddress_Audit_Delete` + AFTER DELETE ON `ShippingAddress` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ShippingAddress', + CAST(OLD.AddressID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'AddressID', OLD.AddressID, + 'UserID', OLD.UserID, + 'RecipientName', OLD.RecipientName, + 'PhoneNumber', OLD.PhoneNumber, + 'FullAddress_Text', OLD.FullAddress_Text, + 'IsDefault', OLD.IsDefault + ), + NULL -- DELETE 操作没有新值 + ); +END; diff --git a/src/backend/sql/triggers/00401_store_audit_insert.sql b/src/backend/sql/triggers/00401_store_audit_insert.sql new file mode 100644 index 0000000..78cb25c --- /dev/null +++ b/src/backend/sql/triggers/00401_store_audit_insert.sql @@ -0,0 +1,33 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on Store table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_Store_Audit_Insert` + AFTER INSERT ON `Store` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Store', + CAST(NEW.StoreID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'StoreID', NEW.StoreID, + 'StoreName', NEW.StoreName, + 'OwnerUserID', NEW.OwnerUserID, + 'Description', NEW.Description, + 'LogoURL', NEW.LogoURL, + 'StoreStatus', NEW.StoreStatus, + 'CreationDate', NEW.CreationDate, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); +END; diff --git a/src/backend/sql/triggers/00402_store_audit_update.sql b/src/backend/sql/triggers/00402_store_audit_update.sql new file mode 100644 index 0000000..7eda61e --- /dev/null +++ b/src/backend/sql/triggers/00402_store_audit_update.sql @@ -0,0 +1,51 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on Store table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_Store_Audit_Update` + AFTER UPDATE ON `Store` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + -- LastUpdatedDate 通常是自动更新的,可以决定是否因为这个时间戳的变化而触发审计日志 + IF OLD.StoreName <=> NEW.StoreName OR + OLD.OwnerUserID <=> NEW.OwnerUserID OR + OLD.Description <=> NEW.Description OR + OLD.LogoURL <=> NEW.LogoURL OR + OLD.StoreStatus <=> NEW.StoreStatus + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Store', + CAST(NEW.StoreID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'StoreID', OLD.StoreID, + 'StoreName', OLD.StoreName, + 'OwnerUserID', OLD.OwnerUserID, + 'Description', OLD.Description, + 'LogoURL', OLD.LogoURL, + 'StoreStatus', OLD.StoreStatus, + 'CreationDate', OLD.CreationDate, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + JSON_OBJECT( + 'StoreID', NEW.StoreID, + 'StoreName', NEW.StoreName, + 'OwnerUserID', NEW.OwnerUserID, + 'Description', NEW.Description, + 'LogoURL', NEW.LogoURL, + 'StoreStatus', NEW.StoreStatus, + 'CreationDate', NEW.CreationDate, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); + END IF; +END; diff --git a/src/backend/sql/triggers/00403_store_audit_delete.sql b/src/backend/sql/triggers/00403_store_audit_delete.sql new file mode 100644 index 0000000..390d1af --- /dev/null +++ b/src/backend/sql/triggers/00403_store_audit_delete.sql @@ -0,0 +1,33 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on Store table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_Store_Audit_Delete` + AFTER DELETE ON `Store` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Store', + CAST(OLD.StoreID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'StoreID', OLD.StoreID, + 'StoreName', OLD.StoreName, + 'OwnerUserID', OLD.OwnerUserID, + 'Description', OLD.Description, + 'LogoURL', OLD.LogoURL, + 'StoreStatus', OLD.StoreStatus, + 'CreationDate', OLD.CreationDate, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + NULL -- DELETE 操作没有新值 + ); +END; diff --git a/src/backend/sql/triggers/00501_product_category_audit_insert.sql b/src/backend/sql/triggers/00501_product_category_audit_insert.sql new file mode 100644 index 0000000..2de405b --- /dev/null +++ b/src/backend/sql/triggers/00501_product_category_audit_insert.sql @@ -0,0 +1,29 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on ProductCategory table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_ProductCategory_Audit_Insert` + AFTER INSERT ON `ProductCategory` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductCategory', + CAST(NEW.CategoryID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'CategoryID', NEW.CategoryID, + 'CategoryName', NEW.CategoryName, + 'ParentCategoryID', NEW.ParentCategoryID, + 'CategoryDescription', NEW.CategoryDescription + ) + ); +END; diff --git a/src/backend/sql/triggers/00502_product_category_audit_update.sql b/src/backend/sql/triggers/00502_product_category_audit_update.sql new file mode 100644 index 0000000..c8ba002 --- /dev/null +++ b/src/backend/sql/triggers/00502_product_category_audit_update.sql @@ -0,0 +1,40 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on ProductCategory table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_ProductCategory_Audit_Update` + AFTER UPDATE ON `ProductCategory` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + IF OLD.CategoryName <=> NEW.CategoryName OR + OLD.ParentCategoryID <=> NEW.ParentCategoryID OR + OLD.CategoryDescription <=> NEW.CategoryDescription + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductCategory', + CAST(NEW.CategoryID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'CategoryID', OLD.CategoryID, + 'CategoryName', OLD.CategoryName, + 'ParentCategoryID', OLD.ParentCategoryID, + 'CategoryDescription', OLD.CategoryDescription + ), + JSON_OBJECT( + 'CategoryID', NEW.CategoryID, + 'CategoryName', NEW.CategoryName, + 'ParentCategoryID', NEW.ParentCategoryID, + 'CategoryDescription', NEW.CategoryDescription + ) + ); + END IF; +END; diff --git a/src/backend/sql/triggers/00503_product_category_audit_delete.sql b/src/backend/sql/triggers/00503_product_category_audit_delete.sql new file mode 100644 index 0000000..ab5400b --- /dev/null +++ b/src/backend/sql/triggers/00503_product_category_audit_delete.sql @@ -0,0 +1,29 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on ProductCategory table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_ProductCategory_Audit_Delete` + AFTER DELETE ON `ProductCategory` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductCategory', + CAST(OLD.CategoryID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'CategoryID', OLD.CategoryID, + 'CategoryName', OLD.CategoryName, + 'ParentCategoryID', OLD.ParentCategoryID, + 'CategoryDescription', OLD.CategoryDescription + ), + NULL -- DELETE 操作没有新值 + ); +END; diff --git a/src/backend/sql/triggers/00601_product_audit_insert.sql b/src/backend/sql/triggers/00601_product_audit_insert.sql new file mode 100644 index 0000000..b140d54 --- /dev/null +++ b/src/backend/sql/triggers/00601_product_audit_insert.sql @@ -0,0 +1,36 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on Product table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_Product_Audit_Insert` + AFTER INSERT ON `Product` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Product', + CAST(NEW.ProductID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'ProductID', NEW.ProductID, + 'ProductName', NEW.ProductName, + 'ProductDescription', NEW.ProductDescription, + 'Price', NEW.Price, + 'ProductStatus', NEW.ProductStatus, + 'StoreID', NEW.StoreID, + 'CategoryID', NEW.CategoryID, + 'StockQuantity', NEW.StockQuantity, + 'MainImageURL', NEW.MainImageURL, + 'CreationDate', NEW.CreationDate, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); +END; diff --git a/src/backend/sql/triggers/00602_product_audit_update.sql b/src/backend/sql/triggers/00602_product_audit_update.sql new file mode 100644 index 0000000..cd92021 --- /dev/null +++ b/src/backend/sql/triggers/00602_product_audit_update.sql @@ -0,0 +1,60 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on Product table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_Product_Audit_Update` + AFTER UPDATE ON `Product` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + -- LastUpdatedDate 通常是自动更新的,可以决定是否因为这个时间戳的变化而触发审计日志 + IF OLD.ProductName <=> NEW.ProductName OR + OLD.ProductDescription <=> NEW.ProductDescription OR + OLD.Price <=> NEW.Price OR + OLD.ProductStatus <=> NEW.ProductStatus OR + OLD.StoreID <=> NEW.StoreID OR + OLD.CategoryID <=> NEW.CategoryID OR + OLD.StockQuantity <=> NEW.StockQuantity OR + OLD.MainImageURL <=> NEW.MainImageURL + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Product', + CAST(NEW.ProductID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'ProductID', OLD.ProductID, + 'ProductName', OLD.ProductName, + 'ProductDescription', OLD.ProductDescription, + 'Price', OLD.Price, + 'ProductStatus', OLD.ProductStatus, + 'StoreID', OLD.StoreID, + 'CategoryID', OLD.CategoryID, + 'StockQuantity', OLD.StockQuantity, + 'MainImageURL', OLD.MainImageURL, + 'CreationDate', OLD.CreationDate, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + JSON_OBJECT( + 'ProductID', NEW.ProductID, + 'ProductName', NEW.ProductName, + 'ProductDescription', NEW.ProductDescription, + 'Price', NEW.Price, + 'ProductStatus', NEW.ProductStatus, + 'StoreID', NEW.StoreID, + 'CategoryID', NEW.CategoryID, + 'StockQuantity', NEW.StockQuantity, + 'MainImageURL', NEW.MainImageURL, + 'CreationDate', NEW.CreationDate, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); + END IF; +END; diff --git a/src/backend/sql/triggers/00603_product_audit_delete.sql b/src/backend/sql/triggers/00603_product_audit_delete.sql new file mode 100644 index 0000000..38b6f4d --- /dev/null +++ b/src/backend/sql/triggers/00603_product_audit_delete.sql @@ -0,0 +1,36 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on Product table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_Product_Audit_Delete` + AFTER DELETE ON `Product` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Product', + CAST(OLD.ProductID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'ProductID', OLD.ProductID, + 'ProductName', OLD.ProductName, + 'ProductDescription', OLD.ProductDescription, + 'Price', OLD.Price, + 'ProductStatus', OLD.ProductStatus, + 'StoreID', OLD.StoreID, + 'CategoryID', OLD.CategoryID, + 'StockQuantity', OLD.StockQuantity, + 'MainImageURL', OLD.MainImageURL, + 'CreationDate', OLD.CreationDate, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + NULL -- DELETE 操作没有新值 + ); +END; diff --git a/src/backend/sql/triggers/00701_product_image_audit_insert.sql b/src/backend/sql/triggers/00701_product_image_audit_insert.sql new file mode 100644 index 0000000..a720fd6 --- /dev/null +++ b/src/backend/sql/triggers/00701_product_image_audit_insert.sql @@ -0,0 +1,31 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on ProductImage table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_ProductImage_Audit_Insert` + AFTER INSERT ON `ProductImage` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductImage', + CAST(NEW.ImageID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'ImageID', NEW.ImageID, + 'ProductID', NEW.ProductID, + 'ImageURL', NEW.ImageURL, + 'ImageType', NEW.ImageType, + 'SortOrder', NEW.SortOrder, + 'UploadDate', NEW.UploadDate + ) + ); +END; diff --git a/src/backend/sql/triggers/00702_product_image_audit_update.sql b/src/backend/sql/triggers/00702_product_image_audit_update.sql new file mode 100644 index 0000000..b84a3b5 --- /dev/null +++ b/src/backend/sql/triggers/00702_product_image_audit_update.sql @@ -0,0 +1,45 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on ProductImage table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_ProductImage_Audit_Update` + AFTER UPDATE ON `ProductImage` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + IF OLD.ProductID <=> NEW.ProductID OR + OLD.ImageURL <=> NEW.ImageURL OR + OLD.ImageType <=> NEW.ImageType OR + OLD.SortOrder <=> NEW.SortOrder + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductImage', + CAST(NEW.ImageID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'ImageID', OLD.ImageID, + 'ProductID', OLD.ProductID, + 'ImageURL', OLD.ImageURL, + 'ImageType', OLD.ImageType, + 'SortOrder', OLD.SortOrder, + 'UploadDate', OLD.UploadDate + ), + JSON_OBJECT( + 'ImageID', NEW.ImageID, + 'ProductID', NEW.ProductID, + 'ImageURL', NEW.ImageURL, + 'ImageType', NEW.ImageType, + 'SortOrder', NEW.SortOrder, + 'UploadDate', NEW.UploadDate + ) + ); + END IF; +END; diff --git a/src/backend/sql/triggers/00703_product_image_audit_delete.sql b/src/backend/sql/triggers/00703_product_image_audit_delete.sql new file mode 100644 index 0000000..046117f --- /dev/null +++ b/src/backend/sql/triggers/00703_product_image_audit_delete.sql @@ -0,0 +1,31 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on ProductImage table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_ProductImage_Audit_Delete` + AFTER DELETE ON `ProductImage` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductImage', + CAST(OLD.ImageID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'ImageID', OLD.ImageID, + 'ProductID', OLD.ProductID, + 'ImageURL', OLD.ImageURL, + 'ImageType', OLD.ImageType, + 'SortOrder', OLD.SortOrder, + 'UploadDate', OLD.UploadDate + ), + NULL -- DELETE 操作没有新值 + ); +END; diff --git a/src/backend/sql/triggers/00801_store_change_request_audit_insert.sql b/src/backend/sql/triggers/00801_store_change_request_audit_insert.sql new file mode 100644 index 0000000..f210513 --- /dev/null +++ b/src/backend/sql/triggers/00801_store_change_request_audit_insert.sql @@ -0,0 +1,37 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on StoreChangeRequest table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_StoreChangeRequest_Audit_Insert` + AFTER INSERT ON `StoreChangeRequest` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'StoreChangeRequest', + CAST(NEW.ChangeRequestID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'ChangeRequestID', NEW.ChangeRequestID, + 'StoreID', NEW.StoreID, + 'RequestingUserID', NEW.RequestingUserID, + 'RequestType', NEW.RequestType, + 'ProposedData_JSON', NEW.ProposedData_JSON, + 'Status', NEW.Status, + 'SubmitterNotes', NEW.SubmitterNotes, + 'AdminReviewerID', NEW.AdminReviewerID, + 'ReviewTimestamp', NEW.ReviewTimestamp, + 'AdminNotes', NEW.AdminNotes, + 'CreationTime', NEW.CreationTime, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); +END; diff --git a/src/backend/sql/triggers/00802_store_change_request_audit_update.sql b/src/backend/sql/triggers/00802_store_change_request_audit_update.sql new file mode 100644 index 0000000..af50e5d --- /dev/null +++ b/src/backend/sql/triggers/00802_store_change_request_audit_update.sql @@ -0,0 +1,63 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on StoreChangeRequest table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_StoreChangeRequest_Audit_Update` + AFTER UPDATE ON `StoreChangeRequest` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + -- LastUpdatedDate 通常是自动更新的,可以决定是否因为这个时间戳的变化而触发审计日志 + IF OLD.StoreID <=> NEW.StoreID OR + OLD.RequestingUserID <=> NEW.RequestingUserID OR + OLD.RequestType <=> NEW.RequestType OR + OLD.ProposedData_JSON <=> NEW.ProposedData_JSON OR + OLD.Status <=> NEW.Status OR + OLD.SubmitterNotes <=> NEW.SubmitterNotes OR + OLD.AdminReviewerID <=> NEW.AdminReviewerID OR + OLD.ReviewTimestamp <=> NEW.ReviewTimestamp OR + OLD.AdminNotes <=> NEW.AdminNotes + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'StoreChangeRequest', + CAST(NEW.ChangeRequestID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'ChangeRequestID', OLD.ChangeRequestID, + 'StoreID', OLD.StoreID, + 'RequestingUserID', OLD.RequestingUserID, + 'RequestType', OLD.RequestType, + 'ProposedData_JSON', OLD.ProposedData_JSON, + 'Status', OLD.Status, + 'SubmitterNotes', OLD.SubmitterNotes, + 'AdminReviewerID', OLD.AdminReviewerID, + 'ReviewTimestamp', OLD.ReviewTimestamp, + 'AdminNotes', OLD.AdminNotes, + 'CreationTime', OLD.CreationTime, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + JSON_OBJECT( + 'ChangeRequestID', NEW.ChangeRequestID, + 'StoreID', NEW.StoreID, + 'RequestingUserID', NEW.RequestingUserID, + 'RequestType', NEW.RequestType, + 'ProposedData_JSON', NEW.ProposedData_JSON, + 'Status', NEW.Status, + 'SubmitterNotes', NEW.SubmitterNotes, + 'AdminReviewerID', NEW.AdminReviewerID, + 'ReviewTimestamp', NEW.ReviewTimestamp, + 'AdminNotes', NEW.AdminNotes, + 'CreationTime', NEW.CreationTime, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); + END IF; +END; diff --git a/src/backend/sql/triggers/00803_store_change_request_audit_delete.sql b/src/backend/sql/triggers/00803_store_change_request_audit_delete.sql new file mode 100644 index 0000000..aa68d8b --- /dev/null +++ b/src/backend/sql/triggers/00803_store_change_request_audit_delete.sql @@ -0,0 +1,37 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on StoreChangeRequest table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_StoreChangeRequest_Audit_Delete` + AFTER DELETE ON `StoreChangeRequest` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'StoreChangeRequest', + CAST(OLD.ChangeRequestID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'ChangeRequestID', OLD.ChangeRequestID, + 'StoreID', OLD.StoreID, + 'RequestingUserID', OLD.RequestingUserID, + 'RequestType', OLD.RequestType, + 'ProposedData_JSON', OLD.ProposedData_JSON, + 'Status', OLD.Status, + 'SubmitterNotes', OLD.SubmitterNotes, + 'AdminReviewerID', OLD.AdminReviewerID, + 'ReviewTimestamp', OLD.ReviewTimestamp, + 'AdminNotes', OLD.AdminNotes, + 'CreationTime', OLD.CreationTime, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + NULL -- DELETE 操作没有新值 + ); +END; diff --git a/src/backend/sql/triggers/00901_product_change_request_audit_insert.sql b/src/backend/sql/triggers/00901_product_change_request_audit_insert.sql new file mode 100644 index 0000000..52b99b4 --- /dev/null +++ b/src/backend/sql/triggers/00901_product_change_request_audit_insert.sql @@ -0,0 +1,38 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on ProductChangeRequest table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_ProductChangeRequest_Audit_Insert` + AFTER INSERT ON `ProductChangeRequest` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductChangeRequest', + CAST(NEW.ChangeRequestID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'ChangeRequestID', NEW.ChangeRequestID, + 'ProductID', NEW.ProductID, + 'MerchantUserID', NEW.MerchantUserID, + 'StoreID', NEW.StoreID, + 'RequestType', NEW.RequestType, + 'ProposedData_JSON', NEW.ProposedData_JSON, + 'Status', NEW.Status, + 'SubmitterNotes', NEW.SubmitterNotes, + 'AdminReviewerID', NEW.AdminReviewerID, + 'ReviewTimestamp', NEW.ReviewTimestamp, + 'AdminNotes', NEW.AdminNotes, + 'CreationTime', NEW.CreationTime, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); +END; diff --git a/src/backend/sql/triggers/00902_product_change_request_audit_update.sql b/src/backend/sql/triggers/00902_product_change_request_audit_update.sql new file mode 100644 index 0000000..b44494a --- /dev/null +++ b/src/backend/sql/triggers/00902_product_change_request_audit_update.sql @@ -0,0 +1,66 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on ProductChangeRequest table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_ProductChangeRequest_Audit_Update` + AFTER UPDATE ON `ProductChangeRequest` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + -- LastUpdatedDate 通常是自动更新的,可以决定是否因为这个时间戳的变化而触发审计日志 + IF OLD.ProductID <=> NEW.ProductID OR + OLD.MerchantUserID <=> NEW.MerchantUserID OR + OLD.StoreID <=> NEW.StoreID OR + OLD.RequestType <=> NEW.RequestType OR + OLD.ProposedData_JSON <=> NEW.ProposedData_JSON OR + OLD.Status <=> NEW.Status OR + OLD.SubmitterNotes <=> NEW.SubmitterNotes OR + OLD.AdminReviewerID <=> NEW.AdminReviewerID OR + OLD.ReviewTimestamp <=> NEW.ReviewTimestamp OR + OLD.AdminNotes <=> NEW.AdminNotes + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductChangeRequest', + CAST(NEW.ChangeRequestID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'ChangeRequestID', OLD.ChangeRequestID, + 'ProductID', OLD.ProductID, + 'MerchantUserID', OLD.MerchantUserID, + 'StoreID', OLD.StoreID, + 'RequestType', OLD.RequestType, + 'ProposedData_JSON', OLD.ProposedData_JSON, + 'Status', OLD.Status, + 'SubmitterNotes', OLD.SubmitterNotes, + 'AdminReviewerID', OLD.AdminReviewerID, + 'ReviewTimestamp', OLD.ReviewTimestamp, + 'AdminNotes', OLD.AdminNotes, + 'CreationTime', OLD.CreationTime, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + JSON_OBJECT( + 'ChangeRequestID', NEW.ChangeRequestID, + 'ProductID', NEW.ProductID, + 'MerchantUserID', NEW.MerchantUserID, + 'StoreID', NEW.StoreID, + 'RequestType', NEW.RequestType, + 'ProposedData_JSON', NEW.ProposedData_JSON, + 'Status', NEW.Status, + 'SubmitterNotes', NEW.SubmitterNotes, + 'AdminReviewerID', NEW.AdminReviewerID, + 'ReviewTimestamp', NEW.ReviewTimestamp, + 'AdminNotes', NEW.AdminNotes, + 'CreationTime', NEW.CreationTime, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); + END IF; +END; diff --git a/src/backend/sql/triggers/00903_product_change_request_audit_delete.sql b/src/backend/sql/triggers/00903_product_change_request_audit_delete.sql new file mode 100644 index 0000000..cb72a89 --- /dev/null +++ b/src/backend/sql/triggers/00903_product_change_request_audit_delete.sql @@ -0,0 +1,38 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on ProductChangeRequest table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_ProductChangeRequest_Audit_Delete` + AFTER DELETE ON `ProductChangeRequest` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'ProductChangeRequest', + CAST(OLD.ChangeRequestID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'ChangeRequestID', OLD.ChangeRequestID, + 'ProductID', OLD.ProductID, + 'MerchantUserID', OLD.MerchantUserID, + 'StoreID', OLD.StoreID, + 'RequestType', OLD.RequestType, + 'ProposedData_JSON', OLD.ProposedData_JSON, + 'Status', OLD.Status, + 'SubmitterNotes', OLD.SubmitterNotes, + 'AdminReviewerID', OLD.AdminReviewerID, + 'ReviewTimestamp', OLD.ReviewTimestamp, + 'AdminNotes', OLD.AdminNotes, + 'CreationTime', OLD.CreationTime, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + NULL -- DELETE 操作没有新值 + ); +END; diff --git a/src/backend/sql/triggers/01001_cart_item_audit_insert.sql b/src/backend/sql/triggers/01001_cart_item_audit_insert.sql new file mode 100644 index 0000000..35b7b1e --- /dev/null +++ b/src/backend/sql/triggers/01001_cart_item_audit_insert.sql @@ -0,0 +1,31 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on CartItem table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_CartItem_Audit_Insert` + AFTER INSERT ON `CartItem` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'CartItem', + CAST(NEW.CartItemID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'CartItemID', NEW.CartItemID, + 'UserID', NEW.UserID, + 'ProductID', NEW.ProductID, + 'Quantity', NEW.Quantity, + 'PriceAtAddition', NEW.PriceAtAddition, + 'AddedDate', NEW.AddedDate + ) + ); +END; diff --git a/src/backend/sql/triggers/01002_cart_item_audit_update.sql b/src/backend/sql/triggers/01002_cart_item_audit_update.sql new file mode 100644 index 0000000..3bc3424 --- /dev/null +++ b/src/backend/sql/triggers/01002_cart_item_audit_update.sql @@ -0,0 +1,45 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on CartItem table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_CartItem_Audit_Update` + AFTER UPDATE ON `CartItem` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + IF OLD.UserID <=> NEW.UserID OR + OLD.ProductID <=> NEW.ProductID OR + OLD.Quantity <=> NEW.Quantity OR + OLD.PriceAtAddition <=> NEW.PriceAtAddition + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'CartItem', + CAST(NEW.CartItemID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'CartItemID', OLD.CartItemID, + 'UserID', OLD.UserID, + 'ProductID', OLD.ProductID, + 'Quantity', OLD.Quantity, + 'PriceAtAddition', OLD.PriceAtAddition, + 'AddedDate', OLD.AddedDate + ), + JSON_OBJECT( + 'CartItemID', NEW.CartItemID, + 'UserID', NEW.UserID, + 'ProductID', NEW.ProductID, + 'Quantity', NEW.Quantity, + 'PriceAtAddition', NEW.PriceAtAddition, + 'AddedDate', NEW.AddedDate + ) + ); + END IF; +END; diff --git a/src/backend/sql/triggers/01003_cart_item_audit_delete.sql b/src/backend/sql/triggers/01003_cart_item_audit_delete.sql new file mode 100644 index 0000000..f340360 --- /dev/null +++ b/src/backend/sql/triggers/01003_cart_item_audit_delete.sql @@ -0,0 +1,31 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on CartItem table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_CartItem_Audit_Delete` + AFTER DELETE ON `CartItem` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'CartItem', + CAST(OLD.CartItemID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'CartItemID', OLD.CartItemID, + 'UserID', OLD.UserID, + 'ProductID', OLD.ProductID, + 'Quantity', OLD.Quantity, + 'PriceAtAddition', OLD.PriceAtAddition, + 'AddedDate', OLD.AddedDate + ), + NULL -- DELETE 操作没有新值 + ); +END; diff --git a/src/backend/sql/triggers/01101_payment_transaction_audit_insert.sql b/src/backend/sql/triggers/01101_payment_transaction_audit_insert.sql new file mode 100644 index 0000000..6547b28 --- /dev/null +++ b/src/backend/sql/triggers/01101_payment_transaction_audit_insert.sql @@ -0,0 +1,34 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on PaymentTransaction table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_PaymentTransaction_Audit_Insert` + AFTER INSERT ON `PaymentTransaction` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'PaymentTransaction', + CAST(NEW.PaymentTransactionID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'PaymentTransactionID', NEW.PaymentTransactionID, + 'UserID', NEW.UserID, + 'TotalAmount', NEW.TotalAmount, + 'PaymentMethod', NEW.PaymentMethod, + 'ExternalGatewayTransactionID', NEW.ExternalGatewayTransactionID, + 'Status', NEW.Status, + 'CreationTime', NEW.CreationTime, + 'CompletionTime', NEW.CompletionTime, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); +END; diff --git a/src/backend/sql/triggers/01102_payment_transaction_audit_update.sql b/src/backend/sql/triggers/01102_payment_transaction_audit_update.sql new file mode 100644 index 0000000..3fcfafd --- /dev/null +++ b/src/backend/sql/triggers/01102_payment_transaction_audit_update.sql @@ -0,0 +1,54 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on PaymentTransaction table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_PaymentTransaction_Audit_Update` + AFTER UPDATE ON `PaymentTransaction` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + -- LastUpdatedDate 通常是自动更新的,可以决定是否因为这个时间戳的变化而触发审计日志 + IF OLD.UserID <=> NEW.UserID OR + OLD.TotalAmount <=> NEW.TotalAmount OR + OLD.PaymentMethod <=> NEW.PaymentMethod OR + OLD.ExternalGatewayTransactionID <=> NEW.ExternalGatewayTransactionID OR + OLD.Status <=> NEW.Status OR + OLD.CompletionTime <=> NEW.CompletionTime + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'PaymentTransaction', + CAST(NEW.PaymentTransactionID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'PaymentTransactionID', OLD.PaymentTransactionID, + 'UserID', OLD.UserID, + 'TotalAmount', OLD.TotalAmount, + 'PaymentMethod', OLD.PaymentMethod, + 'ExternalGatewayTransactionID', OLD.ExternalGatewayTransactionID, + 'Status', OLD.Status, + 'CreationTime', OLD.CreationTime, + 'CompletionTime', OLD.CompletionTime, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + JSON_OBJECT( + 'PaymentTransactionID', NEW.PaymentTransactionID, + 'UserID', NEW.UserID, + 'TotalAmount', NEW.TotalAmount, + 'PaymentMethod', NEW.PaymentMethod, + 'ExternalGatewayTransactionID', NEW.ExternalGatewayTransactionID, + 'Status', NEW.Status, + 'CreationTime', NEW.CreationTime, + 'CompletionTime', NEW.CompletionTime, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); + END IF; +END; diff --git a/src/backend/sql/triggers/01103_payment_transaction_audit_delete.sql b/src/backend/sql/triggers/01103_payment_transaction_audit_delete.sql new file mode 100644 index 0000000..a4de00f --- /dev/null +++ b/src/backend/sql/triggers/01103_payment_transaction_audit_delete.sql @@ -0,0 +1,34 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on PaymentTransaction table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_PaymentTransaction_Audit_Delete` + AFTER DELETE ON `PaymentTransaction` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'PaymentTransaction', + CAST(OLD.PaymentTransactionID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'PaymentTransactionID', OLD.PaymentTransactionID, + 'UserID', OLD.UserID, + 'TotalAmount', OLD.TotalAmount, + 'PaymentMethod', OLD.PaymentMethod, + 'ExternalGatewayTransactionID', OLD.ExternalGatewayTransactionID, + 'Status', OLD.Status, + 'CreationTime', OLD.CreationTime, + 'CompletionTime', OLD.CompletionTime, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + NULL -- DELETE 操作没有新值 + ); +END; diff --git a/src/backend/sql/triggers/01201_order_audit_insert.sql b/src/backend/sql/triggers/01201_order_audit_insert.sql new file mode 100644 index 0000000..54ba3ba --- /dev/null +++ b/src/backend/sql/triggers/01201_order_audit_insert.sql @@ -0,0 +1,45 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER INSERT on Order table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_Order_Audit_Insert` + AFTER INSERT ON `Order` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Order', + CAST(NEW.OrderID AS CHAR), -- 主键值 + 'INSERT', + @actor_id, -- 从会话变量获取操作者ID + NULL, -- INSERT 操作没有旧值 + JSON_OBJECT( + 'OrderID', NEW.OrderID, + 'UserID', NEW.UserID, + 'StoreID', NEW.StoreID, + 'PaymentTransactionID', NEW.PaymentTransactionID, + 'OrderStatus', NEW.OrderStatus, + 'OrderTotalAmount', NEW.OrderTotalAmount, + 'DiscountAmount', NEW.DiscountAmount, + 'ShippingFee', NEW.ShippingFee, + 'FinalAmountForThisOrder', NEW.FinalAmountForThisOrder, + 'ShippingAddress_RecipientName', NEW.ShippingAddress_RecipientName, + 'ShippingAddress_PhoneNumber', NEW.ShippingAddress_PhoneNumber, + 'ShippingAddress_Full', NEW.ShippingAddress_Full, + 'Notes_ByUser', NEW.Notes_ByUser, + 'Notes_ByMerchant', NEW.Notes_ByMerchant, + 'CreationTime', NEW.CreationTime, + 'PaymentConfirmationTime', NEW.PaymentConfirmationTime, + 'ShippingTime', NEW.ShippingTime, + 'DeliveryTime', NEW.DeliveryTime, + 'CompletionTime', NEW.CompletionTime, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); +END; diff --git a/src/backend/sql/triggers/01202_order_audit_update.sql b/src/backend/sql/triggers/01202_order_audit_update.sql new file mode 100644 index 0000000..a705c00 --- /dev/null +++ b/src/backend/sql/triggers/01202_order_audit_update.sql @@ -0,0 +1,87 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER UPDATE on Order table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_Order_Audit_Update` + AFTER UPDATE ON `Order` + FOR EACH ROW +BEGIN + -- 只有当受监控的业务字段实际发生变化时才记录日志 + -- LastUpdatedDate 通常是自动更新的,可以决定是否因为这个时间戳的变化而触发审计日志 + IF OLD.UserID <=> NEW.UserID OR + OLD.StoreID <=> NEW.StoreID OR + OLD.PaymentTransactionID <=> NEW.PaymentTransactionID OR + OLD.OrderStatus <=> NEW.OrderStatus OR + OLD.OrderTotalAmount <=> NEW.OrderTotalAmount OR + OLD.DiscountAmount <=> NEW.DiscountAmount OR + OLD.ShippingFee <=> NEW.ShippingFee OR + OLD.FinalAmountForThisOrder <=> NEW.FinalAmountForThisOrder OR + OLD.ShippingAddress_RecipientName <=> NEW.ShippingAddress_RecipientName OR + OLD.ShippingAddress_PhoneNumber <=> NEW.ShippingAddress_PhoneNumber OR + OLD.ShippingAddress_Full <=> NEW.ShippingAddress_Full OR + OLD.Notes_ByUser <=> NEW.Notes_ByUser OR + OLD.Notes_ByMerchant <=> NEW.Notes_ByMerchant OR + OLD.PaymentConfirmationTime <=> NEW.PaymentConfirmationTime OR + OLD.ShippingTime <=> NEW.ShippingTime OR + OLD.DeliveryTime <=> NEW.DeliveryTime OR + OLD.CompletionTime <=> NEW.CompletionTime + THEN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Order', + CAST(NEW.OrderID AS CHAR), -- 主键值 + 'UPDATE', + @actor_id, + JSON_OBJECT( + 'OrderID', OLD.OrderID, + 'UserID', OLD.UserID, + 'StoreID', OLD.StoreID, + 'PaymentTransactionID', OLD.PaymentTransactionID, + 'OrderStatus', OLD.OrderStatus, + 'OrderTotalAmount', OLD.OrderTotalAmount, + 'DiscountAmount', OLD.DiscountAmount, + 'ShippingFee', OLD.ShippingFee, + 'FinalAmountForThisOrder', OLD.FinalAmountForThisOrder, + 'ShippingAddress_RecipientName', OLD.ShippingAddress_RecipientName, + 'ShippingAddress_PhoneNumber', OLD.ShippingAddress_PhoneNumber, + 'ShippingAddress_Full', OLD.ShippingAddress_Full, + 'Notes_ByUser', OLD.Notes_ByUser, + 'Notes_ByMerchant', OLD.Notes_ByMerchant, + 'CreationTime', OLD.CreationTime, + 'PaymentConfirmationTime', OLD.PaymentConfirmationTime, + 'ShippingTime', OLD.ShippingTime, + 'DeliveryTime', OLD.DeliveryTime, + 'CompletionTime', OLD.CompletionTime, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + JSON_OBJECT( + 'OrderID', NEW.OrderID, + 'UserID', NEW.UserID, + 'StoreID', NEW.StoreID, + 'PaymentTransactionID', NEW.PaymentTransactionID, + 'OrderStatus', NEW.OrderStatus, + 'OrderTotalAmount', NEW.OrderTotalAmount, + 'DiscountAmount', NEW.DiscountAmount, + 'ShippingFee', NEW.ShippingFee, + 'FinalAmountForThisOrder', NEW.FinalAmountForThisOrder, + 'ShippingAddress_RecipientName', NEW.ShippingAddress_RecipientName, + 'ShippingAddress_PhoneNumber', NEW.ShippingAddress_PhoneNumber, + 'ShippingAddress_Full', NEW.ShippingAddress_Full, + 'Notes_ByUser', NEW.Notes_ByUser, + 'Notes_ByMerchant', NEW.Notes_ByMerchant, + 'CreationTime', NEW.CreationTime, + 'PaymentConfirmationTime', NEW.PaymentConfirmationTime, + 'ShippingTime', NEW.ShippingTime, + 'DeliveryTime', NEW.DeliveryTime, + 'CompletionTime', NEW.CompletionTime, + 'LastUpdatedDate', NEW.LastUpdatedDate + ) + ); + END IF; +END; diff --git a/src/backend/sql/triggers/01203_order_audit_delete.sql b/src/backend/sql/triggers/01203_order_audit_delete.sql new file mode 100644 index 0000000..1aef5b9 --- /dev/null +++ b/src/backend/sql/triggers/01203_order_audit_delete.sql @@ -0,0 +1,45 @@ +-- ----------------------------------------------------- +-- Trigger for AFTER DELETE on Order table +-- ----------------------------------------------------- +CREATE TRIGGER `trg_Order_Audit_Delete` + AFTER DELETE ON `Order` + FOR EACH ROW +BEGIN + INSERT INTO `AuditLog` ( + `TableName`, + `RowPKValue`, + `OperationType`, + `ChangedByUserID`, + `OldValues_JSON`, + `NewValues_JSON` + ) + VALUES ( + 'Order', + CAST(OLD.OrderID AS CHAR), + 'DELETE', + @actor_id, + JSON_OBJECT( + 'OrderID', OLD.OrderID, + 'UserID', OLD.UserID, + 'StoreID', OLD.StoreID, + 'PaymentTransactionID', OLD.PaymentTransactionID, + 'OrderStatus', OLD.OrderStatus, + 'OrderTotalAmount', OLD.OrderTotalAmount, + 'DiscountAmount', OLD.DiscountAmount, + 'ShippingFee', OLD.ShippingFee, + 'FinalAmountForThisOrder', OLD.FinalAmountForThisOrder, + 'ShippingAddress_RecipientName', OLD.ShippingAddress_RecipientName, + 'ShippingAddress_PhoneNumber', OLD.ShippingAddress_PhoneNumber, + 'ShippingAddress_Full', OLD.ShippingAddress_Full, + 'Notes_ByUser', OLD.Notes_ByUser, + 'Notes_ByMerchant', OLD.Notes_ByMerchant, + 'CreationTime', OLD.CreationTime, + 'PaymentConfirmationTime', OLD.PaymentConfirmationTime, + 'ShippingTime', OLD.ShippingTime, + 'DeliveryTime', OLD.DeliveryTime, + 'CompletionTime', OLD.CompletionTime, + 'LastUpdatedDate', OLD.LastUpdatedDate + ), + NULL -- DELETE 操作没有新值 + ); +END; diff --git a/src/backend/sql/triggers/90000_unset_system_var.sql b/src/backend/sql/triggers/90000_unset_system_var.sql new file mode 100644 index 0000000..e9f31a1 --- /dev/null +++ b/src/backend/sql/triggers/90000_unset_system_var.sql @@ -0,0 +1 @@ +SET GLOBAL log_bin_trust_function_creators = 0; diff --git a/src/backend/sql/utils/drop_all.sql b/src/backend/sql/utils/drop_all.sql index 2298404..16e5a07 100644 --- a/src/backend/sql/utils/drop_all.sql +++ b/src/backend/sql/utils/drop_all.sql @@ -35,6 +35,73 @@ DROP TABLE IF EXISTS `Store`; DROP TABLE IF EXISTS `ShippingAddress`; DROP TABLE IF EXISTS `UserSession`; DROP TABLE IF EXISTS `User`; +DROP TABLE IF EXISTS `AuditLog`; + +-- 删除所有触发器 +-- User 相关触发器 +DROP TRIGGER IF EXISTS `trg_User_Audit_Insert`; +DROP TRIGGER IF EXISTS `trg_User_Audit_Update`; +DROP TRIGGER IF EXISTS `trg_User_Audit_Delete`; + +-- UserSession 相关触发器 +DROP TRIGGER IF EXISTS `trg_UserSession_Audit_Insert`; +DROP TRIGGER IF EXISTS `trg_UserSession_Audit_Update`; +DROP TRIGGER IF EXISTS `trg_UserSession_Audit_Delete`; + +-- ShippingAddress 相关触发器 +DROP TRIGGER IF EXISTS `trg_ShippingAddress_Audit_Insert`; +DROP TRIGGER IF EXISTS `trg_ShippingAddress_Audit_Update`; +DROP TRIGGER IF EXISTS `trg_ShippingAddress_Audit_Delete`; + +-- Store 相关触发器 +DROP TRIGGER IF EXISTS `trg_Store_Audit_Insert`; +DROP TRIGGER IF EXISTS `trg_Store_Audit_Update`; +DROP TRIGGER IF EXISTS `trg_Store_Audit_Delete`; + +-- ProductCategory 相关触发器 +DROP TRIGGER IF EXISTS `trg_ProductCategory_Audit_Insert`; +DROP TRIGGER IF EXISTS `trg_ProductCategory_Audit_Update`; +DROP TRIGGER IF EXISTS `trg_ProductCategory_Audit_Delete`; + +-- Product 相关触发器 +DROP TRIGGER IF EXISTS `trg_Product_Audit_Insert`; +DROP TRIGGER IF EXISTS `trg_Product_Audit_Update`; +DROP TRIGGER IF EXISTS `trg_Product_Audit_Delete`; + +-- ProductImage 相关触发器 +DROP TRIGGER IF EXISTS `trg_ProductImage_Audit_Insert`; +DROP TRIGGER IF EXISTS `trg_ProductImage_Audit_Update`; +DROP TRIGGER IF EXISTS `trg_ProductImage_Audit_Delete`; + +-- StoreChangeRequest 相关触发器 +DROP TRIGGER IF EXISTS `trg_StoreChangeRequest_Audit_Insert`; +DROP TRIGGER IF EXISTS `trg_StoreChangeRequest_Audit_Update`; +DROP TRIGGER IF EXISTS `trg_StoreChangeRequest_Audit_Delete`; + +-- ProductChangeRequest 相关触发器 +DROP TRIGGER IF EXISTS `trg_ProductChangeRequest_Audit_Insert`; +DROP TRIGGER IF EXISTS `trg_ProductChangeRequest_Audit_Update`; +DROP TRIGGER IF EXISTS `trg_ProductChangeRequest_Audit_Delete`; + +-- CartItem 相关触发器 +DROP TRIGGER IF EXISTS `trg_CartItem_Audit_Insert`; +DROP TRIGGER IF EXISTS `trg_CartItem_Audit_Update`; +DROP TRIGGER IF EXISTS `trg_CartItem_Audit_Delete`; + +-- PaymentTransaction 相关触发器 +DROP TRIGGER IF EXISTS `trg_PaymentTransaction_Audit_Insert`; +DROP TRIGGER IF EXISTS `trg_PaymentTransaction_Audit_Update`; +DROP TRIGGER IF EXISTS `trg_PaymentTransaction_Audit_Delete`; + +-- Order 相关触发器 +DROP TRIGGER IF EXISTS `trg_Order_Audit_Insert`; +DROP TRIGGER IF EXISTS `trg_Order_Audit_Update`; +DROP TRIGGER IF EXISTS `trg_Order_Audit_Delete`; + +-- OrderItem 相关触发器 +DROP TRIGGER IF EXISTS `trg_OrderItem_Audit_Insert`; +DROP TRIGGER IF EXISTS `trg_OrderItem_Audit_Update`; +DROP TRIGGER IF EXISTS `trg_OrderItem_Audit_Delete`; -- 重新启用外键检查 diff --git a/src/backend/test/base_db_testcase.py b/src/backend/test/base_db_testcase.py index 527ec85..123190c 100644 --- a/src/backend/test/base_db_testcase.py +++ b/src/backend/test/base_db_testcase.py @@ -33,7 +33,7 @@ def setUpClass(cls): # 2. 清空测试数据库中的表数据 - reset_test() + reset_test(no_trigger=True) logger.info(f"Testcase Base setting up complete") @@ -90,7 +90,7 @@ def setUpClass(cls): # 2. 重置测试数据库 (创建表结构,清空数据等) logger.info(f"INFO: {cls.__name__}.setUpClass - Resetting test database...") - reset_test() # 假设 reset_test() 是一个同步函数 + reset_test(no_trigger=True) # 假设 reset_test() 是一个同步函数 logger.info(f"INFO: {cls.__name__}.setUpClass - Setup complete.") @@ -214,7 +214,7 @@ def setUpClass(cls): assert (cls._get_drop_all_data_script_path().exists()) - reset_test() + reset_test(no_trigger=True) # 3. (如果需要) 在这里部署表结构 (DDL) 和存储过程 # 如果你的测试数据库不是预先就有这些结构的。