승인 요청 처리 개선 및 UI/로직 추가:
- 승인정보 없는 요청 목록 노출 및 삭제 로직 추가 - 내부 결재 진행 중 취소 불가 안내 메시지 및 스타일 추가 - '승인대기' -> '승인정보 없음' 텍스트 수정
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package com.eactive.apim.portal.apps.app.controller;
|
||||
|
||||
import com.eactive.apim.portal.apprequest.entity.AppRequest;
|
||||
import com.eactive.apim.portal.approval.statemachine.InvalidApprovalTransitionException;
|
||||
import com.eactive.apim.portal.apps.apis.dto.ApiSpecInfoDto;
|
||||
import com.eactive.apim.portal.apps.apis.service.ApiService;
|
||||
import com.eactive.apim.portal.apps.apiservice.dto.ApiGroupSearch;
|
||||
@@ -178,7 +179,6 @@ public class MyAppController {
|
||||
|
||||
model.addAttribute("apiKey", apiKey);
|
||||
model.addAttribute("secretAvailable", secretAvailable);
|
||||
model.addAttribute("authType", "OAuth2");
|
||||
|
||||
return new ModelAndView(CREDENTIAL_DETAIL);
|
||||
}
|
||||
@@ -217,9 +217,17 @@ public class MyAppController {
|
||||
appServiceFacade.cancelApiRequest(id, SecurityUtil.getPortalAuthenticatedUser().getPortalOrg());
|
||||
result.put("success", true);
|
||||
result.put("message", "신청이 취소되었습니다.");
|
||||
} catch (Exception e) {
|
||||
} catch (InvalidApprovalTransitionException e) {
|
||||
result.put("success", false);
|
||||
result.put("message", "신청 취소 중 오류가 발생했습니다: " + e.getMessage());
|
||||
result.put("message", "내부 결재가 진행 중이라 신청을 취소할 수 없습니다. 취소가 필요한 경우 관리자에게 문의해 주세요.");
|
||||
} catch (IllegalStateException e) {
|
||||
log.error("API Key 신청 취소 중 GW 차단 실패. id={}", id, e);
|
||||
result.put("success", false);
|
||||
result.put("message", e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("API Key 신청 취소 실패. id={}", id, e);
|
||||
result.put("success", false);
|
||||
result.put("message", "신청 취소 중 오류가 발생했습니다.");
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -59,6 +59,7 @@ public class AppServiceFacade {
|
||||
private final ApiServiceHelper apiServiceHelper;
|
||||
private final FileService fileService;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final AdminGatewayClient adminGatewayClient;
|
||||
|
||||
public List<ClientDTO> getApikeyList(PortalOrg portalOrg) {
|
||||
|
||||
@@ -68,9 +69,13 @@ public class AppServiceFacade {
|
||||
}
|
||||
|
||||
public List<AppRequest> getPendingApiKeyList(PortalOrg portalOrg) {
|
||||
List<AppRequest> appRequests = appRequestRepository.findAllByOrgAndTypeIsInAndApproval_ApprovalStatusIn(portalOrg, Arrays.asList(AppRequestType.NEW, AppRequestType.MODIFY, AppRequestType.DELETE),
|
||||
List<AppRequestType> types = Arrays.asList(AppRequestType.NEW, AppRequestType.MODIFY, AppRequestType.DELETE);
|
||||
List<AppRequest> appRequests = appRequestRepository.findAllByOrgAndTypeIsInAndApproval_ApprovalStatusIn(portalOrg, types,
|
||||
Arrays.asList(new ProcessingState(), new RequestedState()));
|
||||
|
||||
// 승인정보(approval) 없는 신청도 목록에 노출한다. (사용자가 직접 삭제 가능)
|
||||
appRequests.addAll(appRequestRepository.findAllByOrgAndTypeIsInAndApprovalIsNull(portalOrg, types));
|
||||
|
||||
return appRequests;
|
||||
}
|
||||
|
||||
@@ -134,7 +139,23 @@ public class AppServiceFacade {
|
||||
}
|
||||
|
||||
public void cancelApiRequest(String id, PortalOrg portalOrg) {
|
||||
appRequestRepository.findByIdAndOrg(id, portalOrg).ifPresent(approvalService::cancelAppApproval);
|
||||
appRequestRepository.findByIdAndOrg(id, portalOrg).ifPresent(request -> {
|
||||
if (request.getApproval() == null) {
|
||||
// 승인정보 없는 신청은 결재 워크플로우가 없으므로 즉시 삭제.
|
||||
// 단, GW에 클라이언트가 존재할 수 있으므로 차단(appstatus=0)+리로드를 먼저 수행하고
|
||||
// 실패 시 삭제를 중단한다. (/api_key_delete 와 동일한 순서)
|
||||
if (StringUtils.isNotBlank(request.getClientId())) {
|
||||
try {
|
||||
adminGatewayClient.blockClient(request.getClientId());
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("게이트웨이 차단 처리에 실패하여 삭제를 중단했습니다. 잠시 후 다시 시도해 주세요.", e);
|
||||
}
|
||||
}
|
||||
appRequestRepository.delete(request);
|
||||
} else {
|
||||
approvalService.cancelAppApproval(request);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -164,9 +185,15 @@ public class AppServiceFacade {
|
||||
Map<String, ApiServiceDTO> mainIconsMap = apiServiceHelper.getMainIconsFromServiceDtos(apiServices);
|
||||
|
||||
for (String apiId : apiList) {
|
||||
ApiServiceDTO serviceDTO = mainIconsMap.get(apiId);
|
||||
// 신청 이후 API 스펙/그룹이 삭제된 경우 null 가능
|
||||
ApiSpecInfoDto spec = apiService.selectDetail(apiId);
|
||||
spec.setService(serviceDTO.getGroupName());
|
||||
if (spec == null) {
|
||||
continue;
|
||||
}
|
||||
ApiServiceDTO serviceDTO = mainIconsMap.get(apiId);
|
||||
if (serviceDTO != null) {
|
||||
spec.setService(serviceDTO.getGroupName());
|
||||
}
|
||||
appRequest.getApiSpecList().add(spec);
|
||||
}
|
||||
}
|
||||
|
||||
+283
-3843
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1232,6 +1232,14 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
// 내부 결재 진행중: 신청 취소 불가 안내
|
||||
.dt-cancel-notice {
|
||||
margin: 10px 0 0;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
// Footer Buttons layout
|
||||
.dt-actions {
|
||||
display: flex;
|
||||
|
||||
@@ -256,8 +256,8 @@
|
||||
<h3 class="app-card-title" th:text="${request.clientName}">앱 이름</h3>
|
||||
<!-- Status Badge -->
|
||||
<span class="app-card-badge status-pending"
|
||||
th:text="${request.approval != null and request.approval.approvalStatus != null ? request.approval.approvalStatus.description : '승인대기'}">
|
||||
승인대기
|
||||
th:text="${request.approval != null and request.approval.approvalStatus != null ? request.approval.approvalStatus.description : '승인정보 없음'}">
|
||||
승인정보 없음
|
||||
</span>
|
||||
</div>
|
||||
<!-- App Description & Expected Completion Date -->
|
||||
|
||||
@@ -54,6 +54,9 @@
|
||||
대기중
|
||||
</span>
|
||||
</div>
|
||||
<div class="dt-app-status-row" th:if="${appRequest.approval == null}">
|
||||
<span class="dt-status-badge status-pending">승인정보 없음</span>
|
||||
</div>
|
||||
<h3 class="dt-app-name" th:text="${appRequest.clientName}">앱 이름</h3>
|
||||
<!-- App Description -->
|
||||
<p class="dt-app-desc"
|
||||
@@ -200,12 +203,19 @@
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 내부 결재 진행중: 취소 불가 안내 -->
|
||||
<p class="dt-cancel-notice" sec:authorize="hasRole('ROLE_API_KEY_REQUEST')"
|
||||
th:if="${appRequest.approval != null and appRequest.approval.approvalStatus != null and
|
||||
appRequest.approval.approvalStatus.toString() == 'PROCESSING'}">
|
||||
내부 결재가 진행 중이라 신청을 취소할 수 없습니다. 취소가 필요한 경우 관리자에게 문의해 주세요.
|
||||
</p>
|
||||
|
||||
<!-- Bottom Navigation Actions -->
|
||||
<div class="dt-actions">
|
||||
<!-- Cancel Request Button (danger red) -->
|
||||
<button type="button" sec:authorize="hasRole('ROLE_API_KEY_REQUEST')" class="dt-btn-red"
|
||||
th:if="${appRequest.approval != null and appRequest.approval.approvalStatus != null and
|
||||
(appRequest.approval.approvalStatus.toString() == 'PENDING' or appRequest.approval.approvalStatus.toString() == 'REQUESTED')}"
|
||||
th:if="${appRequest.approval == null or (appRequest.approval.approvalStatus != null and
|
||||
(appRequest.approval.approvalStatus.toString() == 'PENDING' or appRequest.approval.approvalStatus.toString() == 'REQUESTED'))}"
|
||||
th:data-request-id="${appRequest.id}" onclick="cancelRequestById(this)">
|
||||
신청 취소
|
||||
</button>
|
||||
|
||||
@@ -51,16 +51,6 @@
|
||||
<!-- Credential Info Section Card -->
|
||||
<div class="dt-info-container">
|
||||
|
||||
<!-- 인증 방식 -->
|
||||
<div class="dt-row">
|
||||
<div class="dt-col">
|
||||
<label class="dt-label">인증 방식</label>
|
||||
<div class="dt-input-group">
|
||||
<div class="dt-input-box" th:text="${authType}">OAuth2</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Client ID -->
|
||||
<div class="dt-row">
|
||||
<div class="dt-col">
|
||||
|
||||
Reference in New Issue
Block a user