diff --git a/app-builder/jane/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/northbound/AippLogServiceAdapterImpl.java b/app-builder/jane/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/northbound/AippLogServiceAdapterImpl.java new file mode 100644 index 0000000000..c141474333 --- /dev/null +++ b/app-builder/jane/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/northbound/AippLogServiceAdapterImpl.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.jober.aipp.northbound; + +import modelengine.fit.jane.common.entity.OperationContext; +import modelengine.fit.jober.aipp.dto.aipplog.AippInstLogData; +import modelengine.fit.jober.aipp.dto.aipplog.AippInstLogDataDto; +import modelengine.fit.jober.aipp.genericable.adapter.AippLogServiceAdapter; +import modelengine.fit.jober.aipp.service.AippLogService; +import modelengine.fitframework.annotation.Component; + +import java.util.List; + +/** + * {@link AippLogServiceAdapter} 的适配器类的实现类。 + * + * @author 陈潇文 + * @since 2025-07-08 + */ +@Component +public class AippLogServiceAdapterImpl implements AippLogServiceAdapter { + private final AippLogService aippLogService; + + /** + * 用 aipp 实例历史记录服务接口的 {@link AippLogService} 构造 {@link AippLogServiceAdapterImpl}。 + * + * @param aippLogService 表示 aipp 实例历史记录服务接口的 {@link AippLogService}。 + */ + public AippLogServiceAdapterImpl(AippLogService aippLogService) { + this.aippLogService = aippLogService; + } + + @Override + public List queryChatRecentChatLog(String chatId, String appId, OperationContext context) { + List logDataDtoList = this.aippLogService.queryChatRecentChatLog(chatId, appId, context); + return logDataDtoList.stream() + .map(dto -> AippInstLogData.builder() + .aippId(dto.getAippId()) + .version(dto.getVersion()) + .instanceId(dto.getInstanceId()) + .status(dto.getStatus()) + .appName(dto.getAppName()) + .appIcon(dto.getAppIcon()) + .createAt(dto.getCreateAt()) + .question(this.convertQuestion(dto.getQuestion())) + .instanceLogBodies(this.convertLogBodies(dto.getInstanceLogBodies())) + .build()) + .toList(); + } + + private AippInstLogData.AippInstLogBody convertBody(AippInstLogDataDto.AippInstanceLogBody dtoBody) { + if (dtoBody == null) { + return null; + } + return AippInstLogData.AippInstLogBody.builder() + .logId(dtoBody.getLogId()) + .logData(dtoBody.getLogData()) + .logType(dtoBody.getLogType()) + .createAt(dtoBody.getCreateAt()) + .createUserAccount(dtoBody.getCreateUserAccount()) + .build(); + } + + private AippInstLogData.AippInstLogBody convertQuestion(AippInstLogDataDto.AippInstanceLogBody question) { + if (question == null) { + return null; + } + return this.convertBody(question); + } + + private List convertLogBodies( + List logBodies) { + if (logBodies == null) { + return null; + } + return logBodies.stream().map(this::convertBody).toList(); + } +} diff --git a/app-builder/jane/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/northbound/AppBuilderAppServiceAdapterImpl.java b/app-builder/jane/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/northbound/AppBuilderAppServiceAdapterImpl.java index 645e2e7818..1983b1bd55 100644 --- a/app-builder/jane/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/northbound/AppBuilderAppServiceAdapterImpl.java +++ b/app-builder/jane/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/northbound/AppBuilderAppServiceAdapterImpl.java @@ -32,20 +32,25 @@ public class AppBuilderAppServiceAdapterImpl implements AppBuilderAppServiceAdapter { private final AppBuilderAppService appBuilderAppService; + /** + * 用应用创建服务接口{@link AppBuilderAppService} 构造 {@link AppBuilderAppServiceAdapterImpl}。 + * + * @param appBuilderAppService 表示应用创建服务接口的 {@link AppBuilderAppService}。 + */ public AppBuilderAppServiceAdapterImpl(AppBuilderAppService appBuilderAppService) { this.appBuilderAppService = notNull(appBuilderAppService, "The app builder app service cannot be null."); } @Override public RangedResultSet list(AppQueryParams params, OperationContext context) { - AppQueryCondition appQueryCondition = BeanUtils.copyProperties(params, AppQueryCondition.class); + AppQueryCondition appQueryCondition = this.convertParams(params); if (params.getType() == null) { params.setType("app"); } appQueryCondition.setTenantId(context.getTenantId()); appQueryCondition.setType(params.getType()); - Rsp> rsp = this.appBuilderAppService.list(appQueryCondition, - context, params.getOffset(), params.getLimit()); + Rsp> rsp = + this.appBuilderAppService.list(appQueryCondition, context, params.getOffset(), params.getLimit()); return this.appMetadataDtoConvertToAdapter(rsp.getData()); } @@ -55,4 +60,19 @@ RangedResultSet appMetadataDtoConvertToAdapter(RangedResultSet BeanUtils.copyProperties(appBuilderAppMetadataDto, AppMetadata.class)) .collect(Collectors.toList()), dto.getRange()); } + + private AppQueryCondition convertParams(AppQueryParams params) { + if (params == null) { + return null; + } + return AppQueryCondition.builder() + .ids(params.getIds()) + .name(params.getName()) + .state(params.getState()) + .excludeNames(params.getExcludeNames()) + .offset(Long.valueOf(params.getOffset())) + .limit(params.getLimit()) + .type(params.getType()) + .build(); + } } \ No newline at end of file diff --git a/app-builder/jane/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/northbound/AppChatServiceAdapterImpl.java b/app-builder/jane/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/northbound/AppChatServiceAdapterImpl.java index 347b4919b8..1a72935708 100644 --- a/app-builder/jane/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/northbound/AppChatServiceAdapterImpl.java +++ b/app-builder/jane/plugins/aipp-plugin/src/main/java/modelengine/fit/jober/aipp/northbound/AppChatServiceAdapterImpl.java @@ -13,11 +13,8 @@ import modelengine.fit.jober.aipp.dto.chat.CreateAppChatRequest; import modelengine.fit.jober.aipp.genericable.adapter.AppChatServiceAdapter; import modelengine.fit.jober.aipp.service.AppChatService; - import modelengine.fitframework.annotation.Component; -import modelengine.fitframework.annotation.Fit; import modelengine.fitframework.flowable.Choir; -import modelengine.fitframework.serialization.ObjectSerializer; import java.util.Map; @@ -30,17 +27,19 @@ @Component public class AppChatServiceAdapterImpl implements AppChatServiceAdapter { private final AppChatService appChatService; - private final ObjectSerializer serializer; - public AppChatServiceAdapterImpl(AppChatService appChatService, @Fit(alias = "json") ObjectSerializer serializer) { + /** + * 用历史会话服务接口 {@link AppChatService} 构造 {@link AppChatServiceAdapterImpl}。 + * + * @param appChatService 表示历史会话服务接口的 {@link AppChatService}。 + */ + public AppChatServiceAdapterImpl(AppChatService appChatService) { this.appChatService = notNull(appChatService, "The app chat service must not be null."); - this.serializer = notNull(serializer, "The serializer must not be null."); } @Override public Choir chat(String appId, ChatRequest params, OperationContext operationContext, boolean isDebug) { - CreateAppChatRequest createAppChatRequest = - this.serializer.deserialize(this.serializer.serialize(params), CreateAppChatRequest.class); + CreateAppChatRequest createAppChatRequest = this.convertToCreateAppChatRequest(params); createAppChatRequest.setAppId(appId); return this.appChatService.chat(createAppChatRequest, operationContext, isDebug); } @@ -50,4 +49,27 @@ public Choir restartChat(String currentInstanceId, Map a OperationContext operationContext) { return this.appChatService.restartChat(currentInstanceId, additionalContext, operationContext); } + + private CreateAppChatRequest convertToCreateAppChatRequest(ChatRequest params) { + if (params == null) { + return null; + } + ChatRequest.Context ctx = params.getContext(); + CreateAppChatRequest.Context newCtx = null; + if (ctx != null) { + newCtx = CreateAppChatRequest.Context.builder() + .useMemory(ctx.getUseMemory()) + .userContext(ctx.getUserContext()) + .atAppId(ctx.getAtAppId()) + .atChatId(ctx.getAtChatId()) + .dimension(ctx.getDimension()) + .dimensionId(ctx.getDimensionId()) + .build(); + } + return CreateAppChatRequest.builder() + .chatId(params.getChatId()) + .question(params.getQuestion()) + .context(newCtx) + .build(); + } } diff --git a/app-builder/jane/plugins/aipp-plugin/src/test/java/modelengine/fit/jober/aipp/northbound/AppBuilderAppServiceAdapterImplTest.java b/app-builder/jane/plugins/aipp-plugin/src/test/java/modelengine/fit/jober/aipp/northbound/AppBuilderAppServiceAdapterImplTest.java index 6192346bf0..b58999548b 100644 --- a/app-builder/jane/plugins/aipp-plugin/src/test/java/modelengine/fit/jober/aipp/northbound/AppBuilderAppServiceAdapterImplTest.java +++ b/app-builder/jane/plugins/aipp-plugin/src/test/java/modelengine/fit/jober/aipp/northbound/AppBuilderAppServiceAdapterImplTest.java @@ -7,12 +7,18 @@ package modelengine.fit.jober.aipp.northbound; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import modelengine.fit.jane.common.entity.OperationContext; import modelengine.fit.jane.common.response.Rsp; +import modelengine.fit.jober.aipp.condition.AppQueryCondition; import modelengine.fit.jober.aipp.dto.AppBuilderAppMetadataDto; import modelengine.fit.jober.aipp.dto.chat.AppMetadata; +import modelengine.fit.jober.aipp.dto.chat.AppQueryParams; import modelengine.fit.jober.aipp.service.AppBuilderAppService; import modelengine.fit.jober.common.RangeResult; import modelengine.fit.jober.common.RangedResultSet; @@ -20,7 +26,9 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; /** * {@link AippChatServiceAdapterImpl} 的单元测试。 @@ -60,4 +68,31 @@ void testDtoConvertToAdapter() { .containsExactly("testName1", "testName2"); assertThat(result.getResults()).extracting(AppMetadata::getType).containsExactly("testType1", "testType2"); } + + @Test + @DisplayName("测试查询应用列表") + void shouldOkWhenTestQueryAppList() { + AppQueryParams params = AppQueryParams.builder() + .ids(Arrays.asList("id1", "id2")) + .excludeNames(Arrays.asList("name1", "name2")) + .name("name") + .state("active") + .offset(100) + .limit(20) + .type("app") + .build(); + OperationContext operationContext = new OperationContext(); + operationContext.setTenantId("tenantId"); + List metaDtoList = new ArrayList<>(); + metaDtoList.add(AppBuilderAppMetadataDto.builder().name("name1").build()); + Rsp> rsp = + Rsp.ok(RangedResultSet.create(metaDtoList, params.getOffset(), params.getLimit(), metaDtoList.size())); + when(this.appBuilderAppService.list(any(AppQueryCondition.class), + any(OperationContext.class), + anyLong(), + anyInt())).thenReturn(rsp); + RangedResultSet resultSet = this.appBuilderAppServiceAdapterImpl.list(params, operationContext); + assertThat(resultSet.getResults().size()).isEqualTo(1); + assertThat(resultSet.getResults().get(0).getName()).isEqualTo("name1"); + } } \ No newline at end of file diff --git a/app-builder/jane/plugins/aipp-plugin/src/test/java/modelengine/fit/jober/aipp/northbound/AppChatServiceAdapterImplTest.java b/app-builder/jane/plugins/aipp-plugin/src/test/java/modelengine/fit/jober/aipp/northbound/AppChatServiceAdapterImplTest.java new file mode 100644 index 0000000000..ee858aef60 --- /dev/null +++ b/app-builder/jane/plugins/aipp-plugin/src/test/java/modelengine/fit/jober/aipp/northbound/AppChatServiceAdapterImplTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.jober.aipp.northbound; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import modelengine.fit.jane.common.entity.OperationContext; +import modelengine.fit.jober.aipp.dto.chat.ChatRequest; +import modelengine.fit.jober.aipp.dto.chat.CreateAppChatRequest; +import modelengine.fit.jober.aipp.service.AppChatService; +import modelengine.fitframework.flowable.Choir; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * {@link AppChatServiceAdapterImpl} 的单元测试。 + * + * @author 陈潇文 + * @since 2025-07-15 + */ +public class AppChatServiceAdapterImplTest { + private final AppChatService appChatService = mock(AppChatService.class); + private final AppChatServiceAdapterImpl appChatServiceAdapter = + new AppChatServiceAdapterImpl(appChatService); + + @Test + @DisplayName("测试对话") + void shouldOkWhenTestChat() { + String appId = "appId"; + ChatRequest params = ChatRequest.builder().chatId("chatId").question("q").build(); + Map userContext = new HashMap<>(); + userContext.put("a", "aaa"); + ChatRequest.Context context = ChatRequest.Context.builder() + .atChatId("atChatId") + .atAppId("atAppId") + .useMemory(true) + .dimension("dimension") + .dimensionId("dimensionId") + .userContext(userContext) + .build(); + params.setContext(context); + OperationContext operationContext = new OperationContext(); + boolean isDebug = true; + when(this.appChatService.chat(any(CreateAppChatRequest.class), + any(OperationContext.class), + anyBoolean())).thenReturn(mock(Choir.class)); + // when + Choir objectChoir = Assertions.assertDoesNotThrow(() -> this.appChatServiceAdapter.chat(appId, + params, + operationContext, + isDebug)); + // then + Assertions.assertNotNull(objectChoir); + } +} diff --git a/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/aipplog/AippInstLogData.java b/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/aipplog/AippInstLogData.java new file mode 100644 index 0000000000..e3f67bada3 --- /dev/null +++ b/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/aipplog/AippInstLogData.java @@ -0,0 +1,52 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fit.jober.aipp.dto.aipplog; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * aipp 实例历史记录数据。 + * + * @author 陈潇文 + * @since 2025-07-16 + */ +@AllArgsConstructor +@Data +@Builder +@NoArgsConstructor +public class AippInstLogData { + private String aippId; + private String version; + private String instanceId; + private String status; + private String appName; + private String appIcon; + private LocalDateTime createAt; + private AippInstLogBody question; + private List instanceLogBodies; + + /** + * 转换实例日志为实例日志体。 + */ + @AllArgsConstructor + @Data + @Builder + @NoArgsConstructor + public static class AippInstLogBody { + private long logId; + private String logData; + private String logType; + private LocalDateTime createAt; + private String createUserAccount; + } +} diff --git a/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/chat/AppQueryParams.java b/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/chat/AppQueryParams.java index 93c3b68802..c0d582193a 100644 --- a/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/chat/AppQueryParams.java +++ b/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/chat/AppQueryParams.java @@ -26,9 +26,9 @@ @NoArgsConstructor @AllArgsConstructor public class AppQueryParams { - @RequestQuery(name = "appIds", required = false) + @RequestQuery(name = "ids", required = false) @Property(description = "查询的id列表") - private List appIds; + private List ids; @RequestQuery(name = "name", required = false) @Property(description = "查询的名字") diff --git a/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/chat/ChatDeleteParams.java b/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/chat/ChatDeleteParams.java index f42f5f8816..068fd33648 100644 --- a/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/chat/ChatDeleteParams.java +++ b/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/chat/ChatDeleteParams.java @@ -24,11 +24,11 @@ @NoArgsConstructor @AllArgsConstructor public class ChatDeleteParams { - @RequestQuery(value = "app_id", required = false) + @RequestQuery(value = "appId", required = false) @Property(description = "应用的唯一标识符") private String appId; - @RequestQuery(value = "chat_id", required = false) + @RequestQuery(value = "chatId", required = false) @Property(description = "要删除的聊天会话的唯一标识符,若没有指定,则全部删除") private String chatId; } diff --git a/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/chat/ChatQueryParams.java b/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/chat/ChatQueryParams.java index 3a6d477a78..da050be0da 100644 --- a/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/chat/ChatQueryParams.java +++ b/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/chat/ChatQueryParams.java @@ -12,7 +12,6 @@ import lombok.NoArgsConstructor; import modelengine.fit.http.annotation.RequestQuery; import modelengine.fitframework.annotation.Property; -import modelengine.fitframework.util.StringUtils; /** * 会话历史的查询条件参数。 @@ -26,10 +25,10 @@ @AllArgsConstructor public class ChatQueryParams { @Property(description = "aipp的唯一标识符", name = "aipp_id") - private String aippId = StringUtils.EMPTY; + private String aippId; @Property(description = "aipp的版本", name = "aipp_version") - private String aippVersion = StringUtils.EMPTY; + private String aippVersion; @RequestQuery("offset") @Property(description = "偏移量", name = "offset") @@ -44,7 +43,7 @@ public class ChatQueryParams { private String appId; @Property(description = "应用版本", name = "app_version") - private String appVersion = StringUtils.EMPTY; + private String appVersion; @RequestQuery("appState") @Property(description = "应用状态", defaultValue = "active", name = "appState") diff --git a/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/chat/ChatRequest.java b/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/chat/ChatRequest.java index 6130199491..3f728feeaf 100644 --- a/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/chat/ChatRequest.java +++ b/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/dto/chat/ChatRequest.java @@ -10,7 +10,6 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import modelengine.fit.jober.aipp.constants.AippConst; import modelengine.fitframework.annotation.Property; import java.util.Map; @@ -49,10 +48,10 @@ public static class Context { @Property(description = "用户自定义输入", name = "userContext") private Map userContext; - @Property(description = "at其它应用", name = AippConst.BS_AT_APP_ID) + @Property(description = "at其它应用", name = "atAppId") private String atAppId; - @Property(description = "at其它应用的对话", name = AippConst.BS_AT_CHAT_ID) + @Property(description = "at其它应用的对话", name = "atChatId") private String atChatId; @Property(description = "产品的信息", name = "dimension") diff --git a/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/genericable/adapter/AippLogServiceAdapter.java b/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/genericable/adapter/AippLogServiceAdapter.java new file mode 100644 index 0000000000..e09e82e6ae --- /dev/null +++ b/app-builder/jane/services/aipp-genericable/src/main/java/modelengine/fit/jober/aipp/genericable/adapter/AippLogServiceAdapter.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.jober.aipp.genericable.adapter; + +import modelengine.fit.jane.common.entity.OperationContext; +import modelengine.fit.jober.aipp.dto.aipplog.AippInstLogData; + +import java.util.List; + +/** + * aipp 实例历史记录适配器类。 + * + * @author 陈潇文 + * @since 2025-07-08 + */ +public interface AippLogServiceAdapter { + /** + * 查询指定 chatId 的最近 5 次实例记录。 + * + * @param chatId 表示会话 id 的 {@link String}。 + * @param context 表示登录信息的 {@link OperationContext}。 + * @param appId 表示应用 id 的 {@link String}。 + * @return 表示 log 数据的 {@link List}{@code <}{@link AippInstLogData}{@code >}。 + */ + List queryChatRecentChatLog(String chatId, String appId, OperationContext context); +} diff --git a/app-builder/jane/services/aipp-genericable/src/test/java/modelengine/fit/jober/aipp/dto/chat/AppQueryParamsTest.java b/app-builder/jane/services/aipp-genericable/src/test/java/modelengine/fit/jober/aipp/dto/chat/AppQueryParamsTest.java index 657b9ed30f..9aeb5cd639 100644 --- a/app-builder/jane/services/aipp-genericable/src/test/java/modelengine/fit/jober/aipp/dto/chat/AppQueryParamsTest.java +++ b/app-builder/jane/services/aipp-genericable/src/test/java/modelengine/fit/jober/aipp/dto/chat/AppQueryParamsTest.java @@ -25,15 +25,15 @@ class AppQueryParamsTest { @DisplayName("用构建器构建查询应用状态类时,返回成功") void constructAppQueryParams() { AppQueryParams condition = AppQueryParams.builder() - .appIds(Arrays.asList("id1", "id2")) + .ids(Arrays.asList("id1", "id2")) .name("AppName") .state("ACTIVE") .excludeNames(Arrays.asList("Exclude1", "Exclude2")) .build(); assertThat(condition).isNotNull(); - assertThat(condition.getAppIds()).hasSize(2); - assertThat(condition.getAppIds().get(0)).isEqualTo("id1"); + assertThat(condition.getIds()).hasSize(2); + assertThat(condition.getIds().get(0)).isEqualTo("id1"); assertThat(condition.getName()).isEqualTo("AppName"); assertThat(condition.getState()).isEqualTo("ACTIVE"); assertThat(condition.getExcludeNames()).hasSize(2); diff --git a/app-builder/plugins/aipp-northbound/pom.xml b/app-builder/plugins/aipp-northbound/pom.xml index 746784b44b..c57c14babc 100644 --- a/app-builder/plugins/aipp-northbound/pom.xml +++ b/app-builder/plugins/aipp-northbound/pom.xml @@ -57,6 +57,10 @@ modelengine.fit.jade.service voice-service + + modelengine.jade.service + app-engine-base-service + diff --git a/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AippLogController.java b/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AippLogController.java new file mode 100644 index 0000000000..ea85471bf4 --- /dev/null +++ b/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AippLogController.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.jade.aipp.northbound.controller; + +import modelengine.fit.http.annotation.GetMapping; +import modelengine.fit.http.annotation.PathVariable; +import modelengine.fit.http.annotation.RequestMapping; +import modelengine.fit.http.server.HttpClassicServerRequest; +import modelengine.fit.jane.common.controller.AbstractController; +import modelengine.fit.jane.common.response.Rsp; +import modelengine.fit.jane.task.gateway.Authenticator; +import modelengine.fit.jober.aipp.dto.aipplog.AippInstLogData; +import modelengine.fit.jober.aipp.genericable.adapter.AippLogServiceAdapter; +import modelengine.fitframework.annotation.Component; + +import java.util.List; + +/** + * aipp 实例日志管理接口。 + * + * @author 陈潇文 + * @since 2025-07-08 + */ +@Component +@RequestMapping(path = "/api/app/v1/tenants/{tenant_id}/log", group = "aipp 实例日志管理北向接口") +public class AippLogController extends AbstractController { + private final AippLogServiceAdapter aippLogServiceAdapter; + + /** + * 用身份校验器 {@link Authenticator} 和 aipp 实例历史记录适配器类 {@link AippLogServiceAdapter} 构造 {@link AippLogController}。 + * + * @param authenticator 表示身份校验器的 {@link Authenticator}。 + * @param aippLogServiceAdapter 表示 aipp 实例历史记录适配器类的 {@link AippLogServiceAdapter}。 + */ + public AippLogController(Authenticator authenticator, AippLogServiceAdapter aippLogServiceAdapter) { + super(authenticator); + this.aippLogServiceAdapter = aippLogServiceAdapter; + } + + /** + * 根据 chatId 查询历史记录。 + * + * @param httpRequest 表示 Http 请求体的 {@link HttpClassicServerRequest}。 + * @param tenantId 表示租户 id 的 {@link String}。 + * @param chatId 表示会话 id 的 {@link String}。 + * @param appId 表示应用 id 的 {@link String}。 + * @return 表示会话历史记录的 {@link Rsp}{@code <}{@link List}{@code <}{@link AippInstLogData}{@code >>}。 + */ + @GetMapping(path = "/app/{app_id}/chat/{chat_id}", description = "指定chatId查询实例历史记录(查询最近10个实例)") + public Rsp> queryChatRecentChatLog(HttpClassicServerRequest httpRequest, + @PathVariable("tenant_id") String tenantId, @PathVariable("app_id") String appId, + @PathVariable("chat_id") String chatId) { + return Rsp.ok(this.aippLogServiceAdapter.queryChatRecentChatLog(chatId, + appId, + this.contextOf(httpRequest, tenantId))); + } +} diff --git a/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AppBuilderAppController.java b/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AppBuilderAppController.java index 871b5e3cf3..a0be162c28 100644 --- a/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AppBuilderAppController.java +++ b/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AppBuilderAppController.java @@ -37,7 +37,7 @@ * @since 2024-12-17 */ @Component -@RequestMapping(path = "/v1/tenants/{tenantId}/apps", group = "应用信息管理接口") +@RequestMapping(path = "/api/app/v1/tenants/{tenantId}/apps", group = "应用信息管理接口") public class AppBuilderAppController extends AbstractController { private final List excludeNames; private final AppBuilderAppServiceAdapter appService; diff --git a/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AppBuilderPromptController.java b/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AppBuilderPromptController.java index 804fc4d92e..0b2421468c 100644 --- a/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AppBuilderPromptController.java +++ b/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AppBuilderPromptController.java @@ -31,7 +31,7 @@ * @since 2024-12-12 */ @Component -@RequestMapping(path = "/v1/tenants/{tenantId}/apps/{appId}/prompt", group = "灵感大全管理接口") +@RequestMapping(path = "/api/app/v1/tenants/{tenantId}/apps/{appId}/prompt", group = "灵感大全管理接口") public class AppBuilderPromptController extends AbstractController { private final AppBuilderPromptServiceAdapter service; diff --git a/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AppChatController.java b/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AppChatController.java index bd1ddab75c..54d421b5fa 100644 --- a/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AppChatController.java +++ b/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AppChatController.java @@ -48,7 +48,7 @@ * @since 2024-12-12 */ @Component -@RequestMapping(path = "/v1/tenants/{tenantId}/chats", group = "应用对话管理接口") +@RequestMapping(path = "/api/app/v1/tenants/{tenantId}/chats", group = "应用对话管理接口") public class AppChatController extends AbstractController { private final AppChatServiceAdapter appChatService; private final AippChatServiceAdapter aippChatService; @@ -101,7 +101,6 @@ public Choir chat(HttpClassicServerRequest httpRequest, @CarverSpan(value = "operation.appChat.restartChat") @PostMapping(path = "/instances/{currentInstanceId}", summary = "重新对话", description = "该接口可以重新发起指定会话,需要指定需要重新发起会话的实例id,同时可添加附加信息") - @ResponseStatus(HttpResponseStatus.RESET_CONTENT) public Choir restartChat(HttpClassicServerRequest httpRequest, @PathVariable("tenantId") @Property(description = "租户的唯一标识符") String tenantId, @PathVariable("currentInstanceId") @Property(description = "需要重新发起会话的实例的唯一标识符") diff --git a/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AudioController.java b/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AudioController.java index eb784b8c1c..265f1e2c27 100644 --- a/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AudioController.java +++ b/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/AudioController.java @@ -27,7 +27,7 @@ * @since 2024-12-17 */ @Component -@RequestMapping(path = "/v1/tenants/{tenantId}/translation", group = "语音文字互转接口") +@RequestMapping(path = "/api/app/v1/tenants/{tenantId}/translation", group = "语音文字互转接口") public class AudioController extends AbstractController { private final VoiceService voiceService; diff --git a/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/FileController.java b/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/FileController.java index bbcd7f60ae..8878702f27 100644 --- a/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/FileController.java +++ b/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/FileController.java @@ -41,7 +41,7 @@ * @since 2024-12-16 */ @Component -@RequestMapping(path = "/v1/tenants/{tenantId}/file", group = "文件上传接口") +@RequestMapping(path = "/api/app/v1/tenants/{tenantId}/file", group = "文件上传接口") public class FileController extends AbstractController { private final FileServiceAdapter fileService; @@ -69,7 +69,7 @@ public FileController(Authenticator authenticator, FileServiceAdapter fileServic @PostMapping(summary = "上传文件", description = "该接口可以往指定应用上传文件。") @ResponseStatus(HttpResponseStatus.CREATED) public Rsp uploadFile(HttpClassicServerRequest httpRequest, - @PathVariable("tenantId") String tenantId, @RequestQuery(value = "app_id", required = false) String appId, + @PathVariable("tenantId") String tenantId, @RequestQuery(value = "app_id", required = true) String appId, PartitionedEntity receivedFile) throws IOException { List entityList = receivedFile.entities().stream().filter(NamedEntity::isFile).collect(Collectors.toList()); diff --git a/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/UserFeedbackController.java b/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/UserFeedbackController.java new file mode 100644 index 0000000000..5eafbde3e6 --- /dev/null +++ b/app-builder/plugins/aipp-northbound/src/main/java/modelengine/fit/jade/aipp/northbound/controller/UserFeedbackController.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.fit.jade.aipp.northbound.controller; + +import modelengine.fit.http.annotation.GetMapping; +import modelengine.fit.http.annotation.PatchMapping; +import modelengine.fit.http.annotation.PathVariable; +import modelengine.fit.http.annotation.PostMapping; +import modelengine.fit.http.annotation.RequestBody; +import modelengine.fit.http.annotation.RequestMapping; +import modelengine.fit.jane.common.controller.AbstractController; +import modelengine.fit.jane.task.gateway.Authenticator; +import modelengine.fitframework.annotation.Component; +import modelengine.jade.app.engine.base.dto.UsrFeedbackDto; +import modelengine.jade.app.engine.base.service.UsrFeedbackService; + +/** + * 用户反馈北向接口。 + * + * @author 陈潇文 + * @since 2025-07-18 + */ +@Component +@RequestMapping(path = "/api/app/v1/aipp/user") +public class UserFeedbackController extends AbstractController { + private final UsrFeedbackService usrFeedbackService; + + /** + * 用身份校验器 {@link Authenticator} 和 Aipp 用户反馈功能接口 {@link UsrFeedbackService} 构造 {@link UserFeedbackController}。 + * + * @param authenticator 表示身份校验器的 {@link Authenticator}。 + * @param usrFeedbackService 表示 Aipp 用户反馈功能接口的 {@link UsrFeedbackService}。 + */ + public UserFeedbackController(Authenticator authenticator, UsrFeedbackService usrFeedbackService) { + super(authenticator); + this.usrFeedbackService = usrFeedbackService; + } + + /** + * 创建用户反馈记录。 + * + * @param usrFeedbackDto 表示用户反馈消息体的 {@link UsrFeedbackDto}。 + */ + @PostMapping("/feedback") + public void createUsrFeedback(@RequestBody UsrFeedbackDto usrFeedbackDto) { + usrFeedbackService.create(usrFeedbackDto); + } + + /** + * 更新用户反馈信息。 + * + * @param usrFeedbackDto 表示用户反馈消息体的 {@link UsrFeedbackDto}。 + * @param instanceId 表示对话实例 Id 的 {@link String}。 + */ + @PatchMapping("/feedback/{instanceId}") + public void updateUsrFeedback(@PathVariable("instanceId") String instanceId, + @RequestBody UsrFeedbackDto usrFeedbackDto) { + usrFeedbackService.updateOne(instanceId, usrFeedbackDto); + } + + /** + * 通过 LogId 获取对话信息列表。 + * + * @param instanceId 表示对话实例 Id 的 {@link String}。 + * @return 表示对话信息的 {@link UsrFeedbackDto}。 + */ + @GetMapping("/feedback/{instanceId}") + public UsrFeedbackDto getAllAnswerByInstanceId(@PathVariable("instanceId") String instanceId) { + return usrFeedbackService.getUsrFeedbackByInstanceId(instanceId); + } +} diff --git a/common/plugins/apikey-auth-default/pom.xml b/common/plugins/apikey-auth-default/pom.xml new file mode 100644 index 0000000000..8823507aeb --- /dev/null +++ b/common/plugins/apikey-auth-default/pom.xml @@ -0,0 +1,86 @@ + + + 4.0.0 + + + modelengine.fit.jade.plugin + base-plugin-parent + 1.0.0-SNAPSHOT + + + apikey-auth-default + + + 17 + 17 + UTF-8 + + + + + modelengine.fit.jade.service + apikey-service + 1.0.0-SNAPSHOT + + + org.fitframework + fit-api + + + org.junit.jupiter + junit-jupiter + + + org.assertj + assertj-core + + + + + + + org.fitframework + fit-build-maven-plugin + ${fit.version} + + system + 4 + + + + build-plugin + + build-plugin + + + + package-plugin + + package-plugin + + + + + + org.apache.maven.plugins + maven-antrun-plugin + ${maven.antrun.version} + + + install + + + + + + + run + + + + + + + \ No newline at end of file diff --git a/common/plugins/apikey-auth-default/src/main/java/modelengine/jade/apikey/impl/DefaultApikeyAuthServiceImpl.java b/common/plugins/apikey-auth-default/src/main/java/modelengine/jade/apikey/impl/DefaultApikeyAuthServiceImpl.java new file mode 100644 index 0000000000..68607b78d8 --- /dev/null +++ b/common/plugins/apikey-auth-default/src/main/java/modelengine/jade/apikey/impl/DefaultApikeyAuthServiceImpl.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.jade.apikey.impl; + +import modelengine.fitframework.annotation.Component; +import modelengine.jade.apikey.ApikeyAuthService; + +/** + * 表示北向接口 Apikey 鉴权的默认实现。 + * + * @author 陈潇文 + * @since 2025-07-07 + */ +@Component +public class DefaultApikeyAuthServiceImpl implements ApikeyAuthService { + @Override + public boolean authApikeyInfo(String apikey) { + return true; + } +} diff --git a/common/plugins/apikey-auth-default/src/main/resources/application.yml b/common/plugins/apikey-auth-default/src/main/resources/application.yml new file mode 100644 index 0000000000..34efb2f764 --- /dev/null +++ b/common/plugins/apikey-auth-default/src/main/resources/application.yml @@ -0,0 +1,4 @@ +fit: + beans: + packages: + - 'modelengine.jade.apikey.impl' \ No newline at end of file diff --git a/common/plugins/apikey-auth-default/src/test/java/modelengine/jade/apikey/DefaultApikeyAuthServiceImplTest.java b/common/plugins/apikey-auth-default/src/test/java/modelengine/jade/apikey/DefaultApikeyAuthServiceImplTest.java new file mode 100644 index 0000000000..718b4e5f9e --- /dev/null +++ b/common/plugins/apikey-auth-default/src/test/java/modelengine/jade/apikey/DefaultApikeyAuthServiceImplTest.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.jade.apikey; + +import modelengine.jade.apikey.impl.DefaultApikeyAuthServiceImpl; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * 表示 {@link DefaultApikeyAuthServiceImpl} 的测试类。 + * + * @author 陈潇文 + * @since 2025-07-07 + */ +public class DefaultApikeyAuthServiceImplTest { + @Test + void testAuthApikeyInfo() { + DefaultApikeyAuthServiceImpl service = new DefaultApikeyAuthServiceImpl(); + assertThat(service.authApikeyInfo(null)).isTrue(); + assertThat(service.authApikeyInfo("")).isTrue(); + assertThat(service.authApikeyInfo("any-string")).isTrue(); + assertThat(service.authApikeyInfo("Bearer ME-sk-1234567890abcdef-abcdef1234567890abcdef1234567890")).isTrue(); + } +} diff --git a/common/plugins/authentication-default/pom.xml b/common/plugins/authentication-default/pom.xml index 988eb807fc..a594183692 100644 --- a/common/plugins/authentication-default/pom.xml +++ b/common/plugins/authentication-default/pom.xml @@ -85,32 +85,6 @@ - - org.fitframework - fit-dependency-maven-plugin - ${fit.version} - - - dependency - compile - - dependency - - - - - - org.apache.maven.plugins - maven-jar-plugin - ${maven.jar.version} - - - - FIT Lab - - - - org.apache.maven.plugins maven-antrun-plugin diff --git a/common/plugins/http-interceptor/pom.xml b/common/plugins/http-interceptor/pom.xml index 3993e40b6a..1cc76a8d45 100644 --- a/common/plugins/http-interceptor/pom.xml +++ b/common/plugins/http-interceptor/pom.xml @@ -35,11 +35,15 @@ modelengine.fit.jade.service jade-common-service - modelengine.fit.jade.service authentication-service + + modelengine.fit.jade.service + apikey-service + 1.0.0-SNAPSHOT + @@ -98,32 +102,6 @@ - - org.fitframework - fit-dependency-maven-plugin - ${fit.version} - - - dependency - compile - - dependency - - - - - - org.apache.maven.plugins - maven-jar-plugin - ${maven.jar.version} - - - - FIT Lab - - - - org.apache.maven.plugins maven-antrun-plugin diff --git a/common/plugins/http-interceptor/src/main/java/modelengine/jade/common/filter/support/LoginFilter.java b/common/plugins/http-interceptor/src/main/java/modelengine/jade/common/filter/support/LoginFilter.java index aa0878014a..be8bf6a006 100644 --- a/common/plugins/http-interceptor/src/main/java/modelengine/jade/common/filter/support/LoginFilter.java +++ b/common/plugins/http-interceptor/src/main/java/modelengine/jade/common/filter/support/LoginFilter.java @@ -32,20 +32,15 @@ */ @Component public class LoginFilter implements HttpServerFilter { - private final List matchPatterns; - private final List mismatchPatterns; private final AuthenticationService authenticationService; private static final Logger log = Logger.get(LoginFilter.class); /** - * 根据配置创建过滤器的实例。 + * 用用户认证服务 {@link AuthenticationService} 构造 {@link LoginFilter}。 * * @param authenticationService 表示用户认证服务的 {@link AuthenticationService}。 */ public LoginFilter(AuthenticationService authenticationService) { - // 待优化为配置化 - this.matchPatterns = Collections.singletonList("/**"); - this.mismatchPatterns = Collections.emptyList(); this.authenticationService = Validation.notNull(authenticationService, "The auth service cannot be null."); } @@ -61,12 +56,12 @@ public int priority() { @Override public List matchPatterns() { - return this.matchPatterns; + return Collections.singletonList("/**"); } @Override public List mismatchPatterns() { - return this.mismatchPatterns; + return Collections.singletonList("/api/app/v1/**"); } @Override diff --git a/common/plugins/http-interceptor/src/main/java/modelengine/jade/common/filter/support/NorthFilter.java b/common/plugins/http-interceptor/src/main/java/modelengine/jade/common/filter/support/NorthFilter.java new file mode 100644 index 0000000000..6ea3a30110 --- /dev/null +++ b/common/plugins/http-interceptor/src/main/java/modelengine/jade/common/filter/support/NorthFilter.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.jade.common.filter.support; + +import modelengine.fit.http.protocol.HttpResponseStatus; +import modelengine.fit.http.server.HttpClassicServerRequest; +import modelengine.fit.http.server.HttpClassicServerResponse; +import modelengine.fit.http.server.HttpServerFilter; +import modelengine.fit.http.server.HttpServerFilterChain; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.Order; +import modelengine.fitframework.annotation.Scope; +import modelengine.fitframework.inspection.Validation; +import modelengine.fitframework.log.Logger; +import modelengine.jade.apikey.ApikeyAuthService; +import modelengine.jade.authentication.context.HttpRequestUtils; +import modelengine.jade.authentication.context.UserContext; +import modelengine.jade.authentication.context.UserContextHolder; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +/** + * 用于北向接口的过滤器类。 + * + * @author 陈潇文 + * @since 2025-07-07 + */ +@Component +public class NorthFilter implements HttpServerFilter { + private static final Logger log = Logger.get(NorthFilter.class); + private static final String USER_NAME_PREFIX = "sys_api_"; + private static final int ME_SK_START_POS = 13; + private static final int ME_SK_END_POS = 21; + + private final ApikeyAuthService apikeyAuthService; + + /** + * 用 apikey 鉴权服务 {@link ApikeyAuthService} 构造 {@link NorthFilter}。 + * + * @param apikeyAuthService 表示 apikey 鉴权服务的 {@link ApikeyAuthService}。 + */ + public NorthFilter(ApikeyAuthService apikeyAuthService) { + this.apikeyAuthService = Validation.notNull(apikeyAuthService, "The auth service cannot be null."); + } + + @Override + public String name() { + return "NorthFilter"; + } + + @Override + public int priority() { + return Order.HIGHEST; + } + + @Override + public List matchPatterns() { + return Collections.singletonList("/api/app/v1/**"); + } + + @Override + public List mismatchPatterns() { + return Collections.emptyList(); + } + + @Override + public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse response, + HttpServerFilterChain chain) { + Optional token = request.headers().first("Authorization"); + log.info("Received request with Authorization token."); + + if (token.isEmpty() || !this.apikeyAuthService.authApikeyInfo(token.get())) { + // 认证失败,返回 401 错误 + response.statusCode(HttpResponseStatus.UNAUTHORIZED.statusCode()); + log.error("Authentication failed: Token is null or invalid."); + response.send(); + return; + } + + String userName = this.generateUniqueNameForApiKey(token.get()); + + UserContext operationContext = new UserContext(userName, + HttpRequestUtils.getUserIp(request), + HttpRequestUtils.getAcceptLanguages(request)); + UserContextHolder.apply(operationContext, () -> chain.doFilter(request, response)); + } + + @Override + public Scope scope() { + return Scope.GLOBAL; + } + + private String generateUniqueNameForApiKey(String apiKey) { + return USER_NAME_PREFIX + apiKey.substring(ME_SK_START_POS, ME_SK_END_POS); + } +} diff --git a/common/plugins/pom.xml b/common/plugins/pom.xml index ea79e2e3e6..f69d4521f7 100644 --- a/common/plugins/pom.xml +++ b/common/plugins/pom.xml @@ -14,9 +14,41 @@ pom + apikey-auth-default authentication-default http-interceptor schema-generator schema-validator-everit-h1 + + + + + org.fitframework + fit-dependency-maven-plugin + ${fit.version} + + + dependency + compile + + dependency + + + + + + org.apache.maven.plugins + maven-jar-plugin + ${maven.jar.version} + + + + FIT Lab + + + + + + \ No newline at end of file diff --git a/common/plugins/schema-generator/pom.xml b/common/plugins/schema-generator/pom.xml index 42c72c7fba..a912ae43b0 100644 --- a/common/plugins/schema-generator/pom.xml +++ b/common/plugins/schema-generator/pom.xml @@ -76,18 +76,6 @@ - - org.apache.maven.plugins - maven-jar-plugin - ${maven.jar.version} - - - - FIT Lab - - - - org.apache.maven.plugins maven-antrun-plugin diff --git a/common/plugins/schema-validator-everit-h1/pom.xml b/common/plugins/schema-validator-everit-h1/pom.xml index c8b7460756..a025f551e2 100644 --- a/common/plugins/schema-validator-everit-h1/pom.xml +++ b/common/plugins/schema-validator-everit-h1/pom.xml @@ -80,18 +80,6 @@ - - org.apache.maven.plugins - maven-jar-plugin - ${maven.jar.version} - - - - FIT Lab - - - - org.apache.maven.plugins maven-antrun-plugin diff --git a/common/services/apikey-service/pom.xml b/common/services/apikey-service/pom.xml new file mode 100644 index 0000000000..c1b068a37d --- /dev/null +++ b/common/services/apikey-service/pom.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + + + modelengine.fit.jade.service + common-service-parent + 1.0.0-SNAPSHOT + + + apikey-service + + + 17 + 17 + UTF-8 + + \ No newline at end of file diff --git a/common/services/apikey-service/src/main/java/modelengine/jade/apikey/ApikeyAuthService.java b/common/services/apikey-service/src/main/java/modelengine/jade/apikey/ApikeyAuthService.java new file mode 100644 index 0000000000..29ddce2594 --- /dev/null +++ b/common/services/apikey-service/src/main/java/modelengine/jade/apikey/ApikeyAuthService.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + */ + +package modelengine.jade.apikey; + +/** + * apikey 鉴权服务。 + * + * @author 陈潇文 + * @since 2025-07-07 + */ +public interface ApikeyAuthService { + /** + * api key 鉴权。 + * + * @param apikey 表示 api key 的 {@link String}。 + * @return boolean 表示鉴权是否成功的 {@code boolean}。 + */ + boolean authApikeyInfo(String apikey); +} diff --git a/common/services/authentication-service/pom.xml b/common/services/authentication-service/pom.xml index afdaa1c323..3a7efcaa7a 100644 --- a/common/services/authentication-service/pom.xml +++ b/common/services/authentication-service/pom.xml @@ -24,48 +24,4 @@ fit-http-classic - - - - - org.fitframework - fit-build-maven-plugin - ${fit.version} - - - build-service - - build-service - - - - - - org.fitframework - fit-dependency-maven-plugin - ${fit.version} - - - dependency - compile - - dependency - - - - - - org.apache.maven.plugins - maven-jar-plugin - ${maven.jar.version} - - - - FIT Lab - - - - - - \ No newline at end of file diff --git a/common/services/common-service/pom.xml b/common/services/common-service/pom.xml index 19903aa809..510da44cd3 100644 --- a/common/services/common-service/pom.xml +++ b/common/services/common-service/pom.xml @@ -29,48 +29,4 @@ authentication-service - - - - - org.fitframework - fit-build-maven-plugin - ${fit.version} - - - build-service - - build-service - - - - - - org.fitframework - fit-dependency-maven-plugin - ${fit.version} - - - dependency - compile - - dependency - - - - - - org.apache.maven.plugins - maven-jar-plugin - ${maven.jar.version} - - - - FIT Lab - - - - - - \ No newline at end of file diff --git a/common/services/oms-service/pom.xml b/common/services/oms-service/pom.xml index 0ada5c1a66..f030c2b497 100644 --- a/common/services/oms-service/pom.xml +++ b/common/services/oms-service/pom.xml @@ -26,48 +26,4 @@ fit-http-protocol - - - - - org.fitframework - fit-build-maven-plugin - ${fit.version} - - - build-service - - build-service - - - - - - org.fitframework - fit-dependency-maven-plugin - ${fit.version} - - - dependency - compile - - dependency - - - - - - org.apache.maven.plugins - maven-jar-plugin - ${maven.jar.version} - - - - FIT lab - - - - - - \ No newline at end of file diff --git a/common/services/pom.xml b/common/services/pom.xml index 9d22d314d9..c20442aa94 100644 --- a/common/services/pom.xml +++ b/common/services/pom.xml @@ -14,9 +14,54 @@ pom + apikey-service authentication-service common-service oms-service schema-service + + + + + org.fitframework + fit-build-maven-plugin + ${fit.version} + + + build-service + + build-service + + + + + + org.fitframework + fit-dependency-maven-plugin + ${fit.version} + + + dependency + compile + + dependency + + + + + + org.apache.maven.plugins + maven-jar-plugin + ${maven.jar.version} + + + + FIT Lab + + + + + + \ No newline at end of file