fix: allow optional phase5 custom admin role

This commit is contained in:
2026-09-01 20:36:24 +08:00
parent 974d7b1e43
commit 6449daf823
5 changed files with 244 additions and 14 deletions
@@ -16711,11 +16711,14 @@ BEGIN
'platform:overseas-warehouse:customer-visit:edit')) <> 14 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:平台管理员授权不完整';
END IF;
IF (SELECT COUNT(*) FROM iam_role_permission grant_row
JOIN iam_role role ON role.id=grant_row.role_id AND role.tenant_id=grant_row.tenant_id
JOIN iam_permission permission ON permission.id=grant_row.permission_id
WHERE role.role_code='PLATFORM_CUSTOM_ADMIN'
AND permission.permission_code IN (
IF EXISTS (SELECT 1 FROM iam_role role
WHERE role.tenant_id=0 AND role.app_code='PLATFORM'
AND UPPER(role.role_code)='PLATFORM_CUSTOM_ADMIN'
AND role.status='ACTIVE' AND role.deleted=0
AND (SELECT COUNT(*) FROM iam_role_permission grant_row
JOIN iam_permission permission ON permission.id=grant_row.permission_id
WHERE grant_row.role_id=role.id AND grant_row.tenant_id=role.tenant_id
AND permission.permission_code IN (
'platform:overseas-warehouse:dispatch:list',
'platform:overseas-warehouse:dispatch:edit',
'platform:overseas-warehouse:dispatch:cancel',
@@ -16729,7 +16732,7 @@ BEGIN
'platform:overseas-warehouse:delivery:return',
'platform:overseas-warehouse:delivery:status',
'platform:overseas-warehouse:customer-visit:list',
'platform:overseas-warehouse:customer-visit:edit')) <> 14 THEN
'platform:overseas-warehouse:customer-visit:edit')) <> 14) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:平台自定义管理员授权不完整';
END IF;
SELECT COALESCE(SUM(role_code='WAREHOUSE_OPERATOR'),0),
+1 -1
View File
@@ -18,8 +18,8 @@
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>
<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency>
<dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>test</scope></dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
</dependencies>
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>
@@ -223,11 +223,14 @@ BEGIN
'platform:overseas-warehouse:customer-visit:edit')) <> 14 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:平台管理员授权不完整';
END IF;
IF (SELECT COUNT(*) FROM iam_role_permission grant_row
JOIN iam_role role ON role.id=grant_row.role_id AND role.tenant_id=grant_row.tenant_id
JOIN iam_permission permission ON permission.id=grant_row.permission_id
WHERE role.role_code='PLATFORM_CUSTOM_ADMIN'
AND permission.permission_code IN (
IF EXISTS (SELECT 1 FROM iam_role role
WHERE role.tenant_id=0 AND role.app_code='PLATFORM'
AND UPPER(role.role_code)='PLATFORM_CUSTOM_ADMIN'
AND role.status='ACTIVE' AND role.deleted=0
AND (SELECT COUNT(*) FROM iam_role_permission grant_row
JOIN iam_permission permission ON permission.id=grant_row.permission_id
WHERE grant_row.role_id=role.id AND grant_row.tenant_id=role.tenant_id
AND permission.permission_code IN (
'platform:overseas-warehouse:dispatch:list',
'platform:overseas-warehouse:dispatch:edit',
'platform:overseas-warehouse:dispatch:cancel',
@@ -241,7 +244,7 @@ BEGIN
'platform:overseas-warehouse:delivery:return',
'platform:overseas-warehouse:delivery:status',
'platform:overseas-warehouse:customer-visit:list',
'platform:overseas-warehouse:customer-visit:edit')) <> 14 THEN
'platform:overseas-warehouse:customer-visit:edit')) <> 14) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='五期海外派送权限初始化失败:平台自定义管理员授权不完整';
END IF;
SELECT COALESCE(SUM(role_code='WAREHOUSE_OPERATOR'),0),
@@ -108,7 +108,11 @@ class Phase5DeliveryPermissionSqlContractTest {
"INTO v_warehouse_operator_permission_count, v_warehouse_tally_permission_count",
"IF v_warehouse_operator_permission_count <> 14",
"OR v_warehouse_tally_permission_count <> 5 THEN",
"IF EXISTS (SELECT 1 FROM iam_role role",
"AND UPPER(role.role_code)='PLATFORM_CUSTOM_ADMIN'",
"WHERE grant_row.role_id=role.id AND grant_row.tenant_id=role.tenant_id",
"平台自定义管理员授权不完整");
assertThat(sql).doesNotContain("WHERE role.role_code='PLATFORM_CUSTOM_ADMIN'");
assertThat(sql).doesNotContain(
"IF (SELECT COUNT(*) FROM tmp_phase5_delivery_role_permission",
"OR (SELECT COUNT(*) FROM tmp_phase5_delivery_role_permission");
@@ -137,7 +141,7 @@ class Phase5DeliveryPermissionSqlContractTest {
int phase4 = unifiedSql.indexOf("-- 四期海外权限统一目录");
int phase5 = unifiedSql.indexOf("-- 五期海外排车、出库与派送权限(来源:iam/db/phase5-delivery-permissions.sql)");
int bodyStart = unifiedSql.indexOf("USE baiyue_iam;", phase5);
int nextSection = unifiedSql.indexOf("-- 海外智能排车草稿锁", bodyStart);
int nextSection = unifiedSql.indexOf("-- IAM 客户提交即成功", bodyStart);
assertThat(phase4).isGreaterThanOrEqualTo(0);
assertThat(phase5).isGreaterThan(phase4);
@@ -0,0 +1,220 @@
package com.baiyue.iam.repository;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Pattern;
import static org.assertj.core.api.Assertions.assertThat;
class Phase5DeliveryPermissionSqlExecutionTest {
private static final Pattern PLATFORM_CODE =
Pattern.compile("platform:overseas-warehouse:[a-z0-9:-]+");
@Test
void noCustomAdministratorDoesNotCreateAnAssertionViolation() throws Exception {
try (Connection connection = database()) {
executeGrant(connection);
assertThat(customAdministratorViolations(connection)).isZero();
}
}
@Test
void onePartiallyGrantedCustomAdministratorIsCompletedIdempotently() throws Exception {
try (Connection connection = database()) {
insertRole(connection, 11L, "platform_custom_admin");
grantFirstPermissions(connection, 11L, 3);
assertThat(customAdministratorViolations(connection)).isEqualTo(1);
executeGrant(connection);
assertThat(grantCount(connection, 11L)).isEqualTo(14);
assertThat(customAdministratorViolations(connection)).isZero();
executeGrant(connection);
assertThat(grantCount(connection, 11L)).isEqualTo(14);
assertThat(totalGrantCount(connection)).isEqualTo(14);
}
}
@Test
void multipleCustomAdministratorsExposeTheSingleIncompleteRole() throws Exception {
try (Connection connection = database()) {
insertRole(connection, 21L, "PLATFORM_CUSTOM_ADMIN");
insertRole(connection, 22L, "Platform_Custom_Admin");
grantFirstPermissions(connection, 21L, 14);
grantFirstPermissions(connection, 22L, 13);
assertThat(customAdministratorViolations(connection)).isEqualTo(1);
executeGrant(connection);
assertThat(grantCount(connection, 21L)).isEqualTo(14);
assertThat(grantCount(connection, 22L)).isEqualTo(14);
assertThat(customAdministratorViolations(connection)).isZero();
}
}
@Test
void multipleCompleteCustomAdministratorsRemainCompleteAfterReplay() throws Exception {
try (Connection connection = database()) {
insertRole(connection, 31L, "PLATFORM_CUSTOM_ADMIN");
insertRole(connection, 32L, "platform_custom_admin");
grantFirstPermissions(connection, 31L, 14);
grantFirstPermissions(connection, 32L, 14);
assertThat(customAdministratorViolations(connection)).isZero();
executeGrant(connection);
executeGrant(connection);
assertThat(grantCount(connection, 31L)).isEqualTo(14);
assertThat(grantCount(connection, 32L)).isEqualTo(14);
assertThat(totalGrantCount(connection)).isEqualTo(28);
}
}
private static Connection database() throws Exception {
Connection connection = DriverManager.getConnection(
"jdbc:h2:mem:phase5_" + UUID.randomUUID() + ";MODE=MySQL;DATABASE_TO_LOWER=TRUE");
try (Statement statement = connection.createStatement()) {
statement.execute("""
CREATE TABLE iam_role (
id BIGINT PRIMARY KEY,
tenant_id BIGINT NOT NULL,
app_code VARCHAR(32) NOT NULL,
role_code VARCHAR(64) NOT NULL,
status VARCHAR(16) NOT NULL,
deleted INT NOT NULL
)
""");
statement.execute("""
CREATE TABLE iam_permission (
id BIGINT PRIMARY KEY,
tenant_id BIGINT NOT NULL,
app_code VARCHAR(32) NOT NULL,
permission_code VARCHAR(160) NOT NULL,
status VARCHAR(16) NOT NULL,
deleted INT NOT NULL
)
""");
statement.execute("""
CREATE TABLE iam_role_permission (
tenant_id BIGINT NOT NULL,
role_id BIGINT NOT NULL,
permission_id BIGINT NOT NULL,
created_at TIMESTAMP NOT NULL,
PRIMARY KEY (tenant_id, role_id, permission_id)
)
""");
}
long id = 1;
for (String code : platformPermissions()) {
try (PreparedStatement insert = connection.prepareStatement(
"INSERT INTO iam_permission VALUES (?,0,'PLATFORM',?,'ACTIVE',0)")) {
insert.setLong(1, id++);
insert.setString(2, code);
insert.executeUpdate();
}
}
return connection;
}
private static void insertRole(Connection connection, long id, String roleCode) throws Exception {
try (PreparedStatement insert = connection.prepareStatement(
"INSERT INTO iam_role VALUES (?,0,'PLATFORM',?,'ACTIVE',0)")) {
insert.setLong(1, id);
insert.setString(2, roleCode);
insert.executeUpdate();
}
}
private static void grantFirstPermissions(Connection connection, long roleId, int limit) throws Exception {
try (PreparedStatement insert = connection.prepareStatement("""
INSERT INTO iam_role_permission (tenant_id, role_id, permission_id, created_at)
SELECT 0, ?, id, CURRENT_TIMESTAMP FROM iam_permission ORDER BY id LIMIT ?
""")) {
insert.setLong(1, roleId);
insert.setInt(2, limit);
insert.executeUpdate();
}
}
private static void executeGrant(Connection connection) throws Exception {
try (Statement statement = connection.createStatement()) {
statement.executeUpdate(administratorGrantSql());
}
}
private static int grantCount(Connection connection, long roleId) throws Exception {
try (PreparedStatement query = connection.prepareStatement(
"SELECT COUNT(*) FROM iam_role_permission WHERE tenant_id=0 AND role_id=?")) {
query.setLong(1, roleId);
try (ResultSet result = query.executeQuery()) {
result.next();
return result.getInt(1);
}
}
}
private static int totalGrantCount(Connection connection) throws Exception {
try (Statement query = connection.createStatement();
ResultSet result = query.executeQuery("SELECT COUNT(*) FROM iam_role_permission")) {
result.next();
return result.getInt(1);
}
}
private static int customAdministratorViolations(Connection connection) throws Exception {
String placeholders = String.join(",", platformPermissions().stream().map(code -> "?").toList());
String sql = """
SELECT COUNT(*) FROM iam_role role
WHERE role.tenant_id=0 AND role.app_code='PLATFORM'
AND UPPER(role.role_code)='PLATFORM_CUSTOM_ADMIN'
AND role.status='ACTIVE' AND role.deleted=0
AND (SELECT COUNT(*) FROM iam_role_permission grant_row
JOIN iam_permission permission ON permission.id=grant_row.permission_id
WHERE grant_row.role_id=role.id AND grant_row.tenant_id=role.tenant_id
AND permission.permission_code IN (%s)) <> 14
""".formatted(placeholders);
try (PreparedStatement query = connection.prepareStatement(sql)) {
int index = 1;
for (String code : platformPermissions()) query.setString(index++, code);
try (ResultSet result = query.executeQuery()) {
result.next();
return result.getInt(1);
}
}
}
private static String administratorGrantSql() throws Exception {
String sql = sql();
int comment = sql.indexOf("-- 平台管理员默认拥有五期全部后台动作");
int start = sql.indexOf("INSERT IGNORE INTO iam_role_permission", comment);
int end = sql.indexOf(';', start);
assertThat(comment).isGreaterThanOrEqualTo(0);
assertThat(start).isGreaterThan(comment);
assertThat(end).isGreaterThan(start);
return sql.substring(start, end);
}
private static Set<String> platformPermissions() throws Exception {
LinkedHashSet<String> codes = new LinkedHashSet<>();
String grant = administratorGrantSql();
PLATFORM_CODE.matcher(grant).results().map(result -> result.group()).forEach(codes::add);
assertThat(codes).hasSize(14);
return codes;
}
private static String sql() throws Exception {
return new ClassPathResource("db/phase5-delivery-permissions.sql")
.getContentAsString(StandardCharsets.UTF_8);
}
}