diff --git a/build.gradle b/build.gradle index 9b7165f..32a36fb 100644 --- a/build.gradle +++ b/build.gradle @@ -1,71 +1,43 @@ plugins { - id 'java' - id 'org.springframework.boot' version '3.5.10' - id 'io.spring.dependency-management' version '1.1.7' - id 'org.asciidoctor.jvm.convert' version '4.0.5' + id 'java' + id 'org.springframework.boot' version '3.5.9' + id 'io.spring.dependency-management' version '1.1.7' } -group = 'com.spring-study' +group = 'com.example' version = '0.0.1-SNAPSHOT' -description = '채팅 어플리케이션' +description = 'chatting' java { - toolchain { - languageVersion = JavaLanguageVersion.of(17) - } + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } } configurations { - compileOnly { - extendsFrom annotationProcessor - } + compileOnly { + extendsFrom annotationProcessor + } } repositories { - mavenCentral() -} - -ext { - set('snippetsDir', file("build/generated-snippets")) - set('springCloudVersion', "2025.0.1") - set('tanzuScgExtensionsVersion', "1.0.1") + mavenCentral() } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' - implementation 'org.springframework.boot:spring-boot-starter-security' - implementation 'org.springframework.boot:spring-boot-starter-validation' - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework.boot:spring-boot-starter-web-services' - implementation 'com.vmware.tanzu.springcloudgateway.extensions:access-control' - implementation 'org.springframework.cloud:spring-cloud-starter-gateway-server-webflux' - compileOnly 'org.projectlombok:lombok' - developmentOnly 'org.springframework.boot:spring-boot-devtools' - runtimeOnly 'com.mysql:mysql-connector-j' - annotationProcessor 'org.projectlombok:lombok' - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testImplementation 'org.springframework.boot:spring-boot-testcontainers' - testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' - testImplementation 'org.springframework.security:spring-security-test' - testImplementation 'org.testcontainers:junit-jupiter' - testImplementation 'org.testcontainers:mysql' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' -} - -dependencyManagement { - imports { - mavenBom "com.vmware.tanzu.springcloudgateway.extensions:extensions-bom:${tanzuScgExtensionsVersion}" - mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" - } + implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + compileOnly 'org.projectlombok:lombok' + runtimeOnly 'com.mysql:mysql-connector-j' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.5' } tasks.named('test') { - outputs.dir snippetsDir - useJUnitPlatform() -} - -tasks.named('asciidoctor') { - inputs.dir snippetsDir - dependsOn test + useJUnitPlatform() } diff --git a/chatting b/chatting new file mode 160000 index 0000000..6208fa6 --- /dev/null +++ b/chatting @@ -0,0 +1 @@ +Subproject commit 6208fa6c5b4e0c122d210c971a824e55ce2974f0 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 1b33c55..61285a6 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index aaaabb3..19a6bde 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 23d15a9..adff685 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -172,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" diff --git a/gradlew.bat b/gradlew.bat index db3a6ac..c4bdd3a 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/src/main/java/com/example/chatting/ChattingApplication.java b/src/main/java/com/example/chatting/ChattingApplication.java new file mode 100644 index 0000000..e2bb7fe --- /dev/null +++ b/src/main/java/com/example/chatting/ChattingApplication.java @@ -0,0 +1,13 @@ +package com.example.chatting; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ChattingApplication { + + public static void main(String[] args) { + SpringApplication.run(ChattingApplication.class, args); + } + +} diff --git a/src/main/java/com/example/chatting/controller/FriendController.java b/src/main/java/com/example/chatting/controller/FriendController.java new file mode 100644 index 0000000..2425372 --- /dev/null +++ b/src/main/java/com/example/chatting/controller/FriendController.java @@ -0,0 +1,44 @@ +package com.example.chatting.controller; + +import com.example.chatting.domain.enums.FriendEnum; +import com.example.chatting.dto.response.FriendListResponseDto; +import com.example.chatting.service.FriendService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; + +@RequiredArgsConstructor +@RestController +@RequestMapping("/friends") +public class FriendController { + private final FriendService friendService; + + @GetMapping("") + public ResponseEntity> getFriendList(UUID uid) { + return ResponseEntity.ok(friendService.getFriendList(uid)); + } + + @GetMapping("/{name}") + public ResponseEntity> searchFriend(@PathVariable String name, UUID uid) { + return ResponseEntity.ok(friendService.searchFriend(uid, name)); + } + + @PatchMapping("/{id}/block") + public ResponseEntity blockFriend(@PathVariable UUID id, UUID uid) { + return ResponseEntity.ok(friendService.blockFriend(uid, id)); + } + + @PatchMapping("/{id}/hide") + public ResponseEntity hideFriend(@PathVariable UUID id, UUID uid) { + return ResponseEntity.ok(friendService.hideFriend(uid, id)); + } + + @GetMapping("/blacklist") + public ResponseEntity> getBlockFriendList(UUID uid) { + return ResponseEntity.ok(friendService.getBlockFriendList(uid)); + } + +} diff --git a/src/main/java/com/example/chatting/controller/FriendRequestController.java b/src/main/java/com/example/chatting/controller/FriendRequestController.java new file mode 100644 index 0000000..491862d --- /dev/null +++ b/src/main/java/com/example/chatting/controller/FriendRequestController.java @@ -0,0 +1,45 @@ +package com.example.chatting.controller; + +import com.example.chatting.domain.FriendRequest; +import com.example.chatting.domain.enums.FriendRequestEnum; +import com.example.chatting.dto.request.FriendRequestDto; +import com.example.chatting.dto.response.FriendRequestResponseDto; +import com.example.chatting.service.FriendRequestService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; + +@RequiredArgsConstructor +@RestController +@RequestMapping("/friend-requests") +public class FriendRequestController { + private final FriendRequestService friendRequestService; + + @PostMapping("") + public ResponseEntity sendFriend(@RequestBody FriendRequestDto friendRequestDto, UUID uid){ + friendRequestService.sendFriend(uid, friendRequestDto); + return ResponseEntity.ok("친구 요청 전송 성공"); + } + + @GetMapping("") + public ResponseEntity> requestFriendList(UUID uid) { + return ResponseEntity.ok(friendRequestService.requestFriendList(uid)); + } + + @PatchMapping("/{requestId}/accept") + public ResponseEntity acceptRequest(@PathVariable Long requestId, UUID uid) { + friendRequestService.acceptRequest(uid, requestId, FriendRequestEnum.ACCEPT); + return ResponseEntity.ok("친구 요청 수락"); + } + + @PatchMapping("/{requestId}/decline") + public ResponseEntity declineRequest(@PathVariable Long requestId, UUID uid) { + friendRequestService.acceptRequest(uid, requestId, FriendRequestEnum.DECLINE); + return ResponseEntity.ok("친구 요청 거절"); + } + +} diff --git a/src/main/java/com/example/chatting/domain/Friend.java b/src/main/java/com/example/chatting/domain/Friend.java new file mode 100644 index 0000000..75c7dd5 --- /dev/null +++ b/src/main/java/com/example/chatting/domain/Friend.java @@ -0,0 +1,52 @@ +package com.example.chatting.domain; + + +import com.example.chatting.domain.enums.FriendEnum; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.DynamicUpdate; + +import java.time.LocalDate; + +@Entity +@Table(name = "friend") +@NoArgsConstructor +@Getter +@DynamicUpdate +@Builder +@AllArgsConstructor +public class Friend { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne + @JoinColumn(name = "uid", nullable = false) + private User uid; + + @ManyToOne + @JoinColumn(name = "fid", nullable = false) + private User fid; + + @Column(name = "created_at") + private LocalDate createdAt; + + @Enumerated(EnumType.STRING) + private FriendEnum status; + + public Friend(User uid, User fid, LocalDate createdAt, FriendEnum status) { + this.uid = uid; + this.fid = fid; + this.createdAt = createdAt; + this.status = status; + } + + public void updateStatus(FriendEnum status) { + this.status = status; + } +} + diff --git a/src/main/java/com/example/chatting/domain/FriendRequest.java b/src/main/java/com/example/chatting/domain/FriendRequest.java new file mode 100644 index 0000000..819bf4a --- /dev/null +++ b/src/main/java/com/example/chatting/domain/FriendRequest.java @@ -0,0 +1,48 @@ +package com.example.chatting.domain; + +import com.example.chatting.domain.enums.FriendEnum; +import com.example.chatting.domain.enums.FriendRequestEnum; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.time.LocalDate; + +@Entity +@Table(name = "friend_request") +@Getter +@NoArgsConstructor +@Builder +@AllArgsConstructor +public class FriendRequest { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne + @JoinColumn(name = "requester", nullable = false) + private User requester; //요청 보낸 사람 + + @ManyToOne + @JoinColumn(name = "respondent", nullable = false) + private User respondent; //요청 받는 사람 + + @Enumerated(EnumType.STRING) + private FriendRequestEnum status; + + @Column(name = "created_at") + private LocalDate createdAt; + + public FriendRequest(LocalDate createdAt, FriendRequestEnum status, User respondent, User requester) { + this.createdAt = createdAt; + this.status = status; + this.respondent = respondent; + this.requester = requester; + } + + public void updateStatus(FriendRequestEnum status) { + this.status = status; + } +} diff --git a/src/main/java/com/example/chatting/domain/User.java b/src/main/java/com/example/chatting/domain/User.java new file mode 100644 index 0000000..9d1a579 --- /dev/null +++ b/src/main/java/com/example/chatting/domain/User.java @@ -0,0 +1,43 @@ +package com.example.chatting.domain; + + +import jakarta.persistence.*; +import jakarta.validation.constraints.Email; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.DynamicUpdate; + +import java.util.UUID; + + +//임시 +@Entity +@Table(name = "users") +@NoArgsConstructor +@Getter +@DynamicUpdate +@Builder +@AllArgsConstructor +public class User { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name="email") + @Email + private String email; + + @Column(name = "name") + private String name; + + @Column(name = "uuid") + private UUID uuid; + + public User(UUID uuid, String name, String email) { + this.uuid = uuid; + this.name = name; + this.email = email; + } +} diff --git a/src/main/java/com/example/chatting/domain/enums/FriendEnum.java b/src/main/java/com/example/chatting/domain/enums/FriendEnum.java new file mode 100644 index 0000000..a5f6663 --- /dev/null +++ b/src/main/java/com/example/chatting/domain/enums/FriendEnum.java @@ -0,0 +1,5 @@ +package com.example.chatting.domain.enums; + +public enum FriendEnum { + NORMAL, BLOCKED, HIDDEN +} diff --git a/src/main/java/com/example/chatting/domain/enums/FriendRequestEnum.java b/src/main/java/com/example/chatting/domain/enums/FriendRequestEnum.java new file mode 100644 index 0000000..c7447ab --- /dev/null +++ b/src/main/java/com/example/chatting/domain/enums/FriendRequestEnum.java @@ -0,0 +1,5 @@ +package com.example.chatting.domain.enums; + +public enum FriendRequestEnum { + ACCEPT, PENDING, DECLINE +} diff --git a/src/main/java/com/example/chatting/dto/request/FriendRequestDto.java b/src/main/java/com/example/chatting/dto/request/FriendRequestDto.java new file mode 100644 index 0000000..ec6d2f9 --- /dev/null +++ b/src/main/java/com/example/chatting/dto/request/FriendRequestDto.java @@ -0,0 +1,22 @@ +package com.example.chatting.dto.request; + +import com.example.chatting.domain.FriendRequest; +import com.example.chatting.domain.User; +import com.example.chatting.domain.enums.FriendRequestEnum; + +import java.time.LocalDate; +import java.util.UUID; + +public record FriendRequestDto ( + //누구한테 친구를 요청할지 입력 + UUID respondent +){ + public FriendRequest toEntity(User requester, User respondent) { + return FriendRequest.builder() + .requester(requester) + .respondent(respondent) + .createdAt(LocalDate.now()) + .status(FriendRequestEnum.PENDING) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/chatting/dto/response/FriendListResponseDto.java b/src/main/java/com/example/chatting/dto/response/FriendListResponseDto.java new file mode 100644 index 0000000..e62fea1 --- /dev/null +++ b/src/main/java/com/example/chatting/dto/response/FriendListResponseDto.java @@ -0,0 +1,19 @@ +package com.example.chatting.dto.response; + +import com.example.chatting.domain.Friend; + +public record FriendListResponseDto ( + Long id, + Long friendId, //친구 id + String name, //친구 이름 + String email //친구 이메일 +) { + public static FriendListResponseDto fromEntity(Friend friend) { + return new FriendListResponseDto( + friend.getId(), + friend.getFid().getId(), + friend.getFid().getName(), + friend.getFid().getEmail() + ); + } +} diff --git a/src/main/java/com/example/chatting/dto/response/FriendRequestResponseDto.java b/src/main/java/com/example/chatting/dto/response/FriendRequestResponseDto.java new file mode 100644 index 0000000..2c5c47f --- /dev/null +++ b/src/main/java/com/example/chatting/dto/response/FriendRequestResponseDto.java @@ -0,0 +1,21 @@ +package com.example.chatting.dto.response; + +import com.example.chatting.domain.FriendRequest; + +import java.time.LocalDate; + +public record FriendRequestResponseDto ( + Long id, + String name, //요청 보낸 사람 이름 + String email, //요청 보낸 사람 email + LocalDate createdAt //요청 보낸 날짜 +){ + public static FriendRequestResponseDto fromEntity(FriendRequest friendRequest) { + return new FriendRequestResponseDto( + friendRequest.getId(), + friendRequest.getRequester().getName(), + friendRequest.getRequester().getEmail(), + friendRequest.getCreatedAt() + ); + } +} diff --git a/src/main/java/com/example/chatting/repository/FriendRepository.java b/src/main/java/com/example/chatting/repository/FriendRepository.java new file mode 100644 index 0000000..3606289 --- /dev/null +++ b/src/main/java/com/example/chatting/repository/FriendRepository.java @@ -0,0 +1,26 @@ +package com.example.chatting.repository; + +import com.example.chatting.domain.Friend; +import com.example.chatting.domain.User; +import com.example.chatting.domain.enums.FriendEnum; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface FriendRepository extends JpaRepository { + + //친구 리스트 조회, 친구 검색, 친구 차단, 친구 숨김 + // 친구 리스트 조회: id로 친구 리스트 조회 + //친구 검색: id로 친구 조회 + //친구 차단: id로 친구 차단 + //친구 숨김: id로 친구 숨김 + + List findFriendByUid(User uid); //유저id로 유저의 친구 리스트 조회 + Optional findFriendByUidAndFid(User uid, User fid); //관계 확인 + + //이름으로 친구 검색 + List findByUidAndStatusAndFid_NameContaining(User uid, FriendEnum status, String name); +} diff --git a/src/main/java/com/example/chatting/repository/FriendRequestRepository.java b/src/main/java/com/example/chatting/repository/FriendRequestRepository.java new file mode 100644 index 0000000..6e2ad0a --- /dev/null +++ b/src/main/java/com/example/chatting/repository/FriendRequestRepository.java @@ -0,0 +1,26 @@ +package com.example.chatting.repository; + +import com.example.chatting.domain.FriendRequest; +import com.example.chatting.domain.User; +import com.example.chatting.domain.enums.FriendRequestEnum; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface FriendRequestRepository extends JpaRepository { + //친구 요청 + //친구 요청 수락 + //친구 요청 거절 + + //친구 요청을 보내려면 "이미 보낸 상대인지" 확인 필요 + boolean existsByRequesterAndRespondent(User requester, User respondent); + + //받은 요청 리스트 + List findByRespondentAndStatus(User respondent, FriendRequestEnum status); + + //수락/거절 + Optional findById(Long id); +} diff --git a/src/main/java/com/example/chatting/repository/UserRepository.java b/src/main/java/com/example/chatting/repository/UserRepository.java new file mode 100644 index 0000000..f870098 --- /dev/null +++ b/src/main/java/com/example/chatting/repository/UserRepository.java @@ -0,0 +1,12 @@ +package com.example.chatting.repository; + +import com.example.chatting.domain.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.UUID; + +@Repository +public interface UserRepository extends JpaRepository { + public User findUsersByUuid(UUID uuid); +} diff --git a/src/main/java/com/example/chatting/service/FriendRequestService.java b/src/main/java/com/example/chatting/service/FriendRequestService.java new file mode 100644 index 0000000..ab74d5d --- /dev/null +++ b/src/main/java/com/example/chatting/service/FriendRequestService.java @@ -0,0 +1,90 @@ +package com.example.chatting.service; + +import com.example.chatting.domain.Friend; +import com.example.chatting.domain.FriendRequest; +import com.example.chatting.domain.User; +import com.example.chatting.domain.enums.FriendEnum; +import com.example.chatting.domain.enums.FriendRequestEnum; +import com.example.chatting.dto.request.FriendRequestDto; +import com.example.chatting.dto.response.FriendListResponseDto; +import com.example.chatting.dto.response.FriendRequestResponseDto; +import com.example.chatting.repository.FriendRepository; +import com.example.chatting.repository.FriendRequestRepository; +import com.example.chatting.repository.UserRepository; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.UUID; + +@Service +@Transactional +@RequiredArgsConstructor +public class FriendRequestService { + private final FriendRepository friendRepository; + private final UserRepository userRepository; + private final FriendRequestRepository friendRequestRepository; + + //친구 요청 전송 + public void sendFriend(UUID uid, FriendRequestDto friendRequestDto) { + User requester = userRepository.findUsersByUuid(uid); + User respondent = userRepository.findUsersByUuid(friendRequestDto.respondent()); + + if(friendRepository.findFriendByUidAndFid(requester, respondent).isPresent()) { + throw new IllegalArgumentException("이미 친구 관계입니다. "); + } + + if(friendRequestRepository.existsByRequesterAndRespondent(requester, respondent )) { + throw new IllegalArgumentException("이미 친구 요청을 보냈습니다. "); + } + + friendRequestRepository.save(friendRequestDto.toEntity(requester, respondent)); + } + + //받은 요청 리스트 조회 + public List requestFriendList(UUID uid) { + User user = userRepository.findUsersByUuid(uid); + List requestList = friendRequestRepository.findByRespondentAndStatus(user, FriendRequestEnum.PENDING); + List requestDtoList = requestList.stream() + .map(FriendRequestResponseDto::fromEntity) + .toList(); + return requestDtoList; + + } + + //받은 요청 수락, 거절 + public void acceptRequest(UUID uid, Long requestId, FriendRequestEnum now) { + FriendRequest friendRequest = friendRequestRepository.findById(requestId).orElseThrow(() -> new IllegalArgumentException("존재하지 않는 친구 요청")); + + if(!friendRequest.getRespondent().getUuid().equals(uid)) { + throw new IllegalArgumentException("요청 수락 권한 없음"); + } + + if(friendRequest.getStatus()!=FriendRequestEnum.PENDING) { + throw new IllegalArgumentException("이미 처리된 요청"); + } + + if(now == FriendRequestEnum.ACCEPT) { + friendRequest.updateStatus(FriendRequestEnum.ACCEPT); + + Friend me = Friend.builder() + .uid(friendRequest.getRespondent()) //나 + .fid(friendRequest.getRequester()) //너 + .status(FriendEnum.NORMAL) + .build(); + + Friend you = Friend.builder() + .uid(friendRequest.getRequester()) //너 + .fid(friendRequest.getRespondent()) //나(유저 본인) + .status(FriendEnum.NORMAL) + .build(); + + friendRepository.save(me); + friendRepository.save(you); + } else { + friendRequest.updateStatus(FriendRequestEnum.DECLINE); + } + } + +} diff --git a/src/main/java/com/example/chatting/service/FriendService.java b/src/main/java/com/example/chatting/service/FriendService.java new file mode 100644 index 0000000..7030cd0 --- /dev/null +++ b/src/main/java/com/example/chatting/service/FriendService.java @@ -0,0 +1,100 @@ +package com.example.chatting.service; + +import com.example.chatting.domain.Friend; +import com.example.chatting.domain.User; +import com.example.chatting.domain.enums.FriendEnum; +import com.example.chatting.dto.response.FriendListResponseDto; +import com.example.chatting.repository.FriendRepository; +import com.example.chatting.repository.UserRepository; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +@Service +@Transactional +@RequiredArgsConstructor +public class FriendService { + private final FriendRepository friendRepository; + private final UserRepository userRepository; + + //친구 리스트 조회 + public List getFriendList(UUID uid) { + User user = userRepository.findUsersByUuid(uid); + List friendList = friendRepository.findFriendByUid(user); + + List list = new ArrayList<>(); + for(Friend friend : friendList) { + if(friend.getStatus() == FriendEnum.NORMAL) { + FriendListResponseDto dto = FriendListResponseDto.fromEntity(friend); + list.add(dto); + } + } + + return list; + } + + //친구 검색 - 이름으로 검색해야함 + public List searchFriend(UUID uid, String name) { + User user = userRepository.findUsersByUuid(uid); + List list = friendRepository.findByUidAndStatusAndFid_NameContaining(user, FriendEnum.NORMAL, name); + + if(list.isEmpty()) { + throw new IllegalArgumentException("검색 결과가 없습니다. "); + } + + List dtoList = list.stream() + .map(FriendListResponseDto::fromEntity) + .toList(); + + return dtoList; + } + + //친구 차단 + public FriendListResponseDto blockFriend(UUID uid, UUID fid) { + User user = userRepository.findUsersByUuid(uid); + User friend = userRepository.findUsersByUuid(fid); + + Friend isFriend = friendRepository.findFriendByUidAndFid(user, friend) + .orElseThrow(() -> new IllegalArgumentException("친구가 아닙니다. ")); + + if(isFriend.getStatus() == FriendEnum.BLOCKED) { + isFriend.updateStatus(FriendEnum.NORMAL); + } else isFriend.updateStatus(FriendEnum.BLOCKED); + + return FriendListResponseDto.fromEntity(isFriend); + } + + //친구 숨김 + public FriendListResponseDto hideFriend(UUID uid, UUID fid) { + User user = userRepository.findUsersByUuid(uid); + User friend = userRepository.findUsersByUuid(fid); + + Friend isFriend = friendRepository.findFriendByUidAndFid(user, friend) + .orElseThrow(() -> new IllegalArgumentException("친구가 아닙니다. ")); + + if(isFriend.getStatus() == FriendEnum.HIDDEN) { + isFriend.updateStatus(FriendEnum.NORMAL); + } else isFriend.updateStatus(FriendEnum.HIDDEN); + return FriendListResponseDto.fromEntity(isFriend); + } + + //숨김/차단 친구 리스트 + public List getBlockFriendList(UUID uid) { + User user = userRepository.findUsersByUuid(uid); + List list = friendRepository.findFriendByUid(user); + + List blockList = new ArrayList<>(); + for(Friend friend : list) { + if(friend.getStatus() == FriendEnum.HIDDEN || friend.getStatus() == FriendEnum.BLOCKED) { + FriendListResponseDto dto = FriendListResponseDto.fromEntity(friend); + blockList.add(dto); + } + } + return blockList; + } +} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index e0735a7..d4b6522 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -1,3 +1,14 @@ spring: - application: - name: chatting + datasource: + url: jdbc:mysql://localhost:3306/spring?useSSL=false&allowPublicKeyRetrieval=true + username: root + password: 1234 + driver-class-name: com.mysql.cj.jdbc.Driver + jpa: + hibernate: + ddl-auto: update + properties: + hibernate: + show_sql: true + format_sql: true + default_batch_fetch_size: 100 \ No newline at end of file diff --git a/src/test/java/com/example/chatting/ChattingApplicationTests.java b/src/test/java/com/example/chatting/ChattingApplicationTests.java new file mode 100644 index 0000000..b5baee4 --- /dev/null +++ b/src/test/java/com/example/chatting/ChattingApplicationTests.java @@ -0,0 +1,13 @@ +package com.example.chatting; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ChattingApplicationTests { + + @Test + void contextLoads() { + } + +}