앱 관리

This commit is contained in:
현성필
2025-11-01 11:51:11 +09:00
parent 739877d9a1
commit 77c060b01b
9 changed files with 140 additions and 147 deletions
+19
View File
@@ -0,0 +1,19 @@
-- 1. Add fields to ptl_app_request table
ALTER TABLE ptl_app_request ADD app_description VARCHAR2(500);
COMMENT ON COLUMN ptl_app_request.app_description IS '앱 설명';
ALTER TABLE ptl_app_request ADD callback_url VARCHAR2(255);
COMMENT ON COLUMN ptl_app_request.callback_url IS '콜백 URL';
ALTER TABLE ptl_app_request ADD ip_whitelist VARCHAR2(1000);
COMMENT ON COLUMN ptl_app_request.ip_whitelist IS 'IP 화이트리스트 (comma-separated)';
ALTER TABLE ptl_app_request ADD app_icon_file_id VARCHAR2(38);
COMMENT ON COLUMN ptl_app_request.app_icon_file_id IS '앱 아이콘 파일 ID (ptl_file 참조)';
-- 2. Add fields to ptl_credential table
ALTER TABLE ptl_credential ADD app_description VARCHAR2(500);
COMMENT ON COLUMN ptl_credential.app_description IS '앱 설명';
ALTER TABLE ptl_credential ADD app_icon_file_id VARCHAR2(38);
COMMENT ON COLUMN ptl_credential.app_icon_file_id IS '앱 아이콘 파일 ID (ptl_file 참조)';
@@ -111,6 +111,14 @@ public class Credential extends AbstractEntity<String> implements Serializable {
@Comment("기관이름")
private String orgname;
@Column(name = "app_description", length = 500)
@Comment("앱 설명")
private String appDescription;
@Column(name = "app_icon_file_id", length = 38)
@Comment("앱 아이콘 파일 ID")
private String appIconFileId;
@Comment("일별 토큰 제한 수 (0:무제한)")
private int dailytokenlimit;
@@ -1,121 +0,0 @@
package com.eactive.apim.portal.app.entity;
import com.eactive.apim.portal.apispec.entity.ApiSpecInfo;
import com.eactive.eai.data.converter.LocalDateTimeToStringConverter14;
import com.eactive.eai.data.entity.AbstractEntity;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import lombok.Data;
import lombok.NonNull;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
@Entity
@Data
@Table(name = "ptl_prod_client")
@org.hibernate.annotations.Table(appliesTo = "ptl_prod_client", comment = "사용자 정보")
public class ProdClient extends AbstractEntity<String> implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(unique = true, nullable = false, length = 256)
@Comment("client id")
private String clientid;
@Column(length = 11)
@Comment("Access Token 유효 기간(초)")
private String accesstokenvalidityseconds;
@Column(length = 256)
@Comment("허용된 IP")
private String allowedips;
@Column(length = 256)
@Comment("권한")
private String authorities;
@Column(length = 256)
@Comment("자동 승인 스코프")
private String autoapprove;
@Column(length = 40)
@Comment("client명")
private String clientname;
@Column(length = 512)
@Comment("Client 비밀번호")
private String clientsecret;
@Column(length = 256)
@Comment("권한타입")
private String granttypes;
@Column(length = 8)
@Comment("수정인")
@LastModifiedBy
private String modifiedby;
@Column(length = 14)
@Comment("수정일")
@Convert(converter = LocalDateTimeToStringConverter14.class)
@LastModifiedDate
private LocalDateTime modifiedon;
@Column(length = 256)
@Comment("Redirect URI")
private String redirecturi;
@Column(length = 11)
@Comment("Refresh Token 유효 기간(초)")
private String refreshtokenvalidityseconds;
@Column(length = 4000)
@Comment("리소스 id")
private String resourceids;
@Column(length = 1024)
@Comment("scope")
private String scope;
@Column(length = 4000)
@Comment("암호key")
private String securitykey;
@Column(length = 38)
@Comment("기관ID")
private String orgid;
@Comment("APP 상태")
private String appstatus; //0: 차단, 1: 정상
@Column(length = 255)
@Comment("기관이름")
private String orgname;
@Comment("일별 토큰 제한 수 (0:무제한)")
private int dailytokenlimit;
@Override
public @NonNull String getId() {
return clientid;
}
@ManyToMany
@LazyCollection(LazyCollectionOption.FALSE)
@JoinTable(name = "ptl_prod_client_api", joinColumns = @JoinColumn(name = "client_id"), inverseJoinColumns = @JoinColumn(name = "eaisvcname"))
private List<ApiSpecInfo> apiList = new ArrayList<>();
}
@@ -11,11 +11,11 @@ import org.springframework.data.domain.Pageable;
@EMSDataSource
public interface CredentialRepository extends BaseRepository<Credential, String> {
Page<Credential> findAllByOrgidAndServer(Pageable pageable, String id, String server);
Page<Credential> findAllByOrgid(Pageable pageable, String id);
int countAllByOrgidAndServer(String orgid, String server);
int countAllByOrgid(String orgid);
List<Credential> findAllByOrgidAndServer(String orgid, String server);
List<Credential> findAllByOrgid(String orgid);
Optional<Credential> findByClientidAndOrgidAndServer(String clientid, String orgid, String server);
Optional<Credential> findByClientidAndOrgid(String clientid, String orgid);
}
@@ -1,18 +0,0 @@
package com.eactive.apim.portal.app.repository;
import com.eactive.apim.portal.app.entity.ProdClient;
import com.eactive.apim.portal.approval.entity.Approval;
import com.eactive.apim.portal.approval.entity.ApprovalType;
import com.eactive.eai.data.jpa.BaseRepository;
import com.eactive.eai.rms.data.EMSDataSource;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@EMSDataSource
public interface ProdClientRepository extends BaseRepository<ProdClient, String> {
Page<ProdClient> findAllByOrgid(Pageable pageable, String id);
Optional<ProdClient> findByClientidAndOrgid(String clientid, String orgid);
}
@@ -64,6 +64,18 @@ public class AppRequest implements com.eactive.eai.data.Data {
@Column(name = "reason")
private String reason;
@Column(name = "app_description", length = 500)
private String appDescription;
@Column(name = "callback_url", length = 255)
private String callbackUrl;
@Column(name = "ip_whitelist", length = 1000)
private String ipWhitelist;
@Column(name = "app_icon_file_id", length = 38)
private String appIconFileId;
@Column(length = 17, name = "created_date")
@Convert(converter = LocalDateTimeToStringConverter17.class)
@CreationTimestamp
@@ -3,10 +3,7 @@ package com.eactive.apim.portal.apprequest.entity;
public enum AppRequestType {
NEW("API키 신규"),
MODIFY("API 변경"),
DELETE("API키 삭제"),
PROD_NEW("운영 API키 신규"),
PROD_MODIFY("운영 API 변경"),
PROD_DELETE("운영 API키 삭제");
DELETE("API키 삭제");
private final String description;
@@ -20,6 +20,8 @@ public interface AppRequestRepository extends BaseRepository<AppRequest, String>
Optional<AppRequest> findAppRequestByApproval(Approval approval);
List<AppRequest> findAllByOrgAndTypeIsInAndApproval_ApprovalStatusIn(PortalOrg org, List<AppRequestType> types, List<ApprovalState> approvalStates);
int countAllByOrgAndTypeIsInAndApproval_ApprovalStatusIn(PortalOrg org, List<AppRequestType> types, List<ApprovalState> approvalStates);
Optional<AppRequest> findByIdAndOrg(String id, PortalOrg org);
@@ -252,6 +252,100 @@ public class FileService {
return fileDetail;
}
/**
* byte[] 데이터로 단일 파일을 생성합니다.
*
* @param fileName 파일 이름 (확장자 포함)
* @param contentType 파일 MIME 타입
* @param fileData 파일 바이트 데이터
* @return 파일 정보
* @throws IOException 파일 처리 중 오류 발생 시
*/
public FileInfo createSingleFileFromBytes(String fileName, String contentType, byte[] fileData) throws IOException {
// 파일 타입 검증
String type = fileTypeDetector.detectFileType(fileData);
log.debug("upload file type from bytes: {}", type);
if (type.equalsIgnoreCase("unknown")) {
throw new InvalidFileException("허용된 파일 형식이 아닙니다. <br>문서파일과 이미지 파일만 등록 가능합니다. <br>(pdf, doc, docx, xls, xlsx, ppt, pptx, hwp, gif, jpg, png)");
}
// FileInfo 생성
FileInfo fileInfo = new FileInfo();
String fileId = UUID.randomUUID().toString();
fileInfo.setFileId(fileId);
fileInfo.setCreatedDate(LocalDateTime.now());
fileInfo.setUseYn("Y");
// FileDetail 생성
FileDetail fileDetail = new FileDetail();
fileDetail.setFileId(fileId);
fileDetail.setFileSn(1);
fileDetail.setFileSize(fileData.length);
fileDetail.setOriginalFileName(FilenameUtils.getBaseName(fileName));
fileDetail.setFileExtension(FilenameUtils.getExtension(fileName));
// 파일 내용 저장
String contentReference = binaryStorageService.store(fileData);
fileDetail.setFileContents(contentReference);
// FileInfo에 FileDetail 추가
fileInfo.getFileDetails().add(fileDetail);
// 저장 및 반환
return fileRepository.save(fileInfo);
}
/**
* byte[] 데이터로 기존 파일을 업데이트하거나 새로 생성합니다.
*
* @param existingFileId 기존 파일 ID (null이면 새로 생성)
* @param fileName 파일 이름 (확장자 포함)
* @param contentType 파일 MIME 타입
* @param fileData 파일 바이트 데이터
* @return 파일 정보
* @throws IOException 파일 처리 중 오류 발생 시
*/
public FileInfo createOrUpdateSingleFileFromBytes(String existingFileId, String fileName, String contentType, byte[] fileData) throws IOException {
// 신규 등록 또는 기존 파일 정보 조회
FileInfo fileInfo = Optional.ofNullable(existingFileId)
.filter(StringUtils::isNotBlank)
.map(this::findById)
.orElseGet(() -> {
FileInfo newFile = new FileInfo();
newFile.setFileId(UUID.randomUUID().toString());
newFile.setCreatedDate(LocalDateTime.now());
newFile.setUseYn("Y");
return newFile;
});
// 파일 타입 검증
String type = fileTypeDetector.detectFileType(fileData);
log.debug("upload file type from bytes: {}", type);
if (type.equalsIgnoreCase("unknown")) {
throw new InvalidFileException("허용된 파일 형식이 아닙니다. <br>문서파일과 이미지 파일만 등록 가능합니다. <br>(pdf, doc, docx, xls, xlsx, ppt, pptx, hwp, gif, jpg, png)");
}
// FileDetail 생성
FileDetail fileDetail = new FileDetail();
fileDetail.setFileId(fileInfo.getFileId());
fileDetail.setFileSn(1);
fileDetail.setFileSize(fileData.length);
fileDetail.setOriginalFileName(FilenameUtils.getBaseName(fileName));
fileDetail.setFileExtension(FilenameUtils.getExtension(fileName));
// 파일 내용 저장
String contentReference = binaryStorageService.store(fileData);
fileDetail.setFileContents(contentReference);
// 기존 파일 상세 정보 제거 후 새로운 정보 추가
fileInfo.getFileDetails().clear();
fileInfo.getFileDetails().add(fileDetail);
return fileRepository.save(fileInfo);
}
}