diff --git a/src/main/java/AIWA/MCPBackend_Member/Controller/MemberController.java b/src/main/java/AIWA/MCPBackend_Member/Controller/MemberController.java index 59a02f7..0f84a88 100644 --- a/src/main/java/AIWA/MCPBackend_Member/Controller/MemberController.java +++ b/src/main/java/AIWA/MCPBackend_Member/Controller/MemberController.java @@ -1,6 +1,5 @@ package AIWA.MCPBackend_Member.Controller; - import AIWA.MCPBackend_Member.Dto.*; import AIWA.MCPBackend_Member.Entity.Member; import AIWA.MCPBackend_Member.Service.member.MemberService; @@ -18,12 +17,14 @@ @RequiredArgsConstructor @RequestMapping("/member/api/members") public class MemberController { + private final MemberService memberService; private final ResponseService responseService; // 회원 등록 @PostMapping("/register") public SingleResult registerMember(@RequestBody MemberRequestDto memberRequestDto) { + // 회원 등록 Member savedMember = memberService.registerMember(memberRequestDto); MemberResponseDto memberResponseDto = MemberResponseDto.toDto(savedMember); return responseService.getSingleResult(memberResponseDto); @@ -32,49 +33,62 @@ public SingleResult registerMember(@RequestBody MemberRequest // 회원 삭제 @DeleteMapping("/delete") public CommonResult deleteMember(@RequestBody MemberDeleteRequestDto deleteMemberRequestDto) { - // 회원 삭제 서비스 호출 + // 회원 삭제 memberService.deleteMember(deleteMemberRequestDto); - - // 성공 응답 반환 (ResponseService를 통해) return responseService.getSuccessResult(); } + // 모든 회원 조회 + @GetMapping("/all") + public ListResult getAllMembers() { + // 모든 회원 조회 + List members = memberService.getAllMembers(); + List memberResponseDtoList = members.stream() + .map(MemberResponseDto::toDto) + .collect(Collectors.toList()); + return responseService.getListResult(memberResponseDtoList); + } - // 특정 회원 조회 - @GetMapping("/email") // PathVariable로 이메일을 전달 - public SingleResult getMember(@RequestParam String email) { - Member findMember = memberService.getMemberByEmail(email); // Optional을 반환하지 않는다고 가정 -// System.out.println(email); -// System.out.println(findMember.getAccess_key()); -// System.out.println(findMember.getSecret_key()); - if (findMember != null) { - // Member 정보를 MemberCredentialDTO로 변환 - MemberCredentialDTO memberCredentialDTO = new MemberCredentialDTO( - findMember.getEmail(), - findMember.getAccess_key(), - findMember.getSecret_key() - ); - System.out.println(memberCredentialDTO); - return responseService.getSingleResult(memberCredentialDTO); - } else { - return (SingleResult) responseService.getFailResult(); + @GetMapping("/email") + public SingleResult getMemberByEmail(@RequestParam String email) { + // 특정 회원 조회 + Member member = memberService.getMemberByEmail(email); + if (member == null) { + throw new RuntimeException("Member not found with Email: " + email); // 예외 처리 } + MemberResponseDto memberResponseDto = MemberResponseDto.toDto(member); + return responseService.getSingleResult(memberResponseDto); } - @GetMapping("/all") - public ListResult getAllMembers() { - List members = memberService.getAllMembers(); - List memberResponseDtoList = members.stream().map(MemberResponseDto::toDto).collect(Collectors.toList()); - return responseService.getListResult(memberResponseDtoList); + + + + // AWS 키 추가/업데이트 + @PostMapping("/add-aws-gcp-key") + public SingleResult addAwsAndGcpKey(@RequestBody AddAwsAndGcpKeyRequestDto requestDto) { + String result = memberService.addOrUpdateAwsAndGcpKey( + requestDto.getEmail(), + requestDto.getAccessKey(), + requestDto.getSecretKey(), + requestDto.getGcpKeyContent() + ); + return responseService.getSingleResult(result); } - @PostMapping("/update-credentials") - public CommonResult updateCredentials(@RequestBody MemberCredentialDTO memberCredentialDTO) { - System.out.println(memberCredentialDTO.getAccessKey()); - System.out.println(memberCredentialDTO.getSecretKey()); - memberService.addOrUpdateKeys(memberCredentialDTO.getEmail(),memberCredentialDTO.getAccessKey(), memberCredentialDTO.getSecretKey()); + // AWS 키 삭제 + @DeleteMapping("/delete-aws-key") + public CommonResult deleteAwsKey(@RequestBody DeleteKeyRequestDto deleteKeyRequestDto) { + // AWS 키 삭제 + memberService.removeAwsKey(deleteKeyRequestDto.getMemberId()); return responseService.getSuccessResult(); } + // GCP 키 삭제 + @DeleteMapping("/delete-gcp-key") + public CommonResult deleteGcpKey(@RequestBody DeleteKeyRequestDto deleteKeyRequestDto) { + // GCP 키 삭제 + memberService.removeGcpKey(deleteKeyRequestDto.getMemberId()); + return responseService.getSuccessResult(); + } } \ No newline at end of file diff --git a/src/main/java/AIWA/MCPBackend_Member/Dto/AddAwsAndGcpKeyRequestDto.java b/src/main/java/AIWA/MCPBackend_Member/Dto/AddAwsAndGcpKeyRequestDto.java new file mode 100644 index 0000000..a4263d9 --- /dev/null +++ b/src/main/java/AIWA/MCPBackend_Member/Dto/AddAwsAndGcpKeyRequestDto.java @@ -0,0 +1,13 @@ +package AIWA.MCPBackend_Member.Dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class AddAwsAndGcpKeyRequestDto { + private String email; + private String accessKey; + private String secretKey; + private String gcpKeyContent; +} diff --git a/src/main/java/AIWA/MCPBackend_Member/Dto/AiwaKeyResponseDto.java b/src/main/java/AIWA/MCPBackend_Member/Dto/AiwaKeyResponseDto.java new file mode 100644 index 0000000..cd7867b --- /dev/null +++ b/src/main/java/AIWA/MCPBackend_Member/Dto/AiwaKeyResponseDto.java @@ -0,0 +1,25 @@ +package AIWA.MCPBackend_Member.Dto; + +import AIWA.MCPBackend_Member.Entity.AiwaKey; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class AiwaKeyResponseDto { + + private String companyName; // 회사 이름 (AWS, GCP 등) + private String accessKey; // Access Key (AWS의 경우만 있을 수 있음) + private String secretKey; // Secret Key (AWS의 경우만 있을 수 있음) + private String gcpKeyPath; // GCP Key Path (GCP의 경우만 있을 수 있음) + + // Entity -> DTO 변환 메서드 + public static AiwaKeyResponseDto toDto(AiwaKey aiwaKey) { + AiwaKeyResponseDto dto = new AiwaKeyResponseDto(); + dto.setCompanyName(aiwaKey.getCompanyName()); + dto.setAccessKey(aiwaKey.getAccessKey()); + dto.setSecretKey(aiwaKey.getSecretKey()); + dto.setGcpKeyPath(aiwaKey.getGcpKeyPath()); + return dto; + } +} diff --git a/src/main/java/AIWA/MCPBackend_Member/Dto/CompanyDto.java b/src/main/java/AIWA/MCPBackend_Member/Dto/CompanyDto.java deleted file mode 100644 index 1f81381..0000000 --- a/src/main/java/AIWA/MCPBackend_Member/Dto/CompanyDto.java +++ /dev/null @@ -1,18 +0,0 @@ -package AIWA.MCPBackend_Member.Dto; - -import lombok.Getter; - -@Getter -public class CompanyDto { - private String userId; - private String company; - private String accessKey; - private String secretKey; - - public CompanyDto(String userId, String company, String accessKey, String secretKey) { - this.userId = userId; - this.company = company; - this.accessKey = accessKey; - this.secretKey = secretKey; - } -} diff --git a/src/main/java/AIWA/MCPBackend_Member/Dto/DeleteKeyRequestDto.java b/src/main/java/AIWA/MCPBackend_Member/Dto/DeleteKeyRequestDto.java new file mode 100644 index 0000000..92ce125 --- /dev/null +++ b/src/main/java/AIWA/MCPBackend_Member/Dto/DeleteKeyRequestDto.java @@ -0,0 +1,11 @@ +package AIWA.MCPBackend_Member.Dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class DeleteKeyRequestDto { + private Long memberId; + private String companyName; // AWS 또는 GCP +} \ No newline at end of file diff --git a/src/main/java/AIWA/MCPBackend_Member/Dto/MemberCredentialDTO.java b/src/main/java/AIWA/MCPBackend_Member/Dto/MemberCredentialDTO.java deleted file mode 100644 index 4d930cb..0000000 --- a/src/main/java/AIWA/MCPBackend_Member/Dto/MemberCredentialDTO.java +++ /dev/null @@ -1,19 +0,0 @@ -package AIWA.MCPBackend_Member.Dto; - -import lombok.Data; -import lombok.Getter; - - -@Data -@Getter -public class MemberCredentialDTO { - private String email; - private String accessKey; - private String secretKey; - - public MemberCredentialDTO(String email, String accessKey, String secretKey) { - this.email = email; - this.accessKey = accessKey; - this.secretKey = secretKey; - } -} \ No newline at end of file diff --git a/src/main/java/AIWA/MCPBackend_Member/Dto/MemberDeleteRequestDto.java b/src/main/java/AIWA/MCPBackend_Member/Dto/MemberDeleteRequestDto.java index 387351b..dd9f310 100644 --- a/src/main/java/AIWA/MCPBackend_Member/Dto/MemberDeleteRequestDto.java +++ b/src/main/java/AIWA/MCPBackend_Member/Dto/MemberDeleteRequestDto.java @@ -1,14 +1,10 @@ package AIWA.MCPBackend_Member.Dto; import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.Setter; @Getter -@NoArgsConstructor // 기본 생성자 추가 +@Setter public class MemberDeleteRequestDto { - private String email; // final 제거 - - public MemberDeleteRequestDto(String email) { - this.email = email; - } -} + private String email; +} \ No newline at end of file diff --git a/src/main/java/AIWA/MCPBackend_Member/Dto/MemberRequestDto.java b/src/main/java/AIWA/MCPBackend_Member/Dto/MemberRequestDto.java index e61ea7b..1db34d2 100644 --- a/src/main/java/AIWA/MCPBackend_Member/Dto/MemberRequestDto.java +++ b/src/main/java/AIWA/MCPBackend_Member/Dto/MemberRequestDto.java @@ -1,16 +1,12 @@ package AIWA.MCPBackend_Member.Dto; import lombok.Getter; +import lombok.Setter; @Getter +@Setter public class MemberRequestDto { - private final String name; - private final String password; - private final String email; - - public MemberRequestDto(String name, String password, String email) { - this.name = name; - this.password = password; - this.email = email; - } + private String name; + private String email; + private String password; } \ No newline at end of file diff --git a/src/main/java/AIWA/MCPBackend_Member/Dto/MemberResponseDto.java b/src/main/java/AIWA/MCPBackend_Member/Dto/MemberResponseDto.java index 8218b2a..a4dcc25 100644 --- a/src/main/java/AIWA/MCPBackend_Member/Dto/MemberResponseDto.java +++ b/src/main/java/AIWA/MCPBackend_Member/Dto/MemberResponseDto.java @@ -1,22 +1,40 @@ package AIWA.MCPBackend_Member.Dto; - import AIWA.MCPBackend_Member.Entity.Member; -import lombok.Data; +import AIWA.MCPBackend_Member.Entity.AiwaKey; +import lombok.Getter; +import lombok.Setter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.List; +import java.util.stream.Collectors; -@Data +@Getter +@Setter public class MemberResponseDto { - private String userName; - private String email; - private String accessKey; - - public MemberResponseDto(String userName, String email, String accessKey) { - this.userName = userName; - this.email = email; - this.accessKey = accessKey; - } + private Long id; // 회원 ID + private String name; // 회원 이름 + private String email; // 회원 이메일 + + @JsonIgnore // 비밀번호는 반환하지 않음 + private String password; // 회원 비밀번호 + + private List aiwaKeys; // 회원이 관리하는 회사들의 키 정보 리스트 + + // Entity -> DTO 변환 메서드 public static MemberResponseDto toDto(Member member) { - return new MemberResponseDto(member.getName(), member.getEmail(), member.getAccess_key()); + MemberResponseDto memberResponseDto = new MemberResponseDto(); + memberResponseDto.setId(member.getId()); + memberResponseDto.setName(member.getName()); + memberResponseDto.setEmail(member.getEmail()); + memberResponseDto.setPassword(member.getPassword()); // 비밀번호는 필요 없다면 제외 가능 + + // AiwaKey 리스트를 AiwaKeyResponseDto 리스트로 변환 + List aiwaKeyResponseDtoList = member.getAiwaKeys().stream() + .map(AiwaKeyResponseDto::toDto) + .collect(Collectors.toList()); + memberResponseDto.setAiwaKeys(aiwaKeyResponseDtoList); + + return memberResponseDto; } -} \ No newline at end of file +} diff --git a/src/main/java/AIWA/MCPBackend_Member/Entity/AiwaKey.java b/src/main/java/AIWA/MCPBackend_Member/Entity/AiwaKey.java new file mode 100644 index 0000000..65f6823 --- /dev/null +++ b/src/main/java/AIWA/MCPBackend_Member/Entity/AiwaKey.java @@ -0,0 +1,37 @@ +package AIWA.MCPBackend_Member.Entity; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Getter +@Setter +@NoArgsConstructor +public class AiwaKey { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "aiwa_key_id") + private Long id; + + @Column(nullable = false) + private String companyName; + + private String accessKey; + private String secretKey; + private String gcpKeyPath; + + @ManyToOne + @JoinColumn(name = "member_id") + private Member member; + + public AiwaKey(String companyName, String accessKey, String secretKey, String gcpKeyPath, Member member) { + this.companyName = companyName; + this.accessKey = accessKey; + this.secretKey = secretKey; + this.gcpKeyPath = gcpKeyPath; + this.member = member; + } +} diff --git a/src/main/java/AIWA/MCPBackend_Member/Entity/Member.java b/src/main/java/AIWA/MCPBackend_Member/Entity/Member.java index d9335f9..efe7deb 100644 --- a/src/main/java/AIWA/MCPBackend_Member/Entity/Member.java +++ b/src/main/java/AIWA/MCPBackend_Member/Entity/Member.java @@ -6,6 +6,9 @@ import lombok.NoArgsConstructor; import lombok.Setter; +import java.util.ArrayList; +import java.util.List; + @Entity @Getter @@ -27,15 +30,12 @@ public class Member { @Column(unique = true, nullable = false) private String email; - @Column(length = 1000) - private String access_key; - @Column(length = 1000) - private String secret_key; + @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true) + private List aiwaKeys = new ArrayList<>(); public Member(String name, String password, String email) { this.name = name; this.password = password; this.email = email; } - -} +} \ No newline at end of file diff --git a/src/main/java/AIWA/MCPBackend_Member/Service/member/MemberService.java b/src/main/java/AIWA/MCPBackend_Member/Service/member/MemberService.java index 3b7da9e..0b88b9c 100644 --- a/src/main/java/AIWA/MCPBackend_Member/Service/member/MemberService.java +++ b/src/main/java/AIWA/MCPBackend_Member/Service/member/MemberService.java @@ -3,6 +3,7 @@ import AIWA.MCPBackend_Member.Dto.MemberDeleteRequestDto; import AIWA.MCPBackend_Member.Dto.MemberRequestDto; +import AIWA.MCPBackend_Member.Entity.AiwaKey; import AIWA.MCPBackend_Member.Entity.Member; import AIWA.MCPBackend_Member.Repository.MemberRepository; import AIWA.MCPBackend_Member.Service.s3.S3Service; @@ -46,10 +47,6 @@ public void deleteMember(MemberDeleteRequestDto deleteMemberRequestDto) { // 특정 회원 조회 - public Optional getMemberById(Long id) { - return memberRepository.findById(id); - } - public Member getMemberByEmail(String email) { return memberRepository.findByEmail(email); } @@ -59,23 +56,52 @@ public List getAllMembers() { } - public Member addOrUpdateKeys(String email,String access_key,String secret_key) { - + public String addOrUpdateAwsAndGcpKey(String email, String accessKey, String secretKey, String gcpKeyContent) { Member member = getMemberByEmail(email); - member.setAccess_key(access_key); - member.setSecret_key(secret_key); - s3Service.createTfvarsFile(email,access_key,secret_key); + + // 키가 하나의 회사에 대해 AWS와 GCP를 모두 처리할 수 있도록 합니다. + Optional existingAwsKey = member.getAiwaKeys().stream() + .filter(key -> "AWS".equalsIgnoreCase(key.getCompanyName())) + .findFirst(); + + if (existingAwsKey.isPresent()) { + AiwaKey awsKey = existingAwsKey.get(); + awsKey.setAccessKey(accessKey); + awsKey.setSecretKey(secretKey); + // GCP 키를 추가할 경우 GCP Key Path를 업데이트 + awsKey.setGcpKeyPath(s3Service.uploadGcpKeyFile(email, gcpKeyContent)); + } else { + AiwaKey newKey = new AiwaKey("AWS", accessKey, secretKey, s3Service.uploadGcpKeyFile(email, gcpKeyContent), member); + member.getAiwaKeys().add(newKey); + } + + member = memberRepository.save(member); + + return "AWS and GCP keys have been successfully added or updated."; + } + + + + public Member removeAwsKey(Long memberId) { + Member member = memberRepository.findById(memberId) + .orElseThrow(() -> new RuntimeException("Member not found")); + + member.getAiwaKeys().removeIf(key -> "AWS".equalsIgnoreCase(key.getCompanyName())); + return memberRepository.save(member); } - // Access Key와 Secret Key 삭제 - public Member removeKeys(Long id) { - Member member = memberRepository.findById(id) + + public Member removeGcpKey(Long memberId) { + Member member = memberRepository.findById(memberId) .orElseThrow(() -> new RuntimeException("Member not found")); - member.setAccess_key(null); - member.setSecret_key(null); + // GCP 키를 삭제하고 S3에서 GCP 키 파일도 삭제 + member.getAiwaKeys().removeIf(key -> "GCP".equalsIgnoreCase(key.getCompanyName())); + s3Service.deleteGcpKeyFile(member.getEmail()); return memberRepository.save(member); } + + } \ No newline at end of file diff --git a/src/main/java/AIWA/MCPBackend_Member/Service/s3/S3Service.java b/src/main/java/AIWA/MCPBackend_Member/Service/s3/S3Service.java index 893a29c..36d9996 100644 --- a/src/main/java/AIWA/MCPBackend_Member/Service/s3/S3Service.java +++ b/src/main/java/AIWA/MCPBackend_Member/Service/s3/S3Service.java @@ -1,11 +1,13 @@ package AIWA.MCPBackend_Member.Service.s3; - import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.model.*; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; + @Service @RequiredArgsConstructor public class S3Service { @@ -13,14 +15,13 @@ public class S3Service { private final AmazonS3 s3Client; private final String bucketName = "aiwa-terraform"; + // 사용자 디렉토리 생성 public void createUserDirectory(String userId) { String userPrefix = "users/" + userId + "/"; - // 초기 main.tf 및 terraform.tfstate 파일을 업로드합니다 uploadInitialFiles(userPrefix); } private void uploadInitialFiles(String userPrefix) { - // 초기 main.tf 파일 String mainTfContent = """ variable "aws_access_key" { description = "AWS Access Key" @@ -34,44 +35,69 @@ private void uploadInitialFiles(String userPrefix) { provider "aws" { region = "ap-northeast-2" - access_key = var.aws_access_key // 변수로 AWS Access Key 제공 - secret_key = var.aws_secret_key // 변수로 AWS Secret Key 제공 + access_key = var.aws_access_key + secret_key = var.aws_secret_key } """; s3Client.putObject(bucketName, userPrefix + "main.tf", mainTfContent); + } + + // AWS tfvars 파일 생성 + public String createAwsTfvarsFile(String userId, String accessKey, String secretKey) { + String userPrefix = "users/" + userId + "/"; + String tfvarsContent = String.format(""" + aws_access_key = "%s" + aws_secret_key = "%s" + """, accessKey, secretKey); -// // 빈 상태 파일 -// String emptyState = "{}"; -// s3Client.putObject(bucketName, userPrefix + "terraform.tfstate", emptyState); + String tfvarsKey = userPrefix + "aws_terraform.tfvars"; + s3Client.putObject(bucketName, tfvarsKey, tfvarsContent); + return s3Client.getUrl(bucketName, tfvarsKey).toString(); // S3 URL 반환 } - public void deleteUserDirectory(String userId) { + // GCP 자격 증명 파일 업로드 + public String uploadGcpKeyFile(String userId, String gcpKeyContent) { String userPrefix = "users/" + userId + "/"; + String gcpKeyFileKey = userPrefix + "gcp_credentials.json"; + byte[] gcpKeyBytes = gcpKeyContent.getBytes(StandardCharsets.UTF_8); + + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentLength(gcpKeyBytes.length); + s3Client.putObject(bucketName, gcpKeyFileKey, new ByteArrayInputStream(gcpKeyBytes), metadata); + + return s3Client.getUrl(bucketName, gcpKeyFileKey).toString(); // S3 URL 반환 + } + // GCP 키 파일 삭제 + public void deleteGcpKeyFile(String userId) { + String gcpKeyFileKey = "users/" + userId + "/gcp_credentials.json"; + if (s3Client.doesObjectExist(bucketName, gcpKeyFileKey)) { + s3Client.deleteObject(bucketName, gcpKeyFileKey); + } + } - // S3에서 해당 디렉터리(prefix)를 기준으로 모든 파일 목록을 가져옴 + // AWS tfvars 파일 삭제 + public void deleteAwsTfvarsFile(String userId) { + String awsTfvarsKey = "users/" + userId + "/aws_terraform.tfvars"; + if (s3Client.doesObjectExist(bucketName, awsTfvarsKey)) { + s3Client.deleteObject(bucketName, awsTfvarsKey); + } + } + + + // 사용자 디렉토리 삭제 + public void deleteUserDirectory(String userId) { + String userPrefix = "users/" + userId + "/"; ListObjectsV2Request request = new ListObjectsV2Request().withBucketName(bucketName).withPrefix(userPrefix); ListObjectsV2Result result; - // 모든 객체를 반복적으로 가져와 삭제 do { result = s3Client.listObjectsV2(request); for (S3ObjectSummary objectSummary : result.getObjectSummaries()) { s3Client.deleteObject(bucketName, objectSummary.getKey()); } request.setContinuationToken(result.getNextContinuationToken()); - } while (result.isTruncated()); // 계속해서 모든 객체를 삭제할 때까지 반복 - } - - - public void createTfvarsFile(String userId, String accessKey, String secretKey) { - String userPrefix = "users/" + userId + "/"; - String tfvarsContent = String.format(""" - aws_access_key = "%s" - aws_secret_key = "%s" - """, accessKey, secretKey); - - s3Client.putObject(bucketName, userPrefix + "terraform.tfvars", tfvarsContent); + } while (result.isTruncated()); } } \ No newline at end of file