From 77c060b01bc4511331dad319d23d1ec470aa8fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=98=84=EC=84=B1=ED=95=84?= Date: Sat, 1 Nov 2025 11:51:11 +0900 Subject: [PATCH] =?UTF-8?q?=EC=95=B1=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db_migration_add_app_fields.sql | 19 +++ .../apim/portal/app/entity/Credential.java | 8 ++ .../apim/portal/app/entity/ProdClient.java | 121 ------------------ .../app/repository/CredentialRepository.java | 8 +- .../app/repository/ProdClientRepository.java | 18 --- .../portal/apprequest/entity/AppRequest.java | 12 ++ .../apprequest/entity/AppRequestType.java | 5 +- .../repository/AppRequestRepository.java | 2 + .../apim/portal/file/service/FileService.java | 94 ++++++++++++++ 9 files changed, 140 insertions(+), 147 deletions(-) create mode 100644 db_migration_add_app_fields.sql delete mode 100644 src/main/java/com/eactive/apim/portal/app/entity/ProdClient.java delete mode 100644 src/main/java/com/eactive/apim/portal/app/repository/ProdClientRepository.java diff --git a/db_migration_add_app_fields.sql b/db_migration_add_app_fields.sql new file mode 100644 index 0000000..8a2db86 --- /dev/null +++ b/db_migration_add_app_fields.sql @@ -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 참조)'; diff --git a/src/main/java/com/eactive/apim/portal/app/entity/Credential.java b/src/main/java/com/eactive/apim/portal/app/entity/Credential.java index 6c3288e..70cc0b7 100644 --- a/src/main/java/com/eactive/apim/portal/app/entity/Credential.java +++ b/src/main/java/com/eactive/apim/portal/app/entity/Credential.java @@ -111,6 +111,14 @@ public class Credential extends AbstractEntity 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; diff --git a/src/main/java/com/eactive/apim/portal/app/entity/ProdClient.java b/src/main/java/com/eactive/apim/portal/app/entity/ProdClient.java deleted file mode 100644 index 76345ef..0000000 --- a/src/main/java/com/eactive/apim/portal/app/entity/ProdClient.java +++ /dev/null @@ -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 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 apiList = new ArrayList<>(); -} diff --git a/src/main/java/com/eactive/apim/portal/app/repository/CredentialRepository.java b/src/main/java/com/eactive/apim/portal/app/repository/CredentialRepository.java index 1710070..c940645 100644 --- a/src/main/java/com/eactive/apim/portal/app/repository/CredentialRepository.java +++ b/src/main/java/com/eactive/apim/portal/app/repository/CredentialRepository.java @@ -11,11 +11,11 @@ import org.springframework.data.domain.Pageable; @EMSDataSource public interface CredentialRepository extends BaseRepository { - Page findAllByOrgidAndServer(Pageable pageable, String id, String server); + Page findAllByOrgid(Pageable pageable, String id); - int countAllByOrgidAndServer(String orgid, String server); + int countAllByOrgid(String orgid); - List findAllByOrgidAndServer(String orgid, String server); + List findAllByOrgid(String orgid); - Optional findByClientidAndOrgidAndServer(String clientid, String orgid, String server); + Optional findByClientidAndOrgid(String clientid, String orgid); } diff --git a/src/main/java/com/eactive/apim/portal/app/repository/ProdClientRepository.java b/src/main/java/com/eactive/apim/portal/app/repository/ProdClientRepository.java deleted file mode 100644 index c1adafa..0000000 --- a/src/main/java/com/eactive/apim/portal/app/repository/ProdClientRepository.java +++ /dev/null @@ -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 { - - Page findAllByOrgid(Pageable pageable, String id); - - Optional findByClientidAndOrgid(String clientid, String orgid); -} diff --git a/src/main/java/com/eactive/apim/portal/apprequest/entity/AppRequest.java b/src/main/java/com/eactive/apim/portal/apprequest/entity/AppRequest.java index 3d74331..f95caf9 100644 --- a/src/main/java/com/eactive/apim/portal/apprequest/entity/AppRequest.java +++ b/src/main/java/com/eactive/apim/portal/apprequest/entity/AppRequest.java @@ -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 diff --git a/src/main/java/com/eactive/apim/portal/apprequest/entity/AppRequestType.java b/src/main/java/com/eactive/apim/portal/apprequest/entity/AppRequestType.java index 3178ca0..61c340b 100644 --- a/src/main/java/com/eactive/apim/portal/apprequest/entity/AppRequestType.java +++ b/src/main/java/com/eactive/apim/portal/apprequest/entity/AppRequestType.java @@ -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; diff --git a/src/main/java/com/eactive/apim/portal/apprequest/repository/AppRequestRepository.java b/src/main/java/com/eactive/apim/portal/apprequest/repository/AppRequestRepository.java index 30e1f4e..9bbbe36 100644 --- a/src/main/java/com/eactive/apim/portal/apprequest/repository/AppRequestRepository.java +++ b/src/main/java/com/eactive/apim/portal/apprequest/repository/AppRequestRepository.java @@ -20,6 +20,8 @@ public interface AppRequestRepository extends BaseRepository Optional findAppRequestByApproval(Approval approval); + List findAllByOrgAndTypeIsInAndApproval_ApprovalStatusIn(PortalOrg org, List types, List approvalStates); + int countAllByOrgAndTypeIsInAndApproval_ApprovalStatusIn(PortalOrg org, List types, List approvalStates); Optional findByIdAndOrg(String id, PortalOrg org); diff --git a/src/main/java/com/eactive/apim/portal/file/service/FileService.java b/src/main/java/com/eactive/apim/portal/file/service/FileService.java index 2731326..66497d2 100644 --- a/src/main/java/com/eactive/apim/portal/file/service/FileService.java +++ b/src/main/java/com/eactive/apim/portal/file/service/FileService.java @@ -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("허용된 파일 형식이 아닙니다.
문서파일과 이미지 파일만 등록 가능합니다.
(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("허용된 파일 형식이 아닙니다.
문서파일과 이미지 파일만 등록 가능합니다.
(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); + } }