diff --git a/iam/src/main/resources/db/lastleg-permissions.sql b/iam/src/main/resources/db/lastleg-permissions.sql index 3e5897429..90f805f4f 100644 --- a/iam/src/main/resources/db/lastleg-permissions.sql +++ b/iam/src/main/resources/db/lastleg-permissions.sql @@ -81,7 +81,8 @@ VALUES (5306100,0,'MERCHANT','MENU',0,'merchant:cross-border:procurement','海外采购','/cross-border/procurement',NULL,70,'ACTIVE',1,0), (5306110,0,'MERCHANT','MENU',0,'merchant:cross-border:domestic-trucking','美国本土卡','/cross-border/domestic-trucking',NULL,80,'ACTIVE',1,0), (5306120,0,'MERCHANT','MENU',0,'merchant:cross-border:pallet-shipping','美本土散板','/cross-border/pallet-shipping',NULL,90,'ACTIVE',1,0), - (5306130,0,'MERCHANT','MENU',0,'merchant:warehouse:inbound:list','海外仓入库订单','/orders/inbound',NULL,50,'ACTIVE',1,0) + (5306130,0,'MERCHANT','MENU',0,'merchant:warehouse:inbound:list','海外仓入库订单','/orders/inbound',NULL,50,'ACTIVE',1,0), + (5306140,0,'MERCHANT','MENU',0,'merchant:overseas-warehouse:return-inventory:list','退货库存','/overseas-warehouse/return-inventory','GET',95,'ACTIVE',1,0) ON DUPLICATE KEY UPDATE permission_type=VALUES(permission_type), parent_id=VALUES(parent_id), permission_name=VALUES(permission_name), route_path=VALUES(route_path), http_method=VALUES(http_method), sort_no=VALUES(sort_no), status='ACTIVE', built_in=1, deleted=0; @@ -227,7 +228,8 @@ JOIN iam_permission permission ON permission.tenant_id=0 AND permission.app_code 'merchant:cross-border:procurement', 'merchant:cross-border:domestic-trucking', 'merchant:cross-border:pallet-shipping', - 'merchant:warehouse:inbound:list' + 'merchant:warehouse:inbound:list', + 'merchant:overseas-warehouse:return-inventory:list' ) WHERE role.tenant_id=0 AND role.app_code='MERCHANT' AND role.role_code='MERCHANT_OWNER' AND role.status='ACTIVE' AND role.deleted=0 AND permission.status='ACTIVE' AND permission.deleted=0; @@ -242,7 +244,8 @@ BEGIN 'merchant:cross-border:procurement', 'merchant:cross-border:domestic-trucking', 'merchant:cross-border:pallet-shipping', - 'merchant:warehouse:inbound:list')) <> 4 THEN + 'merchant:warehouse:inbound:list', + 'merchant:overseas-warehouse:return-inventory:list')) <> 5 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外客户权限初始化失败:权限资源不完整'; END IF; IF (SELECT COUNT(*) FROM iam_role_permission grant_row @@ -256,7 +259,8 @@ BEGIN 'merchant:cross-border:procurement', 'merchant:cross-border:domestic-trucking', 'merchant:cross-border:pallet-shipping', - 'merchant:warehouse:inbound:list')) <> 4 THEN + 'merchant:warehouse:inbound:list', + 'merchant:overseas-warehouse:return-inventory:list')) <> 5 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='海外客户权限初始化失败:客户默认管理员授权不完整'; END IF; END$$ diff --git a/iam/src/test/java/com/baiyue/iam/repository/MerchantReturnInventoryPermissionSqlContractTest.java b/iam/src/test/java/com/baiyue/iam/repository/MerchantReturnInventoryPermissionSqlContractTest.java new file mode 100644 index 000000000..4cff5c013 --- /dev/null +++ b/iam/src/test/java/com/baiyue/iam/repository/MerchantReturnInventoryPermissionSqlContractTest.java @@ -0,0 +1,63 @@ +package com.baiyue.iam.repository; + +import org.junit.jupiter.api.Test; +import org.springframework.core.io.ClassPathResource; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; + +class MerchantReturnInventoryPermissionSqlContractTest { + private static final String PERMISSION = "merchant:overseas-warehouse:return-inventory:list"; + + @Test + void moduleCatalogGrantsReturnInventoryToTheDefaultMerchantAdministrator() throws Exception { + String sql = new ClassPathResource("db/lastleg-permissions.sql") + .getContentAsString(StandardCharsets.UTF_8); + + assertThat(sql).contains( + "(5306140,0,'MERCHANT','MENU',0,'" + PERMISSION + "','退货库存'", + "role.role_code='MERCHANT_OWNER'", + "'" + PERMISSION + "')) <> 5", + "客户默认管理员授权不完整"); + + int grantStart = sql.indexOf("-- 客户默认管理员获得当前客户海外业务入口"); + int grantEnd = sql.indexOf("DROP PROCEDURE IF EXISTS assert_overseas_merchant_permissions", grantStart); + assertThat(grantStart).isGreaterThanOrEqualTo(0); + assertThat(grantEnd).isGreaterThan(grantStart); + assertThat(sql.substring(grantStart, grantEnd)).contains("'" + PERMISSION + "'"); + } + + @Test + void cleanInitializationKeepsThePermissionAndOwnerGrant() throws Exception { + String sql = repositoryFile("deploy/sql/头程数据库统一增量-MySQL8.sql"); + + assertThat(sql).contains( + "(5306140,0,'MERCHANT','MENU',0,'" + PERMISSION + "','退货库存'", + "(4000100,5306140,0,CURRENT_TIMESTAMP(3))"); + } + + @Test + void lastlegUsesTheCanonicalOverseasPermissionConstant() throws Exception { + String permissions = repositoryFile( + "lastleg-service/src/main/java/com/baiyue/lastleg/security/OverseasPermissions.java"); + String controller = repositoryFile( + "lastleg-service/src/main/java/com/baiyue/lastleg/returnreceipt/controller/MerchantReturnInventoryController.java"); + + assertThat(permissions).contains( + "MERCHANT_RETURN_INVENTORY_LIST =", + "\"" + PERMISSION + "\""); + assertThat(controller).contains( + "LIST_PERMISSION = OverseasPermissions.MERCHANT_RETURN_INVENTORY_LIST", + "@GetMapping(\"/summary\")", + "@PreAuthorize(\"hasAuthority('\" + LIST_PERMISSION + \"')\")"); + } + + private static String repositoryFile(String relativePath) throws Exception { + Path path = Path.of(relativePath); + if (!Files.exists(path)) path = Path.of("..").resolve(relativePath); + return Files.readString(path, StandardCharsets.UTF_8); + } +} diff --git a/iam/src/test/java/com/baiyue/iam/repository/OverseasCustomerPermissionSqlContractTest.java b/iam/src/test/java/com/baiyue/iam/repository/OverseasCustomerPermissionSqlContractTest.java index d760aec46..f65c809ef 100644 --- a/iam/src/test/java/com/baiyue/iam/repository/OverseasCustomerPermissionSqlContractTest.java +++ b/iam/src/test/java/com/baiyue/iam/repository/OverseasCustomerPermissionSqlContractTest.java @@ -18,7 +18,8 @@ class OverseasCustomerPermissionSqlContractTest { "merchant:cross-border:procurement", "merchant:cross-border:domestic-trucking", "merchant:cross-border:pallet-shipping", - "merchant:warehouse:inbound:list"); + "merchant:warehouse:inbound:list", + "merchant:overseas-warehouse:return-inventory:list"); @Test void declaresTheFrozenCustomerOverseasPermissionCatalog() throws Exception { @@ -32,11 +33,12 @@ class OverseasCustomerPermissionSqlContractTest { "'merchant:cross-border:procurement','海外采购','/cross-border/procurement'", "'merchant:cross-border:domestic-trucking','美国本土卡','/cross-border/domestic-trucking'", "'merchant:cross-border:pallet-shipping','美本土散板','/cross-border/pallet-shipping'", - "'merchant:warehouse:inbound:list','海外仓入库订单','/orders/inbound'"); + "'merchant:warehouse:inbound:list','海外仓入库订单','/orders/inbound'", + "'merchant:overseas-warehouse:return-inventory:list','退货库存','/overseas-warehouse/return-inventory'"); } @Test - void grantsAllFourPermissionsOnlyToTheDefaultCustomerAdministrator() throws Exception { + void grantsAllFivePermissionsOnlyToTheDefaultCustomerAdministrator() throws Exception { String sql = sql(); int comment = sql.indexOf("-- 客户默认管理员获得当前客户海外业务入口"); int grantStart = sql.indexOf("INSERT IGNORE INTO iam_role_permission", comment); @@ -64,7 +66,7 @@ class OverseasCustomerPermissionSqlContractTest { "海外客户权限初始化失败:客户默认管理员授权不完整", "permission.app_code='MERCHANT'", "role.role_code='MERCHANT_OWNER'", - ")) <> 4 THEN"); + ")) <> 5 THEN"); } @Test diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/returnreceipt/controller/MerchantReturnInventoryController.java b/lastleg-service/src/main/java/com/baiyue/lastleg/returnreceipt/controller/MerchantReturnInventoryController.java index 0713b49bc..7e82602ec 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/returnreceipt/controller/MerchantReturnInventoryController.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/returnreceipt/controller/MerchantReturnInventoryController.java @@ -6,6 +6,7 @@ import com.baiyue.common.security.AuthenticatedUser; import com.baiyue.lastleg.returnreceipt.dto.ReturnInventoryRequests; import com.baiyue.lastleg.returnreceipt.dto.ReturnInventoryResponses; import com.baiyue.lastleg.returnreceipt.service.ReturnInventoryService; +import com.baiyue.lastleg.security.OverseasPermissions; import jakarta.annotation.Resource; import jakarta.validation.Valid; import org.springframework.http.HttpStatus; @@ -20,7 +21,7 @@ import org.springframework.web.server.ResponseStatusException; @RestController @RequestMapping("/api/merchant/v1/last-leg/return-inventory") public class MerchantReturnInventoryController { - public static final String LIST_PERMISSION = "merchant:overseas-warehouse:return-inventory:list"; + public static final String LIST_PERMISSION = OverseasPermissions.MERCHANT_RETURN_INVENTORY_LIST; @Resource private ReturnInventoryService service; @GetMapping diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/security/OverseasPermissions.java b/lastleg-service/src/main/java/com/baiyue/lastleg/security/OverseasPermissions.java index 98f5ca509..3d4bf6ae0 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/security/OverseasPermissions.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/security/OverseasPermissions.java @@ -43,6 +43,8 @@ public final class OverseasPermissions { public static final String MERCHANT_DELIVERY_LIST = "merchant:warehouse:delivery:list"; public static final String MERCHANT_DELIVERY_CREATE = "merchant:warehouse:delivery:create"; public static final String MERCHANT_INBOUND_LIST = "merchant:warehouse:inbound:list"; + public static final String MERCHANT_RETURN_INVENTORY_LIST = + "merchant:overseas-warehouse:return-inventory:list"; public static final String MERCHANT_PROCUREMENT = "merchant:cross-border:procurement"; public static final String MERCHANT_TRUCKING = "merchant:cross-border:domestic-trucking"; public static final String MERCHANT_LOOSEBOARD = "merchant:cross-border:pallet-shipping";