앱 관리
This commit is contained in:
@@ -4,18 +4,11 @@ package com.eactive.apim.portal.apps.apis.controller;
|
||||
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;
|
||||
import com.eactive.apim.portal.apps.apiservice.dto.ApiServiceApiDTO;
|
||||
import com.eactive.apim.portal.apps.apiservice.dto.ApiServiceDTO;
|
||||
import com.eactive.apim.portal.apps.apiservice.service.ApiServiceService;
|
||||
import com.eactive.apim.portal.apps.app.dto.ClientDTO;
|
||||
import com.eactive.apim.portal.apps.app.service.AppServiceFacade;
|
||||
import com.eactive.apim.portal.common.user.PortalAuthenticatedUser;
|
||||
import com.eactive.apim.portal.common.util.SecurityUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -28,11 +21,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RequiredArgsConstructor
|
||||
public class ApiAjaxController {
|
||||
|
||||
private final static String STG_SERVER = "STG";
|
||||
|
||||
private final ApiService apiService;
|
||||
private final ApiServiceService apiServiceService;
|
||||
private final AppServiceFacade appServiceFacade;
|
||||
|
||||
public Map<String, ApiServiceDTO> getMainIconsFromServiceDtos(List<ApiServiceDTO> apiServices) {
|
||||
Map<String, ApiServiceDTO> mainIconsMap = new HashMap<>();
|
||||
@@ -54,53 +44,15 @@ public class ApiAjaxController {
|
||||
Map<String, ApiServiceDTO> mainIconsMap = getMainIconsFromServiceDtos(apiServices);
|
||||
List<ApiSpecInfoDto> apiSpecInfoDtos = apiService.findApis();
|
||||
|
||||
for (ApiSpecInfoDto spec : apiSpecInfoDtos) {
|
||||
ApiServiceDTO serviceDTO = mainIconsMap.get(spec.getApiId());
|
||||
if (serviceDTO != null) {
|
||||
String mainIcon = serviceDTO.getMainIcon();
|
||||
String service = serviceDTO.getGroupName();
|
||||
spec.setMainIcon(mainIcon);
|
||||
spec.setService(service);
|
||||
}
|
||||
}
|
||||
return apiSpecInfoDtos;
|
||||
}
|
||||
|
||||
@GetMapping("/for_request_prod")
|
||||
@Secured("ROLE_API_KEY_REQUEST")
|
||||
public List<ApiSpecInfoDto> apiRequestProd(@ModelAttribute ApiGroupSearch search) {
|
||||
|
||||
List<ApiServiceDTO> apiServices = apiServiceService.searchApiGroups(search);
|
||||
Map<String, ApiServiceDTO> mainIconsMap = getMainIconsFromServiceDtos(apiServices);
|
||||
|
||||
PortalAuthenticatedUser user = SecurityUtil.getPortalAuthenticatedUser();
|
||||
|
||||
List<ClientDTO> apikeys = appServiceFacade.getApiKeyList(user.getPortalOrg(), STG_SERVER);
|
||||
|
||||
List<ApiServiceApiDTO> apis = apikeys.stream()
|
||||
.flatMap(client -> client.getApiList().stream()) // flatten all apiLists into a single stream of ApiServiceApiDTO
|
||||
.distinct() // remove duplicates
|
||||
.collect(Collectors.toList()); // collect to List
|
||||
|
||||
List<ApiSpecInfoDto> apiSpecInfoDtos = new ArrayList<>();
|
||||
|
||||
apis.forEach(api -> {
|
||||
ApiSpecInfoDto specInfoDto = new ApiSpecInfoDto();
|
||||
specInfoDto.setApiId(api.getApiId());
|
||||
specInfoDto.setApiName(api.getApiDesc());
|
||||
apiSpecInfoDtos.add(specInfoDto);
|
||||
});
|
||||
|
||||
for (ApiSpecInfoDto spec : apiSpecInfoDtos) {
|
||||
ApiServiceDTO serviceDTO = mainIconsMap.get(spec.getApiId());
|
||||
if (serviceDTO != null) {
|
||||
String mainIcon = serviceDTO.getMainIcon();
|
||||
String service = serviceDTO.getGroupName();
|
||||
spec.setMainIcon(mainIcon);
|
||||
spec.setService(service);
|
||||
}
|
||||
}
|
||||
return apiSpecInfoDtos;
|
||||
// Filter APIs that have matching service information
|
||||
return apiSpecInfoDtos.stream()
|
||||
.filter(spec -> mainIconsMap.containsKey(spec.getApiId()))
|
||||
.peek(spec -> {
|
||||
ApiServiceDTO serviceDTO = mainIconsMap.get(spec.getApiId());
|
||||
spec.setMainIcon(serviceDTO.getMainIcon());
|
||||
spec.setService(serviceDTO.getGroupName());
|
||||
})
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
package com.eactive.apim.portal.apps.apis.controller;
|
||||
|
||||
|
||||
import com.eactive.apim.portal.apps.apis.dto.ApiSearchData;
|
||||
import com.eactive.apim.portal.apps.apis.dto.ApiSpecInfoDto;
|
||||
import com.eactive.apim.portal.apps.apis.service.ApiSearchFacade;
|
||||
import com.eactive.apim.portal.apps.apis.service.ApiService;
|
||||
import com.eactive.apim.portal.apps.apiservice.dto.ApiGroupSearch;
|
||||
import com.eactive.apim.portal.apps.apiservice.dto.ApiServiceDTO;
|
||||
import com.eactive.apim.portal.apps.apiservice.service.ApiServiceService;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.eactive.apim.portal.common.exception.NotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
package com.eactive.apim.portal.apps.app.controller;
|
||||
|
||||
import com.eactive.apim.portal.apprequest.entity.AppRequestType;
|
||||
import com.eactive.apim.portal.apps.apis.dto.ApiSearchData;
|
||||
import com.eactive.apim.portal.apps.apis.service.ApiSearchFacade;
|
||||
import com.eactive.apim.portal.apps.app.dto.AppRequestDTO;
|
||||
import com.eactive.apim.portal.apps.app.dto.ClientDTO;
|
||||
import com.eactive.apim.portal.apps.app.dto.ClientSimpleDTO;
|
||||
import com.eactive.apim.portal.apps.app.mapper.CredentialMapper;
|
||||
import com.eactive.apim.portal.apps.app.service.AppServiceFacade;
|
||||
import com.eactive.apim.portal.common.dto.ResponseDTO;
|
||||
import com.eactive.apim.portal.common.user.PortalAuthenticatedUser;
|
||||
import com.eactive.apim.portal.common.util.EncryptionUtil;
|
||||
import com.eactive.apim.portal.common.util.SecurityUtil;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.web.PageableDefault;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.ValidationUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/myapikey")
|
||||
@RequiredArgsConstructor
|
||||
@Secured("ROLE_API_KEY_REQUEST")
|
||||
public class ApiKeyRestController {
|
||||
|
||||
private final static String PROD_SERVER = "PROD";
|
||||
private final static String STG_SERVER = "STG";
|
||||
|
||||
private final AppServiceFacade appServiceFacade;
|
||||
private final CredentialMapper credentialMapper;
|
||||
private final EncryptionUtil encryptionUtil;
|
||||
private final ApiSearchFacade apiSearchFacade;
|
||||
|
||||
@PostMapping("/api_key_request")
|
||||
public ResponseDTO apiRequest(@RequestBody AppRequestDTO appRequest) {
|
||||
appRequest.setOrg(SecurityUtil.getUserOrg());
|
||||
if (appRequest.getType() == null) {
|
||||
appRequest.setType(AppRequestType.NEW);
|
||||
}
|
||||
AppRequestDTO appRequestDTO = appServiceFacade.createAppRequest(appRequest);
|
||||
appServiceFacade.beginApproval(appRequestDTO.getApproval().getId());
|
||||
return new ResponseDTO(200, "SUCCESS", appRequestDTO.getType().getDescription() + " 신청이 완료되었습니다.");
|
||||
}
|
||||
|
||||
@PostMapping("/api_key_request_prod")
|
||||
public ResponseDTO requestProdApiKey(@RequestBody AppRequestDTO appRequest) {
|
||||
appRequest.setOrg(SecurityUtil.getUserOrg());
|
||||
|
||||
if (appRequest.getClientId() != null && !appRequest.getClientId().isEmpty()) {
|
||||
try {
|
||||
appRequest.setClientId(encryptionUtil.decrypt(appRequest.getClientId()));
|
||||
} catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
|
||||
return new ResponseDTO(400, "FAILURE", "API 키 정보가 올바르지 않습니다.");
|
||||
}
|
||||
appRequest.setType(AppRequestType.PROD_MODIFY);
|
||||
} else {
|
||||
appRequest.setType(AppRequestType.PROD_NEW);
|
||||
}
|
||||
|
||||
AppRequestDTO appRequestDTO = appServiceFacade.createAppRequest(appRequest);
|
||||
appServiceFacade.beginApproval(appRequestDTO.getApproval().getId());
|
||||
|
||||
return new ResponseDTO(200, "SUCCESS", appRequestDTO.getType().getDescription() + " 신청이 완료되었습니다.");
|
||||
}
|
||||
|
||||
@GetMapping("/dev")
|
||||
public List<ClientSimpleDTO> apiKeyList() {
|
||||
PortalAuthenticatedUser user = SecurityUtil.getPortalAuthenticatedUser();
|
||||
List<ClientDTO> apikeys = appServiceFacade.getApiKeyList(user.getPortalOrg(), STG_SERVER);
|
||||
|
||||
ApiSearchData apiSearchData = apiSearchFacade.loadAllApiData();
|
||||
for (ClientDTO apikey : apikeys) {
|
||||
apikey.getApiList().forEach(api -> {
|
||||
api.setService(apiSearchData.getServicesByApiId().get(api.getApiId()).getGroupName());
|
||||
});
|
||||
}
|
||||
|
||||
return apikeys.stream().map(credentialMapper::mapToClientSimpleDTO).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@PostMapping("/prod")
|
||||
public ClientSimpleDTO apiKeyProdList(@RequestBody AppRequestDTO appRequest) {
|
||||
PortalAuthenticatedUser user = SecurityUtil.getPortalAuthenticatedUser();
|
||||
|
||||
try {
|
||||
ClientDTO apiKey = appServiceFacade.getApiKey(user.getPortalOrg().getId(), encryptionUtil.decrypt(appRequest.getClientId()), PROD_SERVER);
|
||||
ApiSearchData apiSearchData = apiSearchFacade.loadAllApiData();
|
||||
apiKey.getApiList().forEach(api -> {
|
||||
api.setService(apiSearchData.getServicesByApiId().get(api.getApiId()).getGroupName());
|
||||
});
|
||||
apiKey.setClientid(encryptionUtil.encrypt(apiKey.getClientid()));
|
||||
return credentialMapper.mapToClientSimpleDTO(apiKey);
|
||||
} catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
|
||||
return new ClientSimpleDTO();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,111 @@
|
||||
package com.eactive.apim.portal.apps.app.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* API Key Registration Session Data
|
||||
* Holds data across multiple registration steps
|
||||
*/
|
||||
@Data
|
||||
public class ApiKeyRegistrationDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// Client ID for modification operations
|
||||
private String clientId;
|
||||
|
||||
// Request type for tracking operation type
|
||||
private String requestType; // "NEW" or "MODIFY"
|
||||
|
||||
// Existing app icon file ID (for modifications)
|
||||
private String appIconFileId;
|
||||
|
||||
// Step 1: Basic Information
|
||||
// Transient field for file upload (not serialized in session)
|
||||
private transient MultipartFile appIcon;
|
||||
|
||||
// Persisted file data
|
||||
private String appIconFileName;
|
||||
private byte[] appIconData;
|
||||
private String appIconContentType;
|
||||
|
||||
@NotBlank(message = "앱 이름을 입력해주세요.")
|
||||
@Size(max = 100, message = "앱 이름은 100자를 초과할 수 없습니다.")
|
||||
private String appName;
|
||||
|
||||
@NotBlank(message = "앱 설명을 입력해주세요.")
|
||||
@Size(max = 500, message = "앱 설명은 500자를 초과할 수 없습니다.")
|
||||
private String appDescription;
|
||||
|
||||
// Optional field - allows empty string or valid URL with http(s):// protocol
|
||||
@Pattern(regexp = "^$|^https?://.*", message = "올바른 URL 형식이 아닙니다.")
|
||||
private String callbackUrl;
|
||||
|
||||
private List<String> ipWhitelist = new ArrayList<>();
|
||||
|
||||
// Step 2: API Selection
|
||||
private List<String> selectedApis = new ArrayList<>();
|
||||
|
||||
// Helper method to add IP to whitelist
|
||||
public void addIpAddress(String ip) {
|
||||
if (ip != null && !ip.trim().isEmpty() && !ipWhitelist.contains(ip)) {
|
||||
ipWhitelist.add(ip);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to set IP whitelist from comma-separated string
|
||||
public void setIpWhitelistFromString(String ipString) {
|
||||
ipWhitelist.clear();
|
||||
if (ipString != null && !ipString.trim().isEmpty()) {
|
||||
String[] ips = ipString.split(",");
|
||||
for (String ip : ips) {
|
||||
String trimmedIp = ip.trim();
|
||||
if (!trimmedIp.isEmpty()) {
|
||||
ipWhitelist.add(trimmedIp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to get IP whitelist as comma-separated string
|
||||
public String getIpWhitelistAsString() {
|
||||
return String.join(",", ipWhitelist);
|
||||
}
|
||||
|
||||
// Helper method to get app icon as base64 data URI for image display
|
||||
public String getAppIconBase64() {
|
||||
if (appIconData == null || appIconData.length == 0) {
|
||||
return null;
|
||||
}
|
||||
String base64Data = Base64.getEncoder().encodeToString(appIconData);
|
||||
String contentType = appIconContentType != null ? appIconContentType : "image/png";
|
||||
return "data:" + contentType + ";base64," + base64Data;
|
||||
}
|
||||
|
||||
// Validation helpers
|
||||
public boolean isStep1Complete() {
|
||||
// callbackUrl is optional, so we only check required fields
|
||||
// For modifications, appIconFileId indicates an existing icon
|
||||
boolean hasIcon = (appIconData != null && appIconData.length > 0)
|
||||
|| (appIconFileId != null && !appIconFileId.trim().isEmpty());
|
||||
return hasIcon &&
|
||||
appName != null && !appName.trim().isEmpty() &&
|
||||
appDescription != null && !appDescription.trim().isEmpty();
|
||||
}
|
||||
|
||||
public boolean isStep2Complete() {
|
||||
return selectedApis != null && !selectedApis.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isComplete() {
|
||||
return isStep1Complete() && isStep2Complete();
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,14 @@ public class AppRequestDTO {
|
||||
|
||||
private String reason;
|
||||
|
||||
private String appDescription;
|
||||
|
||||
private String callbackUrl;
|
||||
|
||||
private String ipWhitelist;
|
||||
|
||||
private String appIconFileId;
|
||||
|
||||
private LocalDateTime createdDate;
|
||||
|
||||
private String prevApiList;
|
||||
|
||||
@@ -45,6 +45,10 @@ public class ClientDTO {
|
||||
|
||||
private String appstatus;
|
||||
|
||||
private String appDescription;
|
||||
|
||||
private String appIconFileId;
|
||||
|
||||
private List<ApiServiceApiDTO> apiList = new ArrayList<>();
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ package com.eactive.apim.portal.apps.app.mapper;
|
||||
import com.eactive.apim.portal.apprequest.entity.AppRequest;
|
||||
import com.eactive.apim.portal.apps.apiservice.mapper.ApiServiceApiMapper;
|
||||
import com.eactive.apim.portal.apps.app.dto.AppRequestDTO;
|
||||
import com.eactive.apim.portal.apps.app.dto.ClientDTO;
|
||||
import com.eactive.apim.portal.apps.approval.mapper.ApprovalMapper;
|
||||
import com.eactive.apim.portal.apps.user.mapper.PortalOrgMapper;
|
||||
import com.eactive.eai.data.mapper.BaseMapperConfig;
|
||||
@@ -13,4 +14,53 @@ import org.mapstruct.Mapper;
|
||||
@Mapper(config = BaseMapperConfig.class, uses = {PortalOrgMapper.class, ApiServiceApiMapper.class, ApprovalMapper.class})
|
||||
public interface AppRequestMapper extends GenericMapper<AppRequestDTO, AppRequest> {
|
||||
|
||||
/**
|
||||
* AppRequest를 ClientDTO로 간단하게 매핑합니다.
|
||||
* 뷰에서 AppRequest를 ClientDTO와 동일한 형식으로 표시하기 위해 사용됩니다.
|
||||
*
|
||||
* @param appRequest 앱 요청 엔티티
|
||||
* @return ClientDTO 표시용 DTO
|
||||
*/
|
||||
default ClientDTO mapToClientDTO(AppRequest appRequest) {
|
||||
if (appRequest == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClientDTO dto = new ClientDTO();
|
||||
|
||||
// 기본 식별 정보
|
||||
dto.setClientid(appRequest.getId()); // AppRequest ID를 임시 client ID로 사용
|
||||
dto.setClientname(appRequest.getClientName());
|
||||
|
||||
// 앱 상세 정보
|
||||
dto.setAppDescription(appRequest.getAppDescription());
|
||||
dto.setAppIconFileId(appRequest.getAppIconFileId());
|
||||
|
||||
// 네트워크 설정
|
||||
dto.setRedirecturi(appRequest.getCallbackUrl());
|
||||
dto.setAllowedips(appRequest.getIpWhitelist());
|
||||
|
||||
// 상태 정보 (ApprovalStatus → appstatus 매핑)
|
||||
if (appRequest.getStatus() != null) {
|
||||
switch (appRequest.getStatus()) {
|
||||
case APPROVED:
|
||||
dto.setAppstatus("1"); // 승인됨 = 활성화
|
||||
break;
|
||||
case DENIED:
|
||||
dto.setAppstatus("0"); // 거부됨 = 비활성화
|
||||
break;
|
||||
default:
|
||||
dto.setAppstatus("2"); // 대기중/진행중 = 보류
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 수정 날짜 (createdDate를 modifiedon으로 사용)
|
||||
dto.setModifiedon(appRequest.getCreatedDate());
|
||||
|
||||
// API 목록은 별도 처리 필요 (콤마로 구분된 문자열 → List<ApiServiceApiDTO>)
|
||||
// 필요시 컨트롤러에서 추가 처리
|
||||
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.eactive.apim.portal.apps.app.mapper;
|
||||
|
||||
import com.eactive.apim.portal.app.entity.ProdClient;
|
||||
import com.eactive.apim.portal.apps.apiservice.mapper.ApiSpecInfoMapper;
|
||||
import com.eactive.apim.portal.apps.app.dto.ClientDTO;
|
||||
import com.eactive.eai.data.mapper.BaseMapperConfig;
|
||||
import com.eactive.eai.data.mapper.GenericMapper;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
@Mapper(config = BaseMapperConfig.class, uses = {ApiSpecInfoMapper.class})
|
||||
public interface ProdClientMapper extends GenericMapper<ClientDTO, ProdClient> {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -7,12 +7,14 @@ import com.eactive.apim.portal.apprequest.entity.AppRequest;
|
||||
import com.eactive.apim.portal.apprequest.entity.AppRequestType;
|
||||
import com.eactive.apim.portal.apprequest.repository.AppRequestRepository;
|
||||
import com.eactive.apim.portal.approval.entity.Approval;
|
||||
import com.eactive.apim.portal.approval.statemachine.ProcessingState;
|
||||
import com.eactive.apim.portal.approval.statemachine.RequestedState;
|
||||
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;
|
||||
import com.eactive.apim.portal.apps.apiservice.dto.ApiServiceDTO;
|
||||
import com.eactive.apim.portal.apps.apiservice.dto.ApiServiceApiDTO;
|
||||
import com.eactive.apim.portal.apps.apiservice.service.ApiServiceService;
|
||||
import com.eactive.apim.portal.apps.app.dto.ApiKeyRegistrationDTO;
|
||||
import com.eactive.apim.portal.apps.app.dto.AppRequestDTO;
|
||||
import com.eactive.apim.portal.apps.app.dto.ClientDTO;
|
||||
import com.eactive.apim.portal.apps.app.mapper.AppRequestMapper;
|
||||
@@ -21,16 +23,24 @@ import com.eactive.apim.portal.apps.approval.service.ApprovalService;
|
||||
import com.eactive.apim.portal.apps.user.dto.PortalOrgDTO;
|
||||
import com.eactive.apim.portal.apps.user.mapper.PortalOrgMapper;
|
||||
import com.eactive.apim.portal.common.exception.NotFoundException;
|
||||
import com.eactive.apim.portal.common.user.PortalAuthenticatedUser;
|
||||
import com.eactive.apim.portal.common.util.ApiServiceHelper;
|
||||
import com.eactive.apim.portal.file.entity.FileInfo;
|
||||
import com.eactive.apim.portal.file.service.FileService;
|
||||
import com.eactive.apim.portal.portalorg.entity.PortalOrg;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.transaction.Transactional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@@ -47,53 +57,64 @@ public class AppServiceFacade {
|
||||
private final AppRequestMapper appRequestMapper;
|
||||
private final PortalOrgMapper portalOrgMapper;
|
||||
private final ApiServiceHelper apiServiceHelper;
|
||||
private final FileService fileService;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
public Page<ClientDTO> getApiKeyPageForServer(Pageable pageable, PortalOrg portalOrg, String server) {
|
||||
Page<Credential> clients = credentialRepository.findAllByOrgidAndServer(pageable, portalOrg.getId(), server);
|
||||
return clients.map(credentialMapper::toVo);
|
||||
}
|
||||
public List<ClientDTO> getApikeyList(PortalOrg portalOrg) {
|
||||
|
||||
public List<ClientDTO> getApiKeyList(PortalOrg portalOrg, String server) {
|
||||
List<Credential> clients = credentialRepository.findAllByOrgidAndServer(portalOrg.getId(), server);
|
||||
List<Credential> clients = credentialRepository.findAllByOrgid(portalOrg.getId());
|
||||
return clients.stream().map(credentialMapper::toVo).collect(Collectors.toList());
|
||||
|
||||
}
|
||||
|
||||
public ClientDTO getApiKey(String orgid, String clientId, String server) {
|
||||
return credentialRepository.findByClientidAndOrgidAndServer(clientId, orgid, server).map(credentialMapper::toVo).orElse(null);
|
||||
public List<AppRequest> getPendingApiKeyList(PortalOrg portalOrg) {
|
||||
List<AppRequest> appRequests = appRequestRepository.findAllByOrgAndTypeIsInAndApproval_ApprovalStatusIn(portalOrg, Arrays.asList(AppRequestType.NEW, AppRequestType.MODIFY, AppRequestType.DELETE),
|
||||
Arrays.asList(new ProcessingState(), new RequestedState()));
|
||||
|
||||
return appRequests;
|
||||
}
|
||||
|
||||
public ClientDTO getApiKey(String orgid, String clientId) {
|
||||
return credentialRepository.findByClientidAndOrgid(clientId, orgid).map(credentialMapper::toVo).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* AppRequest ID와 조직 정보로 AppRequest를 조회합니다.
|
||||
* API 그룹 및 API 목록 정보를 함께 처리하여 반환합니다.
|
||||
*
|
||||
* @param id AppRequest ID
|
||||
* @param portalOrg 포털 조직
|
||||
* @return AppRequest DTO (없으면 null)
|
||||
*/
|
||||
public AppRequestDTO getAppRequestById(String id, PortalOrg portalOrg) {
|
||||
return getApiRequestByIdAndPortalOrg(id, portalOrg);
|
||||
}
|
||||
|
||||
|
||||
public Page<AppRequestDTO> getApiRequestHistory(Pageable pageable, PortalOrgDTO portalOrg) {
|
||||
return appRequestRepository.findAllByOrgAndTypeIsIn(pageable, portalOrgMapper.toEntity(portalOrg), Arrays.asList(AppRequestType.NEW,AppRequestType.MODIFY, AppRequestType.DELETE)).map(appRequestMapper::toVo);
|
||||
}
|
||||
|
||||
public Page<AppRequestDTO> getApiRequestProdHistory(Pageable pageable, PortalOrgDTO portalOrg) {
|
||||
return appRequestRepository.findAllByOrgAndTypeIsIn(pageable, portalOrgMapper.toEntity(portalOrg), Arrays.asList(AppRequestType.PROD_NEW,AppRequestType.PROD_MODIFY, AppRequestType.PROD_DELETE)).map(appRequestMapper::toVo);
|
||||
return appRequestRepository.findAllByOrgAndTypeIsIn(pageable, portalOrgMapper.toEntity(portalOrg), Arrays.asList(AppRequestType.NEW, AppRequestType.MODIFY, AppRequestType.DELETE)).map(appRequestMapper::toVo);
|
||||
}
|
||||
|
||||
public AppRequestDTO createAppRequest(AppRequestDTO appRequest) {
|
||||
|
||||
setApiGroupsFromApiList(appRequest);
|
||||
AppRequest request = appRequestRepository.save(appRequestMapper.toEntity(appRequest));
|
||||
|
||||
if (request.getType() != null && (request.getType().equals(AppRequestType.MODIFY) || request.getType().equals(AppRequestType.DELETE) ||
|
||||
request.getType().equals(AppRequestType.PROD_MODIFY) || request.getType().equals(AppRequestType.PROD_DELETE))) {
|
||||
if (request.getType() != null && (request.getType().equals(AppRequestType.MODIFY) || request.getType().equals(AppRequestType.DELETE))) {
|
||||
|
||||
Optional<Credential> client = credentialRepository.findById(request.getClientId());
|
||||
|
||||
if (client.isPresent()) {
|
||||
request.setClientName(client.get().getClientname());
|
||||
|
||||
if(client.get().getApiList() != null) {
|
||||
if (client.get().getApiList() != null) {
|
||||
// 기존 API 목록을 저장
|
||||
String existingApiList = client.get().getApiList().stream()
|
||||
.map(ApiSpecInfo::getApiId)
|
||||
.collect(Collectors.joining(","));
|
||||
.map(ApiSpecInfo::getApiId)
|
||||
.collect(Collectors.joining(","));
|
||||
request.setPrevApiList(existingApiList);
|
||||
}
|
||||
|
||||
if(AppRequestType.DELETE.equals(request.getType()) || AppRequestType.PROD_DELETE.equals(request.getType())) {
|
||||
if (AppRequestType.DELETE.equals(request.getType())) {
|
||||
request.setApiList(request.getPrevApiList());
|
||||
}
|
||||
} else {
|
||||
@@ -108,22 +129,6 @@ public class AppServiceFacade {
|
||||
return appRequestMapper.toVo(request);
|
||||
}
|
||||
|
||||
private void setApiGroupsFromApiList(AppRequestDTO appRequest) {
|
||||
if (StringUtils.isEmpty(appRequest.getApiList())) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> uniqueGroupIds = Arrays.stream(appRequest.getApiList().split(","))
|
||||
.map(apiId -> apiServiceService.findApiServiceByApiId(apiId))
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(apiService -> apiService.getApiGroupApiList().stream())
|
||||
.map(ApiServiceApiDTO::getApiGroupId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
appRequest.setApiGroupList(String.join(",", uniqueGroupIds));
|
||||
}
|
||||
|
||||
|
||||
public void beginApproval(String approvalId) {
|
||||
approvalService.beginApproval(approvalId);
|
||||
}
|
||||
@@ -132,27 +137,11 @@ public class AppServiceFacade {
|
||||
appRequestRepository.findByIdAndOrg(id, portalOrg).ifPresent(approvalService::cancelAppApproval);
|
||||
}
|
||||
|
||||
public List<AppRequestDTO> getProdApiRequestHistory(String clientid) {
|
||||
return appRequestRepository.findAllByClientIdsContainsAndTypeIsIn(clientid,Arrays.asList(AppRequestType.PROD_NEW,AppRequestType.PROD_MODIFY, AppRequestType.PROD_DELETE)).stream().map(appRequestMapper::toVo).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
public AppRequestDTO getApiRequestProdByIdAndPortalOrg(String id, PortalOrg portalOrg) {
|
||||
AppRequestDTO appRequest = appRequestRepository.findByIdAndOrgAndTypeIsIn(id, portalOrg,
|
||||
Arrays.asList(AppRequestType.PROD_NEW,AppRequestType.PROD_MODIFY, AppRequestType.PROD_DELETE)).map(this::convertToAppRequestDTO).orElse(null);
|
||||
|
||||
if(appRequest != null) {
|
||||
processApiGroups(appRequest);
|
||||
processApiList(appRequest);
|
||||
}
|
||||
return appRequest;
|
||||
}
|
||||
|
||||
public AppRequestDTO getApiRequestByIdAndPortalOrg(String id, PortalOrg org) {
|
||||
AppRequestDTO appRequest = appRequestRepository.findByIdAndOrg(id, org).map(this::convertToAppRequestDTO).orElse(null);
|
||||
|
||||
if(appRequest != null) {
|
||||
processApiGroups(appRequest);
|
||||
if (appRequest != null) {
|
||||
processApiList(appRequest);
|
||||
}
|
||||
return appRequest;
|
||||
@@ -167,16 +156,6 @@ public class AppServiceFacade {
|
||||
return dto;
|
||||
}
|
||||
|
||||
private void processApiGroups(AppRequestDTO appRequest) {
|
||||
|
||||
if (!StringUtils.isEmpty(appRequest.getApiGroupList())) {
|
||||
String[] apiGroupList = appRequest.getApiGroupList().split(",");
|
||||
for (String apiGroupId : apiGroupList) {
|
||||
appRequest.getApiServiceDTOList().add(apiServiceService.getApiGroupById(apiGroupId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processApiList(AppRequestDTO appRequest) {
|
||||
|
||||
if (!StringUtils.isEmpty(appRequest.getApiList())) {
|
||||
@@ -192,4 +171,140 @@ public class AppServiceFacade {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ApiKeyRegistrationDTO를 기반으로 AppRequest를 생성합니다.
|
||||
*
|
||||
* @param registration API Key 등록 정보
|
||||
* @param portalOrg 포털 조직
|
||||
* @return 생성된 AppRequest DTO
|
||||
* @throws IOException 파일 처리 중 오류 발생 시
|
||||
*/
|
||||
public AppRequestDTO createAppRequestFromRegistration(ApiKeyRegistrationDTO registration, PortalOrg portalOrg) throws IOException {
|
||||
// 1. 앱 아이콘 파일 저장
|
||||
String appIconFileId = null;
|
||||
|
||||
if (registration.getAppIconData() != null && registration.getAppIconData().length > 0) {
|
||||
FileInfo fileInfo = fileService.createSingleFileFromBytes(registration.getAppIconFileName(), registration.getAppIconContentType(), registration.getAppIconData());
|
||||
appIconFileId = fileInfo.getFileId();
|
||||
}
|
||||
|
||||
// 2. AppRequestDTO 생성 및 필드 매핑
|
||||
AppRequestDTO appRequestDTO = new AppRequestDTO();
|
||||
appRequestDTO.setOrg(portalOrgMapper.toVo(portalOrg));
|
||||
appRequestDTO.setType(AppRequestType.NEW);
|
||||
|
||||
// 기본 정보 매핑
|
||||
appRequestDTO.setClientName(registration.getAppName());
|
||||
appRequestDTO.setAppDescription(registration.getAppDescription());
|
||||
appRequestDTO.setCallbackUrl(registration.getCallbackUrl());
|
||||
appRequestDTO.setAppIconFileId(appIconFileId);
|
||||
|
||||
// IP 화이트리스트 매핑 (List<String> → comma-separated String)
|
||||
if (registration.getIpWhitelist() != null && !registration.getIpWhitelist().isEmpty()) {
|
||||
appRequestDTO.setIpWhitelist(String.join(",", registration.getIpWhitelist()));
|
||||
}
|
||||
|
||||
// 선택된 API 목록 매핑 (List<String> → comma-separated String)
|
||||
if (registration.getSelectedApis() != null && !registration.getSelectedApis().isEmpty()) {
|
||||
appRequestDTO.setApiList(String.join(",", registration.getSelectedApis()));
|
||||
}
|
||||
|
||||
// 3. 기존 createAppRequest 메소드 호출하여 승인 프로세스 시작
|
||||
return createAppRequest(appRequestDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* ApiKeyRegistrationDTO를 기반으로 수정 AppRequest를 생성합니다.
|
||||
*
|
||||
* @param registration API Key 수정 정보
|
||||
* @param portalOrg 포털 조직
|
||||
* @return 생성된 AppRequest DTO
|
||||
* @throws IOException 파일 처리 중 오류 발생 시
|
||||
*/
|
||||
public AppRequestDTO createModifyRequestFromRegistration(ApiKeyRegistrationDTO registration, PortalOrg portalOrg) throws IOException {
|
||||
// 1. 기존 Credential 정보 조회
|
||||
ClientDTO existingClient = getApiKey(portalOrg.getId(), registration.getClientId());
|
||||
if (existingClient == null) {
|
||||
throw new NotFoundException("Client not found: " + registration.getClientId());
|
||||
}
|
||||
|
||||
// 2. 앱 아이콘 파일 저장 (변경된 경우)
|
||||
String appIconFileId = null;
|
||||
|
||||
// 새로운 아이콘 데이터가 있으면 저장
|
||||
if (registration.getAppIconData() != null && registration.getAppIconData().length > 0) {
|
||||
FileInfo fileInfo = fileService.createSingleFileFromBytes(registration.getAppIconFileName(), registration.getAppIconContentType(), registration.getAppIconData());
|
||||
appIconFileId = fileInfo.getFileId();
|
||||
}
|
||||
// 새로운 아이콘이 없으면 기존 아이콘 ID 사용 (registration에서 가져오거나 기존 클라이언트에서 가져옴)
|
||||
else if (registration.getAppIconFileId() != null) {
|
||||
appIconFileId = registration.getAppIconFileId();
|
||||
} else {
|
||||
appIconFileId = existingClient.getAppIconFileId();
|
||||
}
|
||||
|
||||
// 3. AppRequestDTO 생성 및 필드 매핑
|
||||
AppRequestDTO appRequestDTO = new AppRequestDTO();
|
||||
appRequestDTO.setOrg(portalOrgMapper.toVo(portalOrg));
|
||||
appRequestDTO.setType(AppRequestType.MODIFY);
|
||||
appRequestDTO.setClientId(registration.getClientId()); // 수정할 클라이언트 ID 설정
|
||||
|
||||
// 기본 정보 매핑
|
||||
appRequestDTO.setClientName(registration.getAppName());
|
||||
appRequestDTO.setAppDescription(registration.getAppDescription());
|
||||
appRequestDTO.setCallbackUrl(registration.getCallbackUrl());
|
||||
appRequestDTO.setAppIconFileId(appIconFileId);
|
||||
|
||||
// IP 화이트리스트 매핑 (List<String> → comma-separated String)
|
||||
if (registration.getIpWhitelist() != null && !registration.getIpWhitelist().isEmpty()) {
|
||||
appRequestDTO.setIpWhitelist(String.join(",", registration.getIpWhitelist()));
|
||||
}
|
||||
|
||||
// 선택된 API 목록 매핑 (List<String> → comma-separated String)
|
||||
if (registration.getSelectedApis() != null && !registration.getSelectedApis().isEmpty()) {
|
||||
appRequestDTO.setApiList(String.join(",", registration.getSelectedApis()));
|
||||
}
|
||||
|
||||
// 4. 기존 createAppRequest 메소드 호출하여 승인 프로세스 시작
|
||||
// createAppRequest 내부에서 MODIFY 타입인 경우 기존 API 목록을 prevApiList에 저장함
|
||||
return createAppRequest(appRequestDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자의 비밀번호를 검증합니다.
|
||||
* Client Secret 조회 등 민감한 작업 수행 시 본인 확인을 위해 사용됩니다.
|
||||
*
|
||||
* @param user 인증된 사용자 정보
|
||||
* @param password 검증할 비밀번호 (평문)
|
||||
* @return 비밀번호 일치 여부
|
||||
*/
|
||||
public boolean verifyUserPassword(PortalAuthenticatedUser user, String password) {
|
||||
if (user == null || password == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// PasswordEncoder를 사용하여 평문 비밀번호와 저장된 해시를 비교
|
||||
return passwordEncoder.matches(password, user.getPassword());
|
||||
} catch (Exception e) {
|
||||
// 비밀번호 검증 중 오류 발생 시 false 반환 (보안상 구체적인 오류 노출 방지)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* API Key(Credential)를 즉시 삭제합니다.
|
||||
* 승인 프로세스 없이 바로 삭제 처리됩니다.
|
||||
*
|
||||
* @param orgId 조직 ID
|
||||
* @param clientId 삭제할 클라이언트 ID
|
||||
* @throws NotFoundException 클라이언트를 찾을 수 없는 경우
|
||||
*/
|
||||
public void deleteApp(String orgId, String clientId) {
|
||||
Credential credential = credentialRepository.findByClientidAndOrgid(clientId, orgId)
|
||||
.orElseThrow(() -> new NotFoundException("Client not found: " + clientId));
|
||||
|
||||
credentialRepository.delete(credential);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-4
@@ -4,7 +4,6 @@ import com.eactive.apim.portal.apps.dashboard.service.DashboardService;
|
||||
import com.eactive.apim.portal.common.pagerouter.PageHandler;
|
||||
import com.eactive.apim.portal.common.util.SecurityUtil;
|
||||
import com.eactive.apim.portal.portalorg.entity.PortalOrg;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -22,9 +21,7 @@ public class DashboardHandler implements PageHandler {
|
||||
if (SecurityUtil.getPortalAuthenticatedUser() != null && SecurityUtil.getPortalAuthenticatedUser().getPortalOrg() != null) {
|
||||
PortalOrg org = SecurityUtil.getPortalAuthenticatedUser().getPortalOrg();
|
||||
model.addAttribute("pendingKeyCount", dashboardService.getPendingApiKeyRequestCount(org));
|
||||
model.addAttribute("testKeyCount", dashboardService.getTestApiKeyCount(org));
|
||||
model.addAttribute("pendingProdCount", dashboardService.getProdApiKeyRequestCount(org));
|
||||
model.addAttribute("prodKeyCount", dashboardService.getProdApiKeyCount(org));
|
||||
model.addAttribute("testKeyCount", dashboardService.getApiKeyCount(org));
|
||||
|
||||
model.addAttribute("totalApi", dashboardService.getTotalApi(org));
|
||||
model.addAttribute("dailyTotal", dashboardService.getDailyTotalApiUsage(org));
|
||||
|
||||
@@ -5,24 +5,18 @@ import com.eactive.apim.portal.app.entity.Credential;
|
||||
import com.eactive.apim.portal.app.repository.CredentialRepository;
|
||||
import com.eactive.apim.portal.apprequest.entity.AppRequestType;
|
||||
import com.eactive.apim.portal.apprequest.repository.AppRequestRepository;
|
||||
import com.eactive.apim.portal.approval.entity.ApprovalStatus;
|
||||
import com.eactive.apim.portal.approval.statemachine.ProcessingState;
|
||||
import com.eactive.apim.portal.approval.statemachine.RequestedState;
|
||||
import com.eactive.apim.portal.apps.approval.service.ApprovalService;
|
||||
import com.eactive.apim.portal.apps.dashboard.ApiDailyStatistics;
|
||||
import com.eactive.apim.portal.apps.dashboard.repository.PortalStatisticsRepository;
|
||||
import com.eactive.apim.portal.apps.dashboard.repository.PortalStatisticsRepository.TopApiUsage;
|
||||
import com.eactive.apim.portal.common.util.DateUtil;
|
||||
import com.eactive.apim.portal.portalorg.entity.PortalOrg;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -39,15 +33,12 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@Service
|
||||
public class DashboardService {
|
||||
|
||||
private final static String PROD_SERVER = "PROD";
|
||||
private final static String STG_SERVER = "STG";
|
||||
|
||||
private final AppRequestRepository appRequestRepository;
|
||||
private final CredentialRepository credentialRepository;
|
||||
private final PortalStatisticsRepository portalStatisticsRepository;
|
||||
|
||||
public int getTestApiKeyCount(PortalOrg org) {
|
||||
return credentialRepository.countAllByOrgidAndServer(org.getId(), STG_SERVER);
|
||||
public int getApiKeyCount(PortalOrg org) {
|
||||
return credentialRepository.countAllByOrgid(org.getId());
|
||||
}
|
||||
|
||||
public int getPendingApiKeyRequestCount(PortalOrg org) {
|
||||
@@ -55,18 +46,9 @@ public class DashboardService {
|
||||
Arrays.asList(new ProcessingState(), new RequestedState()));
|
||||
}
|
||||
|
||||
public int getProdApiKeyRequestCount(PortalOrg org) {
|
||||
return appRequestRepository.countAllByOrgAndTypeIsInAndApproval_ApprovalStatusIn(org, Arrays.asList(AppRequestType.PROD_NEW, AppRequestType.PROD_MODIFY, AppRequestType.PROD_DELETE),
|
||||
Arrays.asList(new ProcessingState(), new RequestedState()));
|
||||
}
|
||||
|
||||
public int getProdApiKeyCount(PortalOrg org) {
|
||||
return credentialRepository.findAllByOrgidAndServer(org.getId(), PROD_SERVER).size();
|
||||
}
|
||||
|
||||
public int getTotalApi(PortalOrg org) {
|
||||
|
||||
List<Credential> credentials = credentialRepository.findAllByOrgidAndServer(org.getId(), PROD_SERVER);
|
||||
List<Credential> credentials = credentialRepository.findAllByOrgid(org.getId());
|
||||
return (int) credentials.stream()
|
||||
.flatMap(credential -> credential.getApiList().stream())
|
||||
.map(ApiSpecInfo::getApiId)
|
||||
|
||||
Reference in New Issue
Block a user