feat: implement agent core components including planner, executor, orchestrator, and memory management while refactoring tool result presentation
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
package dev.sonpx.loyalty.mcp.aspect;
|
||||
|
||||
import dev.sonpx.loyalty.mcp.model.Result;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Global exception handler for @McpTool methods using AOP.
|
||||
* Prevents internal stack traces from leaking to the MCP Client.
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@Component
|
||||
public class GlobalToolExceptionHandlerAspect {
|
||||
|
||||
@Around("@annotation(org.springframework.ai.mcp.annotation.McpTool)")
|
||||
public Object handleException(ProceedingJoinPoint pjp) throws Throwable {
|
||||
try {
|
||||
return pjp.proceed();
|
||||
} catch (Exception e) {
|
||||
log.error("Global AOP exception caught during execution of MCP tool {}: {}", pjp.getSignature().getName(), e.getMessage());
|
||||
// Return a safe Result to prevent stack traces from leaking to the agent
|
||||
return Result.of(null, "Lỗi hệ thống khi gọi tool tại MCP server. Không thể xử lý yêu cầu. Vui lòng báo cáo lỗi này.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,16 +3,22 @@ package dev.sonpx.loyalty.mcp.config;
|
||||
import static org.springframework.security.oauth2.client.web.client.RequestAttributeClientRegistrationIdResolver.clientRegistrationId;
|
||||
import static org.springframework.security.oauth2.client.web.client.RequestAttributePrincipalResolver.principal;
|
||||
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import dev.sonpx.loyalty.mcp.reward.client.CampaignClient;
|
||||
import dev.sonpx.loyalty.mcp.reward.client.CampaignRuleClient;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.client.BufferingClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
|
||||
import org.springframework.security.oauth2.client.web.client.OAuth2ClientHttpRequestInterceptor;
|
||||
import org.springframework.security.oauth2.client.web.client.RequestAttributeClientRegistrationIdResolver;
|
||||
import org.springframework.security.oauth2.client.web.client.RequestAttributePrincipalResolver;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.support.RestClientAdapter;
|
||||
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
|
||||
@@ -20,6 +26,7 @@ import org.springframework.web.service.invoker.HttpServiceProxyFactory;
|
||||
/**
|
||||
* Created by SonPhung on Sunday, 19-Jul-2026
|
||||
**/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class RestClientConfig {
|
||||
|
||||
@@ -35,15 +42,29 @@ public class RestClientConfig {
|
||||
|
||||
return RestClient.builder()
|
||||
.baseUrl(coreBaseUrl + "/svc/reward")
|
||||
.requestFactory(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()))
|
||||
.requestInterceptor((request, body, execution) -> {
|
||||
clientRegistrationId("keycloak").accept(request.getAttributes());
|
||||
principal("loyalty-service").accept(request.getAttributes());
|
||||
return oauth2Interceptor.intercept(request, body, execution);
|
||||
|
||||
log.info("MCP-Agent Call API [Request] -> {} {}", request.getMethod(), request.getURI());
|
||||
if (body.length > 0) {
|
||||
log.info("MCP-Agent Call API [Request Body] -> {}", new String(body, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
ClientHttpResponse response = oauth2Interceptor.intercept(request, body, execution);
|
||||
|
||||
log.info("MCP-Agent Call API [Response Status] <- {}", response.getStatusCode());
|
||||
if (response.getBody() != null) {
|
||||
log.info("MCP-Agent Call API [Response Body] <- {}", StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
return response;
|
||||
})
|
||||
.defaultStatusHandler(
|
||||
HttpStatusCode::isError,
|
||||
(request, response) -> {
|
||||
throw new RuntimeException("API Error: HTTP Status " + response.getStatusCode());
|
||||
throw new RuntimeException("API Error: HTTP Status " + response.getStatusCode() + " Body: " + new String(response.getBody().readAllBytes()));
|
||||
}
|
||||
)
|
||||
.build();
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package dev.sonpx.loyalty.mcp.exception;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
/**
|
||||
* Global exception handler for the MCP Server.
|
||||
* Prevents stack traces from leaking to the MCP Client (Agent).
|
||||
*/
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
public class GlobalMcpExceptionHandler {
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<String> handleException(Exception ex) {
|
||||
log.error("Global exception caught in MCP server: {}", ex.getMessage());
|
||||
// We return a safe error message instead of the HTML stack trace.
|
||||
// Returning a generic 500 error prevents the LLM from trying to explain server internals.
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body("{\"error\": \"Lỗi hệ thống tại MCP Server. Không thể xử lý yêu cầu.\"}");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package dev.sonpx.loyalty.mcp.model;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@@ -14,16 +13,16 @@ public class Result<T> {
|
||||
|
||||
private final T data;
|
||||
|
||||
private Map<String, String> presentation;
|
||||
@JsonProperty("_agent_instruction")
|
||||
private String agentInstruction;
|
||||
|
||||
public static <T> Result<T> of(T data, String content) {
|
||||
public static <T> Result<T> of(T data, String instruction) {
|
||||
Result<T> result = of(data);
|
||||
result.markdown(content);
|
||||
result.instruction(instruction);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void markdown(String content) {
|
||||
this.presentation = new HashMap<>();
|
||||
this.presentation.put("markdown", content);
|
||||
public void instruction(String instruction) {
|
||||
this.agentInstruction = instruction;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,21 +23,21 @@ public interface CampaignClient {
|
||||
@GetExchange("/api/campaign/csr/list")
|
||||
List<Campaign> getAll(CampaignCriteria criteria, Pageable pageable);
|
||||
|
||||
@GetExchange("/csr/count")
|
||||
@GetExchange("/api/campaign/csr/count")
|
||||
Long count(CampaignCriteria criteria);
|
||||
|
||||
@GetExchange("/csr/id/{id}")
|
||||
@GetExchange("/api/campaign/csr/id/{id}")
|
||||
Campaign findActiveById(@PathVariable String id);
|
||||
|
||||
@GetExchange("/csr/id")
|
||||
List<Campaign> findActiveByIds(@RequestParam Map<String, String> params);
|
||||
@GetExchange("/api/campaign/list-by-ids")
|
||||
List<Campaign> findActiveByIds(@RequestParam("idList") List<String> idList);
|
||||
|
||||
@GetExchange("/csr/id/generate")
|
||||
@GetExchange("/api/campaign/csr/id/generate")
|
||||
String generateId();
|
||||
|
||||
@GetExchange("/csr/id/check/{id}")
|
||||
@GetExchange("/api/campaign/csr/id/check/{id}")
|
||||
String checkId(@PathVariable String id);
|
||||
|
||||
@PostExchange("/csr/create")
|
||||
@PostExchange("/api/campaign/csr/create")
|
||||
OperationResult<Campaign> create(@Valid @RequestBody Campaign dto);
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ public interface CampaignRuleClient {
|
||||
@GetExchange("/api/campaign-rule/csr/id/{id}")
|
||||
CampaignRule findActiveById(@PathVariable String id);
|
||||
|
||||
@GetExchange("/api/campaign-rule/csr/id")
|
||||
List<CampaignRule> findActiveByIds(@RequestParam Map<String, String> params);
|
||||
@GetExchange("/api/campaign-rule/list-by-ids")
|
||||
List<CampaignRule> findActiveByIds(@RequestParam("idList") List<String> idList);
|
||||
|
||||
@GetExchange("/api/campaign-rule/csr/id/generate")
|
||||
String generateId();
|
||||
|
||||
@@ -5,8 +5,8 @@ import dev.sonpx.loyalty.mcp.model.Result;
|
||||
import dev.sonpx.loyalty.mcp.reward.client.CampaignRuleClient;
|
||||
import dev.sonpx.loyalty.mcp.reward.criteria.CampaignRuleCriteria;
|
||||
import dev.sonpx.loyalty.mcp.reward.model.CampaignRule;
|
||||
import dev.sonpx.loyalty.mcp.util.MarkdownGenerator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -23,72 +23,38 @@ public class CampaignRuleService {
|
||||
private final CampaignRuleClient campaignRuleClient;
|
||||
|
||||
public Result<List<CampaignRule>> getAll(CampaignRuleCriteria criteria) {
|
||||
try {
|
||||
List<CampaignRule> rules = campaignRuleClient.getAll(criteria, Pageable.ofSize(10));
|
||||
return Result.of(rules, MarkdownGenerator.generateCampaignRuleMD(rules));
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return Result.of(null);
|
||||
}
|
||||
List<CampaignRule> rules = campaignRuleClient.getAll(criteria, Pageable.ofSize(10));
|
||||
return Result.of(rules, "Format these campaign rules as a markdown table with columns ID, Campaign ID, Rule Code, Status.");
|
||||
}
|
||||
|
||||
public Result<Long> count(CampaignRuleCriteria criteria) {
|
||||
try {
|
||||
Long count = campaignRuleClient.count(criteria);
|
||||
return Result.of(count, MarkdownGenerator.generateCampaignRuleMD(count));
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return Result.of(null);
|
||||
}
|
||||
Long count = campaignRuleClient.count(criteria);
|
||||
return Result.of(count, "Present the campaign rule count.");
|
||||
}
|
||||
|
||||
public Result<CampaignRule> findActiveById(String id) {
|
||||
try {
|
||||
CampaignRule rule = campaignRuleClient.findActiveById(id);
|
||||
return Result.of(rule, MarkdownGenerator.generateCampaignRuleMD(rule));
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return Result.of(null);
|
||||
}
|
||||
CampaignRule rule = campaignRuleClient.findActiveById(id);
|
||||
return Result.of(rule, "Format this campaign rule as a markdown table with its details.");
|
||||
}
|
||||
|
||||
public Result<List<CampaignRule>> findActiveByIds(String ids) {
|
||||
try {
|
||||
List<CampaignRule> rules = campaignRuleClient.findActiveByIds(java.util.Map.of("id", ids));
|
||||
return Result.of(rules, MarkdownGenerator.generateCampaignRuleMD(rules));
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return Result.of(null);
|
||||
}
|
||||
List<String> idList = java.util.Arrays.asList(ids.split(",\\s*"));
|
||||
List<CampaignRule> rules = campaignRuleClient.findActiveByIds(idList);
|
||||
return Result.of(rules, "Format these campaign rules as a markdown table with columns ID, Campaign ID, Rule Code, Status.");
|
||||
}
|
||||
|
||||
public Result<String> generateId() {
|
||||
try {
|
||||
String id = campaignRuleClient.generateId();
|
||||
return Result.of(id, MarkdownGenerator.generateCampaignRuleIdMD(id));
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return Result.of(null);
|
||||
}
|
||||
String id = campaignRuleClient.generateId();
|
||||
return Result.of(id, "Present the newly generated campaign rule ID.");
|
||||
}
|
||||
|
||||
public Result<String> checkId(String id) {
|
||||
try {
|
||||
String checkResult = campaignRuleClient.checkId(id);
|
||||
return Result.of(checkResult, MarkdownGenerator.generateCheckResultMD(checkResult));
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return Result.of(null);
|
||||
}
|
||||
String checkResult = campaignRuleClient.checkId(id);
|
||||
return Result.of(checkResult, "Present the result of the campaign rule ID check.");
|
||||
}
|
||||
|
||||
public Result<OperationResult<CampaignRule>> create(CampaignRule dto) {
|
||||
try {
|
||||
OperationResult<CampaignRule> opResult = campaignRuleClient.create(dto);
|
||||
return Result.of(opResult, MarkdownGenerator.generateCampaignRuleOperationResultMD(opResult));
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return Result.of(null);
|
||||
}
|
||||
OperationResult<CampaignRule> opResult = campaignRuleClient.create(dto);
|
||||
return Result.of(opResult, "Present the result of the campaign rule creation operation, formatting the created rule details if successful.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package dev.sonpx.loyalty.mcp.service;
|
||||
|
||||
import static dev.sonpx.loyalty.mcp.util.MarkdownGenerator.generateCampaignMD;
|
||||
|
||||
import dev.sonpx.loyalty.mcp.model.OperationResult;
|
||||
import dev.sonpx.loyalty.mcp.model.Result;
|
||||
import dev.sonpx.loyalty.mcp.reward.client.CampaignClient;
|
||||
import dev.sonpx.loyalty.mcp.reward.criteria.CampaignCriteria;
|
||||
import dev.sonpx.loyalty.mcp.reward.model.Campaign;
|
||||
import dev.sonpx.loyalty.mcp.util.MarkdownGenerator;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -25,73 +22,38 @@ public class CampaignService {
|
||||
private final CampaignClient campaignClient;
|
||||
|
||||
public Result<List<Campaign>> getAll(CampaignCriteria criteria) {
|
||||
try {
|
||||
List<Campaign> campaigns = campaignClient.getAll(criteria, Pageable.ofSize(10));
|
||||
|
||||
return Result.of(campaigns, generateCampaignMD(campaigns));
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return Result.of(null);
|
||||
}
|
||||
List<Campaign> campaigns = campaignClient.getAll(criteria, Pageable.ofSize(5));
|
||||
return Result.of(campaigns, "Format these campaigns as a markdown table with columns ID, Name, Start Date, End Date, Status.");
|
||||
}
|
||||
|
||||
public Result<Long> count(CampaignCriteria criteria) {
|
||||
try {
|
||||
Long count = campaignClient.count(criteria);
|
||||
return Result.of(count, MarkdownGenerator.generateCampaignMD(count));
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return Result.of(null);
|
||||
}
|
||||
Long count = campaignClient.count(criteria);
|
||||
return Result.of(count, "Present the campaign count.");
|
||||
}
|
||||
|
||||
public Result<Campaign> findActiveById(String id) {
|
||||
try {
|
||||
Campaign campaign = campaignClient.findActiveById(id);
|
||||
return Result.of(campaign, MarkdownGenerator.generateCampaignMD(campaign));
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return Result.of(null);
|
||||
}
|
||||
Campaign campaign = campaignClient.findActiveById(id);
|
||||
return Result.of(campaign, "Format this campaign as a markdown table with its details.");
|
||||
}
|
||||
|
||||
public Result<List<Campaign>> findActiveByIds(String ids) {
|
||||
try {
|
||||
List<Campaign> campaigns = campaignClient.findActiveByIds(java.util.Map.of("id", ids));
|
||||
return Result.of(campaigns, MarkdownGenerator.generateCampaignMD(campaigns));
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return Result.of(null);
|
||||
}
|
||||
List<String> idList = java.util.Arrays.asList(ids.split(",\\s*"));
|
||||
List<Campaign> campaigns = campaignClient.findActiveByIds(idList);
|
||||
return Result.of(campaigns, "Format these campaigns as a markdown table with columns ID, Name, Start Date, End Date, Status.");
|
||||
}
|
||||
|
||||
public Result<String> generateId() {
|
||||
try {
|
||||
String id = campaignClient.generateId();
|
||||
return Result.of(id, MarkdownGenerator.generateCampaignIdMD(id));
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return Result.of(null);
|
||||
}
|
||||
String id = campaignClient.generateId();
|
||||
return Result.of(id, "Present the newly generated campaign ID.");
|
||||
}
|
||||
|
||||
public Result<String> checkId(String id) {
|
||||
try {
|
||||
String checkResult = campaignClient.checkId(id);
|
||||
return Result.of(checkResult, MarkdownGenerator.generateCheckResultMD(checkResult));
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return Result.of(null);
|
||||
}
|
||||
String checkResult = campaignClient.checkId(id);
|
||||
return Result.of(checkResult, "Present the result of the campaign ID check.");
|
||||
}
|
||||
|
||||
public Result<OperationResult<Campaign>> create(Campaign dto) {
|
||||
try {
|
||||
OperationResult<Campaign> opResult = campaignClient.create(dto);
|
||||
return Result.of(opResult, MarkdownGenerator.generateOperationResultMD(opResult));
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return Result.of(null);
|
||||
}
|
||||
OperationResult<Campaign> opResult = campaignClient.create(dto);
|
||||
return Result.of(opResult, "Present the result of the campaign creation operation, formatting the created campaign details if successful.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public class CampaignRuleTools {
|
||||
|
||||
private final CampaignRuleService campaignRuleService;
|
||||
|
||||
@McpTool(description = "Lấy danh sách các Campaign Rule, cho phép tìm kiếm với param search, hiển thị tối đa 10 bản ghi")
|
||||
@McpTool(description = "Lấy danh sách các Campaign Rule (Thể lệ chiến dịch). Dùng tool này khi người dùng hỏi về rule, thể lệ, quy tắc, điều kiện của chiến dịch. Cho phép tìm kiếm với param search (ví dụ: nhập tên chiến dịch hoặc tên rule vào đây), hiển thị tối đa 10 bản ghi.")
|
||||
public Result<List<CampaignRule>> campaignRules(String search) {
|
||||
CampaignRuleCriteria criteria = new CampaignRuleCriteria();
|
||||
criteria.setSearch(search);
|
||||
|
||||
@@ -19,7 +19,7 @@ public class CampaignTools {
|
||||
|
||||
private final CampaignService campaignService;
|
||||
|
||||
@McpTool(description = "Lấy danh sách chiến dịch, cho phép tìm kiếm với param search")
|
||||
@McpTool(description = "Lấy danh sách chiến dịch (Campaign), cho phép tìm kiếm với param search. CHỈ dùng tool này khi cần tìm thông tin về chính chiến dịch đó. NẾU người dùng hỏi về RULE / THỂ LỆ của chiến dịch, HÃY DÙNG tool campaignRules.")
|
||||
public Result<List<Campaign>> campaigns(String search) {
|
||||
CampaignCriteria criteria = new CampaignCriteria();
|
||||
criteria.setSearch(search);
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
package dev.sonpx.loyalty.mcp.util;
|
||||
|
||||
import dev.sonpx.loyalty.mcp.model.OperationResult;
|
||||
import dev.sonpx.loyalty.mcp.reward.model.Campaign;
|
||||
import dev.sonpx.loyalty.mcp.reward.model.CampaignRule;
|
||||
import java.util.List;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
public class MarkdownGenerator {
|
||||
|
||||
public static String generateCampaignMD(Campaign campaign) {
|
||||
if (campaign == null) {
|
||||
return "No campaign data available.";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("### 🏆 Campaign Details\n\n");
|
||||
sb.append("| Field | Value |\n");
|
||||
sb.append("| :--- | :--- |\n");
|
||||
sb.append("| **Campaign ID** | ").append(campaign.getCampaignId()).append(" |\n");
|
||||
sb.append("| **Name** | ").append(campaign.getName()).append(" |\n");
|
||||
|
||||
if (campaign.getDescription() != null) {
|
||||
sb.append("| **Description** | ").append(campaign.getDescription()).append(" |\n");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String generateCampaignMD(List<Campaign> campaigns) {
|
||||
if (CollectionUtils.isEmpty(campaigns)) {
|
||||
return "No campaigns data available.";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("### 🏆 Campaign List\n\n");
|
||||
sb.append("| Id | Name | Description |\n");
|
||||
sb.append("| :--- | :--- | :--- |\n");
|
||||
|
||||
campaigns.forEach((campaign) -> {
|
||||
sb.append("| ").append(campaign.getCampaignId());
|
||||
sb.append(" | ").append(campaign.getName());
|
||||
sb.append(" | ").append(campaign.getDescription()).append(" |\n");
|
||||
});
|
||||
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String generateCampaignMD(Long count) {
|
||||
if (count == null) {
|
||||
return "Total campaigns: 0";
|
||||
}
|
||||
return "Total campaigns: " + count;
|
||||
}
|
||||
|
||||
public static String generateCampaignIdMD(String id) {
|
||||
if (id == null) {
|
||||
return "No campaign ID available.";
|
||||
}
|
||||
return "Campaign ID: " + id;
|
||||
}
|
||||
|
||||
public static String generateCampaignRuleMD(CampaignRule rule) {
|
||||
if (rule == null) {
|
||||
return "No campaign rule data available.";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("### 📜 Campaign Rule Details\n\n");
|
||||
sb.append("| Field | Value |\n");
|
||||
sb.append("| :--- | :--- |\n");
|
||||
sb.append("| **Rule ID** | ").append(rule.getRuleId()).append(" |\n");
|
||||
sb.append("| **Name** | ").append(rule.getRuleName()).append(" |\n");
|
||||
if (rule.getRuleType() != null) {
|
||||
sb.append("| **Type** | ").append(rule.getRuleType()).append(" |\n");
|
||||
}
|
||||
if (rule.getCampaignId() != null) {
|
||||
sb.append("| **Campaign ID** | ").append(rule.getCampaignId().getCode()).append(" |\n");
|
||||
}
|
||||
if (rule.getDescription() != null) {
|
||||
sb.append("| **Description** | ").append(rule.getDescription()).append(" |\n");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String generateCampaignRuleMD(List<CampaignRule> rules) {
|
||||
if (CollectionUtils.isEmpty(rules)) {
|
||||
return "No campaign rules data available.";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("### 📜 Campaign Rule List\n\n");
|
||||
sb.append("| Rule Id | Name | Type | Campaign Id | Description |\n");
|
||||
sb.append("| :--- | :--- | :--- | :--- | :--- |\n");
|
||||
|
||||
rules.forEach((rule) -> {
|
||||
sb.append("| ").append(rule.getRuleId());
|
||||
sb.append(" | ").append(rule.getRuleName());
|
||||
sb.append(" | ").append(rule.getRuleType() != null ? rule.getRuleType() : "");
|
||||
sb.append(" | ").append(rule.getCampaignId() != null ? rule.getCampaignId().getCode() : "");
|
||||
sb.append(" | ").append(rule.getDescription() != null ? rule.getDescription() : "").append(" |\n");
|
||||
});
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String generateCampaignRuleMD(Long count) {
|
||||
if (count == null) {
|
||||
return "Total campaign rules: 0";
|
||||
}
|
||||
return "Total campaign rules: " + count;
|
||||
}
|
||||
|
||||
public static String generateCampaignRuleIdMD(String id) {
|
||||
if (id == null) {
|
||||
return "No campaign rule ID available.";
|
||||
}
|
||||
return "Campaign Rule ID: " + id;
|
||||
}
|
||||
|
||||
public static String generateCheckResultMD(String result) {
|
||||
if (result == null) {
|
||||
return "No check result available.";
|
||||
}
|
||||
return "Check result: " + result;
|
||||
}
|
||||
|
||||
public static String generateOperationResultMD(OperationResult<Campaign> result) {
|
||||
if (result == null) {
|
||||
return "No operation result available.";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if ("00".equals(result.getErrorCode()) || result.getErrorCode() == null) {
|
||||
sb.append("✅ Operation successful.\n\n");
|
||||
if (result.getEntity() != null) {
|
||||
sb.append(generateCampaignMD(result.getEntity()));
|
||||
}
|
||||
} else {
|
||||
sb.append("❌ Operation failed.\n\n");
|
||||
sb.append("**Error Code:** ").append(result.getErrorCode()).append("\n");
|
||||
sb.append("**Message:** ").append(result.getMessage()).append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String generateCampaignRuleOperationResultMD(OperationResult<CampaignRule> result) {
|
||||
if (result == null) {
|
||||
return "No operation result available.";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if ("00".equals(result.getErrorCode()) || result.getErrorCode() == null) {
|
||||
sb.append("✅ Operation successful.\n\n");
|
||||
if (result.getEntity() != null) {
|
||||
sb.append(generateCampaignRuleMD(result.getEntity()));
|
||||
}
|
||||
} else {
|
||||
sb.append("❌ Operation failed.\n\n");
|
||||
sb.append("**Error Code:** ").append(result.getErrorCode()).append("\n");
|
||||
sb.append("**Message:** ").append(result.getMessage()).append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -30,8 +30,9 @@ loyalty:
|
||||
base-url: ${LOYALTY_CORE_BASE_URL:http://192.168.99.242:8081}
|
||||
|
||||
logging:
|
||||
pattern:
|
||||
console: "%d{HH:mm:ss.SSS} %5p --- %-40.40logger{39} : %m%n"
|
||||
level:
|
||||
root: warn
|
||||
org.springframework.ai: INFO
|
||||
org.springframework.web: INFO
|
||||
dev.sonpx.loyalty: DEBUG
|
||||
|
||||
Reference in New Issue
Block a user