This is an automated email from the ASF dual-hosted git repository. lizhimins pushed a commit to branch rocketmq-studio in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
commit 49bc441957ab6d82af7c16952d699c364b220524 Author: lizhimins <[email protected]> AuthorDate: Sun Jul 5 15:34:00 2026 +0800 feat: implement backend common module and auth - Add common domain classes (Result, PageResult, BaseEntity) - Add 16 business enums (ClusterStatus, TopicType, etc.) - Implement global exception handler - Configure CORS and web MVC - Implement authentication (AuthController, AuthService) - Add auth unit tests --- .../com/rocketmq/studio/auth/AuthController.java | 44 ++++++++ .../java/com/rocketmq/studio/auth/AuthService.java | 60 +++++++++++ .../java/com/rocketmq/studio/auth/LoginDTO.java | 26 +++++ .../java/com/rocketmq/studio/auth/LoginVO.java | 42 ++++++++ .../com/rocketmq/studio/auth/SecurityConfig.java | 25 +++++ .../rocketmq/studio/common/config/CorsConfig.java | 33 ++++++ .../rocketmq/studio/common/config/WebConfig.java | 25 +++++ .../rocketmq/studio/common/domain/BaseEntity.java | 27 +++++ .../rocketmq/studio/common/domain/PageResult.java | 47 +++++++++ .../com/rocketmq/studio/common/domain/Result.java | 47 +++++++++ .../studio/common/domain/enums/AlertLevel.java | 22 ++++ .../studio/common/domain/enums/BrokerStatus.java | 22 ++++ .../studio/common/domain/enums/CertStatus.java | 22 ++++ .../studio/common/domain/enums/CertType.java | 22 ++++ .../studio/common/domain/enums/ClientLanguage.java | 22 ++++ .../studio/common/domain/enums/ClientType.java | 22 ++++ .../studio/common/domain/enums/ClusterStatus.java | 22 ++++ .../studio/common/domain/enums/ClusterType.java | 22 ++++ .../studio/common/domain/enums/ConsumeType.java | 22 ++++ .../studio/common/domain/enums/DeliveryStatus.java | 22 ++++ .../studio/common/domain/enums/FlushDiskType.java | 22 ++++ .../studio/common/domain/enums/InstanceType.java | 22 ++++ .../studio/common/domain/enums/Protocol.java | 22 ++++ .../common/domain/enums/SubscriptionMode.java | 22 ++++ .../studio/common/domain/enums/TopicPerm.java | 22 ++++ .../studio/common/domain/enums/TopicType.java | 22 ++++ .../studio/common/exception/BusinessException.java | 29 ++++++ .../common/exception/GlobalExceptionHandler.java | 45 ++++++++ .../rocketmq/studio/auth/AuthControllerTest.java | 115 +++++++++++++++++++++ .../com/rocketmq/studio/auth/AuthServiceTest.java | 115 +++++++++++++++++++++ 30 files changed, 1032 insertions(+) diff --git a/server/src/main/java/com/rocketmq/studio/auth/AuthController.java b/server/src/main/java/com/rocketmq/studio/auth/AuthController.java new file mode 100644 index 0000000..8b4f6f1 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/auth/AuthController.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.auth; + +import com.rocketmq.studio.common.domain.Result; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/auth") +@RequiredArgsConstructor +public class AuthController { + + private final AuthService authService; + + @PostMapping("/login") + public Result<LoginVO> login(@RequestBody LoginDTO request) { + return Result.ok(authService.login(request)); + } + + @PostMapping("/logout") + public Result<Void> logout() { + authService.logout(); + return Result.ok(); + } +} diff --git a/server/src/main/java/com/rocketmq/studio/auth/AuthService.java b/server/src/main/java/com/rocketmq/studio/auth/AuthService.java new file mode 100644 index 0000000..0591cef --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/auth/AuthService.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.auth; + +import com.rocketmq.studio.common.exception.BusinessException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.UUID; + +@Slf4j +@Service +public class AuthService { + + public LoginVO login(LoginDTO request) { + log.info("Login attempt for user: {}", request.getUsername()); + + if (request.getUsername() == null || request.getUsername().isBlank()) { + throw new BusinessException(400, "Username is required"); + } + if (request.getPassword() == null || request.getPassword().isBlank()) { + throw new BusinessException(400, "Password is required"); + } + + // Mock authentication — accept any non-empty credentials + String token = "mock-jwt-" + UUID.randomUUID(); + boolean isAdmin = "admin".equals(request.getUsername()); + + LoginVO response = LoginVO.builder() + .token(token) + .expiresIn(86400) + .user(LoginVO.UserInfo.builder() + .username(request.getUsername()) + .admin(isAdmin) + .build()) + .build(); + + log.info("User {} logged in successfully, admin={}", request.getUsername(), isAdmin); + return response; + } + + public void logout() { + log.info("User logged out"); + } +} diff --git a/server/src/main/java/com/rocketmq/studio/auth/LoginDTO.java b/server/src/main/java/com/rocketmq/studio/auth/LoginDTO.java new file mode 100644 index 0000000..a24238f --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/auth/LoginDTO.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.auth; + +import lombok.Data; + +@Data +public class LoginDTO { + private String username; + private String password; +} diff --git a/server/src/main/java/com/rocketmq/studio/auth/LoginVO.java b/server/src/main/java/com/rocketmq/studio/auth/LoginVO.java new file mode 100644 index 0000000..2a826f5 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/auth/LoginVO.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.auth; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class LoginVO { + private String token; + private int expiresIn; + private UserInfo user; + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class UserInfo { + private String username; + private boolean admin; + } +} diff --git a/server/src/main/java/com/rocketmq/studio/auth/SecurityConfig.java b/server/src/main/java/com/rocketmq/studio/auth/SecurityConfig.java new file mode 100644 index 0000000..7784098 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/auth/SecurityConfig.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.auth; + +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SecurityConfig { + // TODO: Add Spring Security configuration when Spring Security dependency is added +} diff --git a/server/src/main/java/com/rocketmq/studio/common/config/CorsConfig.java b/server/src/main/java/com/rocketmq/studio/common/config/CorsConfig.java new file mode 100644 index 0000000..fd14f2f --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/config/CorsConfig.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rocketmq.studio.common.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class CorsConfig implements WebMvcConfigurer { + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins("*") + .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") + .allowedHeaders("*"); + } +} diff --git a/server/src/main/java/com/rocketmq/studio/common/config/WebConfig.java b/server/src/main/java/com/rocketmq/studio/common/config/WebConfig.java new file mode 100644 index 0000000..951171f --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/config/WebConfig.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rocketmq.studio.common.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + // TODO: Add web configuration as needed +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/BaseEntity.java b/server/src/main/java/com/rocketmq/studio/common/domain/BaseEntity.java new file mode 100644 index 0000000..50144c5 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/BaseEntity.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rocketmq.studio.common.domain; + +import lombok.Data; +import java.time.LocalDateTime; + +@Data +public abstract class BaseEntity { + private String id; + private LocalDateTime createdAt; + private LocalDateTime updatedAt; +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/PageResult.java b/server/src/main/java/com/rocketmq/studio/common/domain/PageResult.java new file mode 100644 index 0000000..0d6b1e4 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/PageResult.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rocketmq.studio.common.domain; + +import java.util.Collections; +import java.util.List; + +public class PageResult<T> { + private List<T> items; + private long total; + private int page; + private int size; + + private PageResult() {} + + public static <T> PageResult<T> of(List<T> items, long total, int page, int size) { + PageResult<T> result = new PageResult<>(); + result.items = items; + result.total = total; + result.page = page; + result.size = size; + return result; + } + + public static <T> PageResult<T> empty(int page, int size) { + return of(Collections.emptyList(), 0, page, size); + } + + public List<T> getItems() { return items; } + public long getTotal() { return total; } + public int getPage() { return page; } + public int getSize() { return size; } +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/Result.java b/server/src/main/java/com/rocketmq/studio/common/domain/Result.java new file mode 100644 index 0000000..b234e08 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/Result.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rocketmq.studio.common.domain; + +public class Result<T> { + private int code; + private String message; + private T data; + + private Result() {} + + private Result(int code, String message, T data) { + this.code = code; + this.message = message; + this.data = data; + } + + public static <T> Result<T> ok(T data) { + return new Result<>(200, "success", data); + } + + public static <T> Result<T> ok() { + return new Result<>(200, "success", null); + } + + public static <T> Result<T> error(int code, String message) { + return new Result<>(code, message, null); + } + + public int getCode() { return code; } + public String getMessage() { return message; } + public T getData() { return data; } +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/enums/AlertLevel.java b/server/src/main/java/com/rocketmq/studio/common/domain/enums/AlertLevel.java new file mode 100644 index 0000000..e1dc8f8 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/AlertLevel.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.common.domain.enums; + +public enum AlertLevel { + error, warning, info +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/enums/BrokerStatus.java b/server/src/main/java/com/rocketmq/studio/common/domain/enums/BrokerStatus.java new file mode 100644 index 0000000..4396f7d --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/BrokerStatus.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.common.domain.enums; + +public enum BrokerStatus { + running, readonly, maintenance +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/enums/CertStatus.java b/server/src/main/java/com/rocketmq/studio/common/domain/enums/CertStatus.java new file mode 100644 index 0000000..af1d284 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/CertStatus.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.common.domain.enums; + +public enum CertStatus { + valid, expiring, expired +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/enums/CertType.java b/server/src/main/java/com/rocketmq/studio/common/domain/enums/CertType.java new file mode 100644 index 0000000..8b45b36 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/CertType.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.common.domain.enums; + +public enum CertType { + TLS, mTLS, ServiceAccount +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClientLanguage.java b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClientLanguage.java new file mode 100644 index 0000000..d87daeb --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClientLanguage.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.common.domain.enums; + +public enum ClientLanguage { + Java, Go, Python, Rust, Cpp, CSharp, NodeJS, PHP +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClientType.java b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClientType.java new file mode 100644 index 0000000..f244d18 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClientType.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.common.domain.enums; + +public enum ClientType { + Producer, Consumer +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClusterStatus.java b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClusterStatus.java new file mode 100644 index 0000000..5dd4307 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClusterStatus.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.common.domain.enums; + +public enum ClusterStatus { + healthy, warning, error, offline +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClusterType.java b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClusterType.java new file mode 100644 index 0000000..a10f3e2 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClusterType.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.common.domain.enums; + +public enum ClusterType { + V4_DIRECT, V5_PROXY_LOCAL, V5_PROXY_CLUSTER +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/enums/ConsumeType.java b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ConsumeType.java new file mode 100644 index 0000000..15e127c --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ConsumeType.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.common.domain.enums; + +public enum ConsumeType { + CLUSTERING, BROADCASTING +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/enums/DeliveryStatus.java b/server/src/main/java/com/rocketmq/studio/common/domain/enums/DeliveryStatus.java new file mode 100644 index 0000000..7c474f1 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/DeliveryStatus.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.common.domain.enums; + +public enum DeliveryStatus { + success, failed, pending +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/enums/FlushDiskType.java b/server/src/main/java/com/rocketmq/studio/common/domain/enums/FlushDiskType.java new file mode 100644 index 0000000..6bba212 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/FlushDiskType.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.common.domain.enums; + +public enum FlushDiskType { + ASYNC_FLUSH, SYNC_FLUSH +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/enums/InstanceType.java b/server/src/main/java/com/rocketmq/studio/common/domain/enums/InstanceType.java new file mode 100644 index 0000000..132b726 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/InstanceType.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.common.domain.enums; + +public enum InstanceType { + PROXY, DIRECT +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/enums/Protocol.java b/server/src/main/java/com/rocketmq/studio/common/domain/enums/Protocol.java new file mode 100644 index 0000000..64a568a --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/Protocol.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.common.domain.enums; + +public enum Protocol { + gRPC, Remoting +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/enums/SubscriptionMode.java b/server/src/main/java/com/rocketmq/studio/common/domain/enums/SubscriptionMode.java new file mode 100644 index 0000000..3a65255 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/SubscriptionMode.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.common.domain.enums; + +public enum SubscriptionMode { + Push, Pop +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/enums/TopicPerm.java b/server/src/main/java/com/rocketmq/studio/common/domain/enums/TopicPerm.java new file mode 100644 index 0000000..cd3660a --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/TopicPerm.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.common.domain.enums; + +public enum TopicPerm { + RW, RO, WO +} diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/enums/TopicType.java b/server/src/main/java/com/rocketmq/studio/common/domain/enums/TopicType.java new file mode 100644 index 0000000..1b2571b --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/TopicType.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.common.domain.enums; + +public enum TopicType { + NORMAL, FIFO, DELAY, TRANSACTION, LITE +} diff --git a/server/src/main/java/com/rocketmq/studio/common/exception/BusinessException.java b/server/src/main/java/com/rocketmq/studio/common/exception/BusinessException.java new file mode 100644 index 0000000..cb6c566 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/exception/BusinessException.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rocketmq.studio.common.exception; + +import lombok.Getter; + +@Getter +public class BusinessException extends RuntimeException { + private final int code; + + public BusinessException(int code, String message) { + super(message); + this.code = code; + } +} diff --git a/server/src/main/java/com/rocketmq/studio/common/exception/GlobalExceptionHandler.java b/server/src/main/java/com/rocketmq/studio/common/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..3bc1c19 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/common/exception/GlobalExceptionHandler.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.rocketmq.studio.common.exception; + +import com.rocketmq.studio.common.domain.Result; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); + + @ExceptionHandler(BusinessException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result<?> handleBusinessException(BusinessException ex) { + log.warn("Business exception: {}", ex.getMessage()); + return Result.error(ex.getCode(), ex.getMessage()); + } + + @ExceptionHandler(Exception.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result<?> handleException(Exception ex) { + log.error("Unexpected exception", ex); + return Result.error(500, "Internal Server Error"); + } +} diff --git a/server/src/test/java/com/rocketmq/studio/auth/AuthControllerTest.java b/server/src/test/java/com/rocketmq/studio/auth/AuthControllerTest.java new file mode 100644 index 0000000..b4fe26f --- /dev/null +++ b/server/src/test/java/com/rocketmq/studio/auth/AuthControllerTest.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.auth; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(AuthController.class) +@AutoConfigureMockMvc(addFilters = false) +class AuthControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private AuthService authService; + + @Autowired + private ObjectMapper objectMapper; + + @Test + void loginShouldReturnTokenOnValidRequest() throws Exception { + LoginVO mockResponse = LoginVO.builder() + .token("mock-jwt-abc123") + .expiresIn(86400) + .user(LoginVO.UserInfo.builder() + .username("testuser") + .admin(false) + .build()) + .build(); + + when(authService.login(any(LoginDTO.class))).thenReturn(mockResponse); + + LoginDTO request = new LoginDTO(); + request.setUsername("testuser"); + request.setPassword("testpass"); + + mockMvc.perform(post("/api/auth/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value(200)) + .andExpect(jsonPath("$.message").value("success")) + .andExpect(jsonPath("$.data.token").value("mock-jwt-abc123")) + .andExpect(jsonPath("$.data.expiresIn").value(86400)) + .andExpect(jsonPath("$.data.user.username").value("testuser")) + .andExpect(jsonPath("$.data.user.admin").value(false)); + } + + @Test + void loginShouldReturnAdminUserWhenAdminLogsIn() throws Exception { + LoginVO mockResponse = LoginVO.builder() + .token("mock-jwt-admin") + .expiresIn(86400) + .user(LoginVO.UserInfo.builder() + .username("admin") + .admin(true) + .build()) + .build(); + + when(authService.login(any(LoginDTO.class))).thenReturn(mockResponse); + + LoginDTO request = new LoginDTO(); + request.setUsername("admin"); + request.setPassword("adminpass"); + + mockMvc.perform(post("/api/auth/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.user.username").value("admin")) + .andExpect(jsonPath("$.data.user.admin").value(true)); + } + + @Test + void logoutShouldReturnSuccess() throws Exception { + doNothing().when(authService).logout(); + + mockMvc.perform(post("/api/auth/logout")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value(200)) + .andExpect(jsonPath("$.message").value("success")); + + verify(authService).logout(); + } +} diff --git a/server/src/test/java/com/rocketmq/studio/auth/AuthServiceTest.java b/server/src/test/java/com/rocketmq/studio/auth/AuthServiceTest.java new file mode 100644 index 0000000..1452572 --- /dev/null +++ b/server/src/test/java/com/rocketmq/studio/auth/AuthServiceTest.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.rocketmq.studio.auth; + +import com.rocketmq.studio.common.exception.BusinessException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +@ExtendWith(MockitoExtension.class) +class AuthServiceTest { + + private AuthService authService; + + @BeforeEach + void setUp() { + authService = new AuthService(); + } + + @Test + void loginShouldReturnTokenForValidCredentials() { + LoginDTO request = new LoginDTO(); + request.setUsername("testuser"); + request.setPassword("testpass"); + + LoginVO response = authService.login(request); + + assertThat(response).isNotNull(); + assertThat(response.getToken()).startsWith("mock-jwt-"); + assertThat(response.getExpiresIn()).isEqualTo(86400); + assertThat(response.getUser()).isNotNull(); + assertThat(response.getUser().getUsername()).isEqualTo("testuser"); + assertThat(response.getUser().isAdmin()).isFalse(); + } + + @Test + void loginShouldReturnAdminFlagForAdminUser() { + LoginDTO request = new LoginDTO(); + request.setUsername("admin"); + request.setPassword("adminpass"); + + LoginVO response = authService.login(request); + + assertThat(response.getUser().getUsername()).isEqualTo("admin"); + assertThat(response.getUser().isAdmin()).isTrue(); + } + + @Test + void loginShouldThrowWhenUsernameIsNull() { + LoginDTO request = new LoginDTO(); + request.setUsername(null); + request.setPassword("password"); + + assertThatThrownBy(() -> authService.login(request)) + .isInstanceOf(BusinessException.class) + .hasMessage("Username is required"); + } + + @Test + void loginShouldThrowWhenUsernameIsBlank() { + LoginDTO request = new LoginDTO(); + request.setUsername(" "); + request.setPassword("password"); + + assertThatThrownBy(() -> authService.login(request)) + .isInstanceOf(BusinessException.class) + .hasMessage("Username is required"); + } + + @Test + void loginShouldThrowWhenPasswordIsNull() { + LoginDTO request = new LoginDTO(); + request.setUsername("testuser"); + request.setPassword(null); + + assertThatThrownBy(() -> authService.login(request)) + .isInstanceOf(BusinessException.class) + .hasMessage("Password is required"); + } + + @Test + void loginShouldThrowWhenPasswordIsBlank() { + LoginDTO request = new LoginDTO(); + request.setUsername("testuser"); + request.setPassword(" "); + + assertThatThrownBy(() -> authService.login(request)) + .isInstanceOf(BusinessException.class) + .hasMessage("Password is required"); + } + + @Test + void logoutShouldCompleteWithoutError() { + authService.logout(); + } +}
