diff --git a/backend/api/internal/logic/platform/resource_test.go b/backend/api/internal/logic/platform/resource_test.go index 3158998..e2850df 100644 --- a/backend/api/internal/logic/platform/resource_test.go +++ b/backend/api/internal/logic/platform/resource_test.go @@ -177,6 +177,21 @@ func TestReplacePlatformRoleMenusAllowsAnEmptySetToClearAssignmentsTransactional assertMockExpectations(t, mock) } +func TestReplacePlatformRoleMenusRejectsSystemRoleBeforeChangingRelations(t *testing.T) { + _, mock := setupPlatformRoleDatabase(t) + mock.ExpectBegin() + mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "platform_role" WHERE identity = $1 ORDER BY "platform_role"."id" LIMIT $2`)). + WithArgs("root-role", 1). + WillReturnRows(platformSystemRoleRows("root-role")) + mock.ExpectRollback() + + ctx, recorder := updateContext(http.MethodPut, "/roles/root-role/menus", "root-role", []byte(`{"menu_identities":[]}`)) + ReplacePlatformRoleMenus(ctx) + + assertResponseCode(t, recorder, int32(status.Code(errcode.ErrInvalidArgument))) + assertMockExpectations(t, mock) +} + type responseBody struct { Code int32 `json:"code"` Message string `json:"message"` @@ -207,6 +222,11 @@ func platformRoleRows(identity string) *sqlmock.Rows { AddRow(uint64(1), identity, nil, nil, "enabled", 1, identity, identity, "global", false) } +func platformSystemRoleRows(identity string) *sqlmock.Rows { + return sqlmock.NewRows([]string{"id", "identity", "created_at", "updated_at", "status", "version", "role_code", "name", "data_scope", "is_system"}). + AddRow(uint64(1), identity, nil, nil, "enabled", 1, identity, identity, "global", true) +} + func updateContext(method, target, identity string, body []byte) (*gin.Context, *httptest.ResponseRecorder) { recorder := httptest.NewRecorder() ctx, _ := gin.CreateTestContext(recorder) diff --git a/backend/api/internal/logic/platform/role.go b/backend/api/internal/logic/platform/role.go index 23f9464..e164edd 100644 --- a/backend/api/internal/logic/platform/role.go +++ b/backend/api/internal/logic/platform/role.go @@ -11,6 +11,8 @@ import ( "gorm.io/gorm" ) +var errSystemPlatformRole = errors.New("system platform roles cannot be modified") + // ListPlatformRole 查询平台角色分页列表。 func ListPlatformRole(ctx *gin.Context) { listPage[models.PlatformRole](ctx) } @@ -108,6 +110,9 @@ func ReplacePlatformRoleMenus(ctx *gin.Context) { if err := transaction.Where("identity = ?", ctx.Param("identity")).First(&role).Error; err != nil { return err } + if role.IsSystem { + return errSystemPlatformRole + } var menus []models.PlatformMenu if len(request.MenuIdentities) > 0 { if err := transaction.Where("identity IN ?", request.MenuIdentities).Find(&menus).Error; err != nil { @@ -132,6 +137,10 @@ func ReplacePlatformRoleMenus(ctx *gin.Context) { infra.Response.Error(ctx, errcode.ErrRecordNotFound) return } + if errors.Is(err, errSystemPlatformRole) { + infra.Response.Error(ctx, errcode.ErrInvalidArgument) + return + } infra.Response.Error(ctx, err) return }