diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..a178c9f Binary files /dev/null and b/.DS_Store differ diff --git a/.gradle/8.1.1/checksums/checksums.lock b/.gradle/8.1.1/checksums/checksums.lock deleted file mode 100644 index c860a62..0000000 Binary files a/.gradle/8.1.1/checksums/checksums.lock and /dev/null differ diff --git a/.gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock b/.gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock deleted file mode 100644 index aea0c51..0000000 Binary files a/.gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock and /dev/null differ diff --git a/.gradle/8.1.1/executionHistory/executionHistory.lock b/.gradle/8.1.1/executionHistory/executionHistory.lock deleted file mode 100644 index 27b0e26..0000000 Binary files a/.gradle/8.1.1/executionHistory/executionHistory.lock and /dev/null differ diff --git a/.gradle/8.1.1/fileChanges/last-build.bin b/.gradle/8.1.1/fileChanges/last-build.bin deleted file mode 100644 index f76dd23..0000000 Binary files a/.gradle/8.1.1/fileChanges/last-build.bin and /dev/null differ diff --git a/.gradle/8.1.1/fileHashes/fileHashes.lock b/.gradle/8.1.1/fileHashes/fileHashes.lock deleted file mode 100644 index 22cabd2..0000000 Binary files a/.gradle/8.1.1/fileHashes/fileHashes.lock and /dev/null differ diff --git a/.gradle/8.1.1/gc.properties b/.gradle/8.1.1/gc.properties deleted file mode 100644 index e69de29..0000000 diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock deleted file mode 100644 index 6394df6..0000000 Binary files a/.gradle/buildOutputCleanup/buildOutputCleanup.lock and /dev/null differ diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties deleted file mode 100644 index d8d5482..0000000 --- a/.gradle/buildOutputCleanup/cache.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon Jul 03 14:30:27 KST 2023 -gradle.version=8.1.1 diff --git a/.gradle/vcs-1/gc.properties b/.gradle/vcs-1/gc.properties deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/$CACHE_FILE$ b/.idea/$CACHE_FILE$ deleted file mode 100644 index f9784d3..0000000 --- a/.idea/$CACHE_FILE$ +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - Android - - - - - - \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index 37e6a33..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -DongnaeFriend \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index a4b7174..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml deleted file mode 100644 index d68d958..0000000 --- a/.idea/dbnavigator.xml +++ /dev/null @@ -1,463 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/dictionaries b/.idea/dictionaries deleted file mode 100644 index 149349d..0000000 --- a/.idea/dictionaries +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index 859c9b3..0000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml deleted file mode 100644 index fdc392f..0000000 --- a/.idea/jarRepositories.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 4bc4fc6..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/build.gradle b/build.gradle index 689a83e..ba1dac1 100644 --- a/build.gradle +++ b/build.gradle @@ -2,8 +2,10 @@ plugins { id 'java' id 'org.springframework.boot' version '2.7.13' id 'io.spring.dependency-management' version '1.0.15.RELEASE' + id "com.ewerk.gradle.plugins.querydsl" version "1.0.10" } + group = 'com.umc' version = '0.0.1-SNAPSHOT' @@ -26,16 +28,52 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-web' + + // querydsl 추가 + implementation "com.querydsl:querydsl-jpa:5.0.0" + implementation "com.querydsl:querydsl-apt:5.0.0" + compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' + + //gson + implementation 'com.google.code.gson:gson:2.8.8' + + //jwt + implementation 'io.jsonwebtoken:jjwt:0.9.1' + + //thymeleaf + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' } tasks.named('test') { useJUnitPlatform() } + + jar { enabled = false } + +// Qtype 생성 경로 +def querydslDir = "$buildDir/generated/querydsl" +querydsl { + jpa = true + querydslSourcesDir = querydslDir +} +sourceSets { + main.java.srcDir querydslDir +} +compileQuerydsl{ + options.annotationProcessorPath = configurations.querydsl +} +configurations { + compileOnly { + extendsFrom annotationProcessor + } + querydsl.extendsFrom compileClasspath +} + diff --git a/out/production/classes/com/umc/DongnaeFriend/DongnaeFriendApplication.class b/out/production/classes/com/umc/DongnaeFriend/DongnaeFriendApplication.class deleted file mode 100644 index 9880d22..0000000 Binary files a/out/production/classes/com/umc/DongnaeFriend/DongnaeFriendApplication.class and /dev/null differ diff --git a/out/production/classes/com/umc/DongnaeFriend/HealthCheckController.class b/out/production/classes/com/umc/DongnaeFriend/HealthCheckController.class deleted file mode 100644 index 4f3fc49..0000000 Binary files a/out/production/classes/com/umc/DongnaeFriend/HealthCheckController.class and /dev/null differ diff --git a/out/production/classes/com/umc/DongnaeFriend/domain/user/entity/User.class b/out/production/classes/com/umc/DongnaeFriend/domain/user/entity/User.class deleted file mode 100644 index df7c895..0000000 Binary files a/out/production/classes/com/umc/DongnaeFriend/domain/user/entity/User.class and /dev/null differ diff --git a/out/production/resources/application.yml b/out/production/resources/application.yml deleted file mode 100644 index 7878137..0000000 --- a/out/production/resources/application.yml +++ /dev/null @@ -1,20 +0,0 @@ -logging: - level: - com.example.carrotmarket: debug - org.hibernate.SQL: debug - -spring: - jpa: - properties: - hibernate: - format_sql: true ---- -# Settings for local -spring: - datasource: - url: jdbc:mysql://localhost:3306/dongnae?characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=false - username: dongnae - password: df1234 - driver-class-name: com.mysql.cj.jdbc.Driver - jpa: - hibernate.ddl-auto: create \ No newline at end of file diff --git a/out/test/classes/com/umc/DongnaeFriend/DongnaeFriendApplicationTests.class b/out/test/classes/com/umc/DongnaeFriend/DongnaeFriendApplicationTests.class deleted file mode 100644 index 2e115dc..0000000 Binary files a/out/test/classes/com/umc/DongnaeFriend/DongnaeFriendApplicationTests.class and /dev/null differ diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000..0f989cb Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/main/.DS_Store b/src/main/.DS_Store new file mode 100644 index 0000000..60811ad Binary files /dev/null and b/src/main/.DS_Store differ diff --git a/src/main/java/com/umc/DongnaeFriend/KakaoTokenController.java b/src/main/java/com/umc/DongnaeFriend/KakaoTokenController.java new file mode 100644 index 0000000..d9668b9 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/KakaoTokenController.java @@ -0,0 +1,85 @@ +package com.umc.DongnaeFriend; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.umc.DongnaeFriend.domain.user.dto.UserDto; +import com.umc.DongnaeFriend.domain.user.service.KakaoService; +import com.umc.DongnaeFriend.domain.user.service.UserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.http.HttpServletResponse; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Controller +@RequestMapping("") +public class KakaoTokenController { + + @Autowired + private UserService userService; + + @Autowired + private KakaoService kakaoService; + + @GetMapping("/kakao") + public String kakologin(Model model, HttpServletResponse response) { + response.setContentType(MediaType.TEXT_HTML_VALUE); + + return "html/index"; + } + + @GetMapping("/callback") + public String callback(Model model, @RequestParam("code") String code) throws IOException { + + try { +//------kakao POST 요청------ + String reqURL = "https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id=1ad317e194df665ca44dcb82d11a7093&code=" + code; + URL url = new URL(reqURL); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + + + BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); + + String line = ""; + String result = ""; + + while ((line = br.readLine()) != null) { + result += line; + } + + ObjectMapper objectMapper = new ObjectMapper(); + Map jsonMap = objectMapper.readValue(result, new TypeReference>() { + }); + + String accessToken = (String) jsonMap.get("access_token"); + + //-------------------------------------------------서버 로그인---------------------------------------------------- + + HashMap userInfo = kakaoService.getUserInfo(accessToken); + UserDto.Response response = userService.userValidation(userInfo); + + model.addAttribute("token","Bearer "+ response.getAccessToken()); + + return "html/token"; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + + } + +} diff --git a/src/main/java/com/umc/DongnaeFriend/config/JwtConfig.java b/src/main/java/com/umc/DongnaeFriend/config/JwtConfig.java new file mode 100644 index 0000000..902da00 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/config/JwtConfig.java @@ -0,0 +1,12 @@ +package com.umc.DongnaeFriend.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class JwtConfig { + + @Value("${jwt.secret-key}") + public String SECRET_KEY; + +} diff --git a/src/main/java/com/umc/DongnaeFriend/config/QuerydslConfiguration.java b/src/main/java/com/umc/DongnaeFriend/config/QuerydslConfiguration.java new file mode 100644 index 0000000..bcfc8e4 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/config/QuerydslConfiguration.java @@ -0,0 +1,20 @@ +package com.umc.DongnaeFriend.config; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +@Configuration +public class QuerydslConfiguration { + + @PersistenceContext + private EntityManager entityManager; + + @Bean + public JPAQueryFactory jpaQueryFactory() { + return new JPAQueryFactory(entityManager); + } +} \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/config/SecurityConfig.java b/src/main/java/com/umc/DongnaeFriend/config/SecurityConfig.java new file mode 100644 index 0000000..0f9a562 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/config/SecurityConfig.java @@ -0,0 +1,35 @@ +package com.umc.DongnaeFriend.config; + + +import com.umc.DongnaeFriend.global.security.JwtTokenFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; + +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +@EnableWebSecurity +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Autowired + private JwtTokenFilter jwtTokenFilter; + + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf().disable() + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + .antMatchers("/user/login").permitAll() // 인증 없이 접근 허용하는 URL + .antMatchers("/user/reissuance").permitAll() // 인증 없이 접근 허용하는 URL + .antMatchers("/kakao").permitAll() // 카카오 토큰 추출(임시) + .antMatchers("/callback").permitAll() // 카카오 토큰 추출(임시) + .anyRequest().authenticated(); // 그 외의 URL은 인증 필요 + http.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class); + } + + // 나머지 코드는 이전 예제와 동일 +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java new file mode 100644 index 0000000..ee6b422 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/AccountBookController.java @@ -0,0 +1,49 @@ +package com.umc.DongnaeFriend.domain.account.book.controller; + +import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; +import com.umc.DongnaeFriend.domain.account.book.service.AccountBookService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/account") +public class AccountBookController { + + private final AccountBookService accountBookService; + + @GetMapping("/budget") + public ResponseEntity getBudget(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month){ + return ResponseEntity.status(HttpStatus.OK).body(accountBookService.getBudget(year, month)); + } + + @PostMapping("/budget") + public ResponseEntity createBudget(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month, + @RequestParam(value = "amount", required = false) Long budget){ + accountBookService.createBudget(year, month, budget); + + return new ResponseEntity<>(HttpStatus.OK); + } + + @PutMapping("/budget") + public ResponseEntity updateBudget(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month, + @RequestParam(value = "amount", required = false) Long budget){ + accountBookService.updateBudget(year, month, budget); + + return new ResponseEntity<>(HttpStatus.OK); + } + + @GetMapping("/all") + public ResponseEntity getAccountBook(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month){ + + return ResponseEntity.status(HttpStatus.OK).body(accountBookService.getAccountBookResponse(year, month)); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/MemoController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/MemoController.java new file mode 100644 index 0000000..b466809 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/MemoController.java @@ -0,0 +1,51 @@ +package com.umc.DongnaeFriend.domain.account.book.controller; + +import com.umc.DongnaeFriend.domain.account.book.dto.MemoDto; +import com.umc.DongnaeFriend.domain.account.book.service.MemoService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/account/memo") +public class MemoController { + + private final MemoService memoService; + + /** + * 유저 권한 확인 필요 + */ + @GetMapping + public ResponseEntity getMemoList(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month){ + return ResponseEntity.status(HttpStatus.OK).body(memoService.getMemoList(year, month)); + } + + @PostMapping + public ResponseEntity createMemo(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month, + @RequestBody MemoDto.MemoRequest requestDto){ + memoService.createMemo(requestDto, year,month); + + return new ResponseEntity<>(HttpStatus.OK); + } + + @PutMapping + public ResponseEntity updateMemo(@RequestParam(value = "id", required = false) Long id, + @RequestBody MemoDto.MemoRequest requestDto){ + memoService.updateMemo(requestDto, id); + + return new ResponseEntity<>(HttpStatus.OK); + } + + @DeleteMapping + public ResponseEntity deleteMemo(@RequestParam(value = "id", required = false) Long id){ + memoService.deleteMemo(id); + + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/TransactionController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/TransactionController.java new file mode 100644 index 0000000..e5a517e --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/controller/TransactionController.java @@ -0,0 +1,48 @@ +package com.umc.DongnaeFriend.domain.account.book.controller; + + +import com.umc.DongnaeFriend.domain.account.book.dto.TransactionDto; +import com.umc.DongnaeFriend.domain.account.book.service.TransactionService; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.transaction.Transactional; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/account") +public class TransactionController { + + private final TransactionService transactionService; + + @PostMapping + public ResponseEntity createTransaction(@RequestBody TransactionDto.TransactionRequest request){ + transactionService.createTransaction(request); + + return new ResponseEntity<>(HttpStatus.OK); + + } + + @GetMapping + public ResponseEntity getTransaction(@RequestParam(value = "year", required = false) Integer year, + @RequestParam(value = "month", required = false) Integer month, + @RequestParam(value = "day", required = false) Integer day, Pageable pageable){ + return ResponseEntity.status(HttpStatus.OK).body(transactionService.getTransactions(year, month, day, pageable)); + } + + @PutMapping + public ResponseEntity updateTransaction(@RequestBody TransactionDto.TransactionRequest requestDto, + @RequestParam(value = "id", required = false) Long id){ + transactionService.updateTransaction(requestDto, id); + return new ResponseEntity<>(HttpStatus.OK); + } + + @DeleteMapping + public ResponseEntity deleteTransaction(@RequestParam(value = "id", required = false) Long id){ + transactionService.deleteTransaction(id); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java new file mode 100644 index 0000000..5c632c1 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/AccountBookDto.java @@ -0,0 +1,56 @@ +package com.umc.DongnaeFriend.domain.account.book.dto; + +import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.type.TransactionCategory; +import lombok.*; + +import java.util.List; + +public class AccountBookDto { + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class AccountBookCategoryResponse{ + private TransactionCategory transactionCategory; + private Long price; + } + + + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class BudgetResponse{ + private Long accountBookId; + private Long budget; + + public static BudgetResponse of(Long accountBookId, Long budget){ + return new BudgetResponse(accountBookId, budget); + } + } + + @Getter + public static class BudgetRequest{ + public static AccountBook toEntity(Integer year, Integer month, Long amount){ + return AccountBook.builder() + .expenditure(0L) + .income(0L) + .budget(amount) + .year(year) + .month(month) + .build(); + } + } + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class AccountBookResponse { + private Long expenditure; + private Long income; + private Long budget; + private List expense; + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/Expense.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/Expense.java new file mode 100644 index 0000000..29ee3e9 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/Expense.java @@ -0,0 +1,12 @@ +package com.umc.DongnaeFriend.domain.account.book.dto; + +import com.umc.DongnaeFriend.domain.type.TransactionCategory; +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class Expense { + public TransactionCategory category; + public long price; +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/MemoDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/MemoDto.java new file mode 100644 index 0000000..c984bbd --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/MemoDto.java @@ -0,0 +1,63 @@ +package com.umc.DongnaeFriend.domain.account.book.dto; + +import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.account.book.entity.Memo; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.security.core.parameters.P; + +import java.util.List; +import java.util.stream.Collectors; + +public class MemoDto { + + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class MemoResponse{ + private Long memoId; + private String memo; + private Boolean done; + + public static MemoResponse from(Memo memo){ + return new MemoResponse( + memo.getId(), + memo.getMemo(), + memo.getDone()); + } + } + + @Getter + public static class MemoListResponse{ + private List memos; + + public MemoListResponse(List memos){ + this.memos = memos; + } + + public static MemoListResponse of(List memoList){ + List memoResponses = memoList + .stream() + .map(MemoResponse::from) + .collect(Collectors.toList()); + + return new MemoListResponse(memoResponses); + } + } + + @Getter + @AllArgsConstructor + @NoArgsConstructor + public static class MemoRequest{ + private String memo; + private Boolean done; + + public Memo toEntity(AccountBook accountBook){ + return Memo.builder() + .accountBook(accountBook) + .memo(memo) + .build(); + } + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/TransactionDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/TransactionDto.java new file mode 100644 index 0000000..40070dc --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/dto/TransactionDto.java @@ -0,0 +1,89 @@ +package com.umc.DongnaeFriend.domain.account.book.dto; + +import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.account.book.entity.Memo; +import com.umc.DongnaeFriend.domain.account.book.entity.Transaction; +import com.umc.DongnaeFriend.domain.type.PayCategory; +import com.umc.DongnaeFriend.domain.type.TransactionCategory; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.stream.Collectors; + +public class TransactionDto { + @Getter + @AllArgsConstructor + @NoArgsConstructor + public static class TransactionRequest{ + private Integer year; + private Integer month; + private Integer day; + private Integer type; + private Long price; + private TransactionCategory transactionCategory; + private PayCategory payCategory; + private String categoryMemo; + + public Transaction toEntity(AccountBook accountBook){ + return Transaction.builder() + .type(type) // 0이면 지출, 1이면 수입 + .transactionCategory(transactionCategory) + .year(year) + .month(month) + .day(day) + .price(price) + .payCategory(payCategory) + .categoryMemo(categoryMemo) + .accountBook(accountBook) + .build(); + } + } + + @Getter + @AllArgsConstructor + @NoArgsConstructor + public static class TransactionResponse{ + private Long id; + private Integer type; + private TransactionCategory transactionCategory; + private Integer year; + private Integer month; + private Integer day; + private Long price; + private PayCategory payCategory; + private String memo; + + public static TransactionResponse from(Transaction transaction){ + return new TransactionResponse( + transaction.getId(), + transaction.getType(), + transaction.getTransactionCategory(), + transaction.getYear(), + transaction.getMonth(), + transaction.getDay(), + transaction.getPrice(), + transaction.getPayCategory(), + transaction.getCategoryMemo()); + } + } + + @Getter + public static class TransactionListResponse{ + private List transactions; + + public TransactionListResponse(List transactions){ + this.transactions = transactions; + } + + public static TransactionListResponse of(List transactionList){ + List transactionResponses = transactionList + .stream() + .map(TransactionResponse::from) + .collect(Collectors.toList()); + + return new TransactionListResponse(transactionResponses); + } + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/AccountBook.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/AccountBook.java index 0f90154..65f6afb 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/AccountBook.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/AccountBook.java @@ -23,15 +23,16 @@ public class AccountBook extends BaseTimeEntity { private Long id; @ManyToOne(fetch = LAZY) - @JoinColumn(name = "user_id", nullable = false) + //@JoinColumn(name = "user_id", nullable = false) + @JoinColumn(name = "user_id") private User user; private Long budget; - @Column(nullable = false) + //@Column(nullable = false) private Long expenditure; - @Column(nullable = false) + //@Column(nullable = false) private Long income; @Column(nullable = false) @@ -39,4 +40,8 @@ public class AccountBook extends BaseTimeEntity { @Column(nullable = false) private Integer month; + + public void updateBudget(Long budget){ + this.budget = budget; + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Memo.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Memo.java index dfb8f7c..bc13412 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Memo.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Memo.java @@ -7,6 +7,8 @@ import com.umc.DongnaeFriend.domain.BaseTimeEntity; import javax.persistence.*; + +import com.umc.DongnaeFriend.domain.account.book.dto.MemoDto; import lombok.*; @Getter @@ -28,6 +30,11 @@ public class Memo extends BaseTimeEntity { @Column(columnDefinition = "MEDIUMTEXT", nullable = false) private String memo; - @Column(nullable = false) - private Boolean done; // 완료 여부 + //@Column(nullable = false) + private Boolean done; + + public void updateMemo(MemoDto.MemoRequest request){ + this.memo = request.getMemo(); + this.done = request.getDone(); + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Transaction.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Transaction.java index 7d1c3ab..3c7c7e1 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Transaction.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/entity/Transaction.java @@ -7,6 +7,8 @@ import static lombok.AccessLevel.PROTECTED; import com.umc.DongnaeFriend.domain.BaseTimeEntity; +import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; +import com.umc.DongnaeFriend.domain.account.book.dto.TransactionDto; import com.umc.DongnaeFriend.domain.type.PayCategory; import com.umc.DongnaeFriend.domain.type.TransactionCategory; import javax.persistence.*; @@ -38,7 +40,7 @@ public class Transaction extends BaseTimeEntity { private PayCategory payCategory; //현금, 체크카드 등 @Enumerated(value = STRING) - @Column(nullable = false) + //@Column(nullable = false) private TransactionCategory transactionCategory; //식비, 교육 등 @Column(columnDefinition = "MEDIUMTEXT") @@ -52,4 +54,15 @@ public class Transaction extends BaseTimeEntity { @Column(nullable = false) private Integer day; + + public void updateTransaction(TransactionDto.TransactionRequest request, AccountBook accountBook){ + this.accountBook = accountBook; + this.categoryMemo = request.getCategoryMemo(); + this.year = request.getYear(); + this.month =request.getMonth(); + this.day = request.getDay(); + this.price = request.getPrice(); + this.payCategory = request.getPayCategory(); + + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java new file mode 100644 index 0000000..ed98f65 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepository.java @@ -0,0 +1,57 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.accountBook; + +import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; +import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.account.book.service.AccountBookService; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import javax.transaction.Transactional; +import java.util.List; +import java.util.Optional; + +public interface AccountBookRepository extends JpaRepository, AccountBookRepositoryCustom { + + //Optional findByIdAndYearAndMonth(Long accountBookId, Integer year, Integer month); + Optional findByYearAndMonth(Integer year, Integer month); + @Modifying + @Query(value = "update AccountBook ab " + + "set ab.expenditure = ab.expenditure + :expenditure " + + "where ab.id = :accountBookId") + void updateAccountBookExpenditure(@Param("accountBookId")Long accountBookId, @Param("expenditure")Long expenditure); + + @Modifying + @Query(value = "update AccountBook ab " + + "set ab.income = ab.income + :income " + + "where ab.id = :accountBookId") + void updateAccountBookIncome(@Param("accountBookId")Long accountBookId, @Param("income")Long income); + + @Modifying + @Query(value = "update AccountBook ab " + + "set ab.expenditure = ab.expenditure - :expenditure " + + "where ab.id = :accountBookId") + void updateAccountBookExpenditureDelete(@Param("accountBookId")Long accountBookId, @Param("expenditure")Long expenditure); + @Modifying + @Query(value = "update AccountBook ab " + + "set ab.income = ab.income - :income " + + "where ab.id = :accountBookId") + void updateAccountBookIncomeDelete(@Param("accountBookId")Long accountBookId, @Param("income")Long income); + @Modifying + @Query(value = "update AccountBook ab " + + "set ab.expenditure = ab.expenditure - :expenditureGap " + + "where ab.id = :accountBookId") + void updateAccountBookExpenditureEdit(@Param("accountBookId")Long accountBookId, @Param("expenditureGap")Long expenditureGap); + @Modifying + @Query(value = "update AccountBook ab " + + "set ab.income = ab.income + :incomeGap " + + "where ab.id = :accountBookId") + void updateAccountBookIncomeEdit(@Param("accountBookId")Long accountBookId, @Param("incomeGap")Long incomeGap); + + /*@Query(value = "SELECT transaction.transaction_category, SUM(transaction.price) as sum_price " + + "from transaction " + + "where transaction.month = :month and transaction.year = :year " + + "group by transaction.transaction_category", nativeQuery = true) + Object[] getAccountBookGroupByCategory (@Param("month") long month, @Param("year") long year);*/ +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java new file mode 100644 index 0000000..ffb4e1f --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustom.java @@ -0,0 +1,11 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.accountBook; + + +import com.umc.DongnaeFriend.domain.account.book.dto.Expense; +import org.springframework.data.domain.Pageable; + +import java.util.List; + +public interface AccountBookRepositoryCustom { + List getAccountBook(Integer year, Integer month); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java new file mode 100644 index 0000000..d0b9eb6 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/accountBook/AccountBookRepositoryCustomImpl.java @@ -0,0 +1,37 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.accountBook; + + +import com.umc.DongnaeFriend.domain.account.book.dto.Expense; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import javax.persistence.EntityManager; +import java.util.List; + +@Slf4j +@RequiredArgsConstructor +@Repository +public class AccountBookRepositoryCustomImpl implements AccountBookRepositoryCustom { + + private final EntityManager em; + + @Override + public List getAccountBook (@Param("year") Integer year, @Param("month") Integer month) { + + return em.createQuery( + "select new com.umc.DongnaeFriend.domain.account.book.dto.Expense(t.transactionCategory, sum(t.price)) " + + "from Transaction t where t.year= :year and t.month= :month group by t.transactionCategory " + + "order by sum(t.price) desc", Expense.class) + .setParameter("year", year) + .setParameter("month", month) + .getResultList(); + } +} + +// .select(transaction.transactionCategory, transaction.price.sum()) +// .from(transaction) +// .where(transaction.month.eq(month).and(transaction.year.eq(year))) +// .groupBy(transaction.transactionCategory) +// .fetch().toArray(); diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepository.java new file mode 100644 index 0000000..1b5da1a --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepository.java @@ -0,0 +1,15 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.memo; + +import com.umc.DongnaeFriend.domain.account.book.entity.Memo; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; +import java.util.Optional; + +public interface MemoRepository extends JpaRepository, MemoRepositoryCustom{ + Optional findByAccountBookId(Long accountBookId); + @Query("select m from Memo m where m.accountBook.id = :accountBookId") + List findMemoListByAccountBookId(@Param("accountBookId") Long accountBookId); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustom.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustom.java new file mode 100644 index 0000000..6c33afd --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustom.java @@ -0,0 +1,6 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.memo; + +public interface MemoRepositoryCustom { + + Integer getMemoCnt(Integer year, Integer month); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustomImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustomImpl.java new file mode 100644 index 0000000..91c16a3 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/memo/MemoRepositoryCustomImpl.java @@ -0,0 +1,30 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.memo; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import static com.umc.DongnaeFriend.domain.account.book.entity.QAccountBook.accountBook; +import com.umc.DongnaeFriend.domain.account.book.entity.QMemo; + +import javax.persistence.EntityManager; + + +public class MemoRepositoryCustomImpl implements MemoRepositoryCustom{ + + private final JPAQueryFactory jpaQueryFactory; + + public MemoRepositoryCustomImpl(JPAQueryFactory jpaQueryFactory) { + this.jpaQueryFactory = jpaQueryFactory; + } + + @Override + public Integer getMemoCnt(Integer year, Integer month) { + QMemo memo = QMemo.memo1; + + return Math.toIntExact(jpaQueryFactory + .select(memo.count()) + .from(memo) + .innerJoin(memo.accountBook, accountBook) + .where(memo.accountBook.month.eq(month) + .and(accountBook.year.eq(year))) + .fetchFirst()); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepository.java new file mode 100644 index 0000000..79321bf --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepository.java @@ -0,0 +1,25 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.transaction; + +import com.umc.DongnaeFriend.domain.account.book.dto.TransactionDto; +import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.account.book.entity.Transaction; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; +import java.util.Optional; + +public interface TransactionRepository extends JpaRepository, TransactionRepositoryCustom { + + @Query(value = "select t from Transaction t where t.year = :year and t.month = :month and t.day = :day") + List findByYearAndMonth(@Param("year") Integer year, @Param("month") Integer month, + @Param("day") Integer day, Pageable pageable); + +/* @Query(value = "select new com.umc.DongnaeFriend.domain.account.book.dto.TransactionDto.TransactionByCategory(tr.transactionCategory, SUM(tr.price)) " + + "from Transaction tr " + + "where tr.year = :year and tr.month = :month " + + "group by tr.transactionCategory") + TransactionDto.TransactionByCategory getTransactionByYearAndMonth(@Param("year") Integer year, @Param("month") Integer month);*/ +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepositoryCustom.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepositoryCustom.java new file mode 100644 index 0000000..7fd97e0 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepositoryCustom.java @@ -0,0 +1,4 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.transaction; + +public interface TransactionRepositoryCustom { +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepositoryCustomImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepositoryCustomImpl.java new file mode 100644 index 0000000..1c64433 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/repository/transaction/TransactionRepositoryCustomImpl.java @@ -0,0 +1,4 @@ +package com.umc.DongnaeFriend.domain.account.book.repository.transaction; + +public class TransactionRepositoryCustomImpl implements TransactionRepositoryCustom{ +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java new file mode 100644 index 0000000..2c5c95f --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/AccountBookService.java @@ -0,0 +1,52 @@ +package com.umc.DongnaeFriend.domain.account.book.service; + +import com.umc.DongnaeFriend.domain.account.book.dto.AccountBookDto; +import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.account.book.repository.accountBook.AccountBookRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import javax.transaction.Transactional; + + +@Slf4j +@Service +@RequiredArgsConstructor +public class AccountBookService { + + // User 권한 확인 필요 // + + private final AccountBookRepository accountBookRepository; + + + // 가계부 예산 설정 (한달) + @Transactional + public void createBudget(Integer year, Integer month, Long budget){ + accountBookRepository.save(AccountBookDto.BudgetRequest.toEntity(year, month, budget)); + } + + // 가계부 예산 설정 조회 + public AccountBookDto.BudgetResponse getBudget(Integer year, Integer month){ + AccountBook accountBook = accountBookRepository.findByYearAndMonth(year, month).orElseThrow(); + return AccountBookDto.BudgetResponse.of(accountBook.getId(),accountBook.getBudget()); + } + + // 가계부 예산 설정 수정 + public void updateBudget(Integer year, Integer month, Long budget){ + AccountBook accountBook = accountBookRepository.findByYearAndMonth(year, month).orElseThrow(); + accountBook.updateBudget(budget); + } + + + // 가계부 조회 -> 이번달 남은 예산 & 지출, 저축(수입), 카테고리별 지출 + public AccountBookDto.AccountBookResponse getAccountBookResponse(Integer year, Integer month) { + AccountBook accountBook = accountBookRepository.findByYearAndMonth(year, month).orElseThrow(); + return AccountBookDto.AccountBookResponse.builder() + .income(accountBook.getIncome()) + .expenditure(accountBook.getExpenditure()) + .budget(accountBook.getBudget()+accountBook.getIncome()-accountBook.getExpenditure()) + .expense(accountBookRepository.getAccountBook(year,month)) + .build(); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/MemoService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/MemoService.java new file mode 100644 index 0000000..22ad46c --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/MemoService.java @@ -0,0 +1,65 @@ +package com.umc.DongnaeFriend.domain.account.book.service; + +import com.umc.DongnaeFriend.domain.account.book.dto.MemoDto; +import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.account.book.entity.Memo; +import com.umc.DongnaeFriend.domain.account.book.repository.accountBook.AccountBookRepository; +import com.umc.DongnaeFriend.domain.account.book.repository.memo.MemoRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor +public class MemoService { + + private final MemoRepository memoRepository; + private final AccountBookRepository accountBookRepository; + + // 메모 전체 조회 -> 리스트 + public MemoDto.MemoListResponse getMemoList(Integer year, Integer month){ + + // User 권한 확인 + AccountBook accountBook = accountBookRepository.findByYearAndMonth(year, month).orElseThrow(); + List memoList = memoRepository.findMemoListByAccountBookId(accountBook.getId()); + return MemoDto.MemoListResponse.of(memoList); + } + + // 메모 등록 + @Transactional + public void createMemo(MemoDto.MemoRequest memoRequest, Integer year, Integer month){ + + // User 권한 확인 + AccountBook accountBook = accountBookRepository.findByYearAndMonth(year, month).orElseThrow(); + Integer memoCnt = memoRepository.getMemoCnt(year, month); + + if(memoCnt<8){ + memoRepository.save(memoRequest.toEntity(accountBook)); + }else{ + // 개수 초과 예외처리 + log.info("메모 개수 초과 발생 !"); + } + } + + // 메모 수정 + @Transactional + public void updateMemo(MemoDto.MemoRequest memoRequest, Long memoId){ + + // User 권한 확인 + Memo memo = memoRepository.findById(memoId).orElseThrow(); + memo.updateMemo(memoRequest); + } + + // 메모 삭제 + @Transactional + public void deleteMemo(Long memoId){ + + // User 권한 확인 + Memo memo = memoRepository.findById(memoId).orElseThrow(); + memoRepository.deleteById(memo.getId()); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java new file mode 100644 index 0000000..a15cc8f --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/book/service/TransactionService.java @@ -0,0 +1,94 @@ +package com.umc.DongnaeFriend.domain.account.book.service; + +import com.umc.DongnaeFriend.domain.account.book.dto.TransactionDto; +import com.umc.DongnaeFriend.domain.account.book.entity.AccountBook; +import com.umc.DongnaeFriend.domain.account.book.entity.Transaction; +import com.umc.DongnaeFriend.domain.account.book.repository.accountBook.AccountBookRepository; +import com.umc.DongnaeFriend.domain.account.book.repository.transaction.TransactionRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor +public class TransactionService { + + private final TransactionRepository transactionRepository; + private final AccountBookRepository accountBookRepository; + + // 지출 또는 수입 내역 추가 + @Transactional + public void createTransaction(TransactionDto.TransactionRequest request){ + + log.info("Year : " + request.getYear() + " Month : " + request.getMonth()); + AccountBook accountBook = findTarget(request.getYear(), request.getMonth()); + + transactionRepository.save(request.toEntity(accountBook)); + + // AccountBook income, expenditure 값 변경 + + if(request.getType()==1){ + log.info("Price 추가 : " + request.getPrice()); + + accountBookRepository.updateAccountBookIncome(accountBook.getId(), request.getPrice()); + }else{ + log.info("Price 추가 : " + request.getPrice()); + + accountBookRepository.updateAccountBookExpenditure(accountBook.getId(), request.getPrice()); + } + } + + // 지출 또는 수입 내역 조회 + public TransactionDto.TransactionListResponse getTransactions(Integer year, Integer month, Integer day, Pageable pageable){ + + List transactionList = transactionRepository.findByYearAndMonth(year, month, day, pageable); + return TransactionDto.TransactionListResponse.of(transactionList); + } + + // 지출 또는 수입 내역 삭제 + @Transactional + public void deleteTransaction(Long transactionId){ + + Transaction transaction = transactionRepository.findById(transactionId).orElseThrow(); + AccountBook accountBook = findTarget(transaction.getYear(), transaction.getMonth()); + + // AccountBook income, expenditure 값이 변경되어야 함. + if(transaction.getType()==1){ + log.info("Price 삭제: " + transaction.getPrice()); + accountBookRepository.updateAccountBookIncomeDelete(accountBook.getId(), transaction.getPrice()); + }else{ + log.info("Price 삭제 : " + transaction.getPrice()); + + accountBookRepository.updateAccountBookExpenditureDelete(accountBook.getId(), transaction.getPrice()); + } + transactionRepository.deleteById(transaction.getId()); + } + + // 지출 또는 수입 내역 수정 + @Transactional + public void updateTransaction(TransactionDto.TransactionRequest request, Long transactionId){ + Transaction transaction = transactionRepository.findById(transactionId).orElseThrow(); + AccountBook accountBook = findTarget(transaction.getYear(), transaction.getMonth()); + + Transaction updateTrans = request.toEntity(accountBook); + Long priceGap = updateTrans.getPrice()-transaction.getPrice(); + log.info("priceGap : " + priceGap); + + if(transaction.getType()==1){ + accountBookRepository.updateAccountBookIncomeEdit(accountBook.getId(), priceGap); + }else{ + accountBookRepository.updateAccountBookExpenditureEdit(accountBook.getId(), priceGap); + } + + transaction.updateTransaction(request, accountBook); + } + + private AccountBook findTarget(Integer year, Integer month){ + return accountBookRepository.findByYearAndMonth(year, month).orElseThrow(); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java new file mode 100644 index 0000000..d067631 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/controller/accountBookSharingController.java @@ -0,0 +1,89 @@ +package com.umc.DongnaeFriend.domain.account.sharing.controller; + +import com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto; +import com.umc.DongnaeFriend.domain.account.sharing.service.AccountBookSharingService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("/account-books/sharing") +public class accountBookSharingController { + + @Autowired + AccountBookSharingService accountBookSharingService; + + /* + * [가계부 공유] 게시글 검색 + * @param keyword + * @param pageable + * + * @param pageable + * size : 페이지 사이즈 + * page : 페이지 + * sortBy : 정렬순 + * - like + * - createdAt + */ + + @GetMapping("/search") + + public ResponseEntity searchAll(@RequestParam("keyword") String keyword, @RequestParam("category") int category, Pageable pageable) { + List res = accountBookSharingService.searchByKeyword(keyword, category, pageable); + return ResponseEntity.ok(res); + } + + /* + * [가계부 공유] 게시글 등록 + + * + * @param RequestDto + */ + + @PostMapping("") + public ResponseEntity createPost(@RequestBody SharingDto.Request req) { + accountBookSharingService.createPost(req); + return new ResponseEntity<>(HttpStatus.OK); + } + + /* + * [가계부 공유] 게시글 상세 조회 + * + * @PathVariable accountBookId + */ + @GetMapping("/{accountBookId}") + public ResponseEntity updatePost(@PathVariable("accountBookId") long board_id) { + return ResponseEntity.ok(accountBookSharingService.getBoard(board_id)); + } + + /* + * [가계부 공유] 게시글 수정 + * + * @PathVariable accountBookId + * @RequestBody SharingDto.Request + */ + @PutMapping("/{accountBookId}") + public ResponseEntity updateBoard(@PathVariable("accountBookId") int board_id, @RequestBody SharingDto.Request req) { + accountBookSharingService.updateBoard(board_id, req); + return new ResponseEntity<>(HttpStatus.OK); + } + + /* + * [가계부 공유] 게시글 삭제 + * + * @PathVariable accountBookId + */ + @DeleteMapping("/{accountBookId}") + public ResponseEntity deleteBoard(@PathVariable("accountBookId") int board_id) { + accountBookSharingService.deleteBoard(board_id); + return new ResponseEntity<>(HttpStatus.OK); + } + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java new file mode 100644 index 0000000..da5c307 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/dto/SharingDto.java @@ -0,0 +1,106 @@ +package com.umc.DongnaeFriend.domain.account.sharing.dto; + +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; +import com.umc.DongnaeFriend.domain.type.SharingCategory; +import com.umc.DongnaeFriend.domain.user.entity.User; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.lang.Nullable; + +import javax.validation.constraints.NotNull; +import java.util.List; + +public class SharingDto { + + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class Request { + + @NotNull(message = "카테고리는 필수입니다.") + private int category; + + @NotNull(message = "제목은 필수입니다.") + private String title; + + @NotNull(message = "내용은 필수입니다.") + private String content; + + + private List images; + + public SharingBoard toEntity(User user) { + return SharingBoard.builder() + .user(user) + .category(SharingCategory.valueOf(category)) + .title(title) + .content(content) + .view(0) + .build(); + } + } + + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class Response{ + String profileImage; + String nickname; + int category; + String title; + String content; + List images; + String createdAt; + boolean isWriter; + boolean likeOrNot; + boolean scrapOrNot; + int view; + } + + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class ListResponse { + private Long id; + + private int category; + + private String title; + + private String content; + + private String imageUrl; + + private String createdAt; + + private int view; + + private int commentCount; + + private int likes; + + } + + /** + * 프로필 조회 시 필요한 정보 + */ + @Getter @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class AccountBookProfileListResponse { + private Long boardId; + private int category; + private String title; + private String imageUrl; + //private String town; + private String createdAt; + private int commentCount; + private int likeCount; + } + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/entity/SharingBoard.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/entity/SharingBoard.java index 343fa87..bee611c 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/entity/SharingBoard.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/entity/SharingBoard.java @@ -8,10 +8,13 @@ import com.fasterxml.jackson.databind.ser.Serializers.Base; import com.umc.DongnaeFriend.domain.BaseTimeEntity; +import com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto; +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; import com.umc.DongnaeFriend.domain.type.SharingCategory; import com.umc.DongnaeFriend.domain.user.entity.User; import javax.persistence.*; import lombok.*; +import org.hibernate.annotations.ColumnDefault; @Getter @Builder @@ -38,4 +41,14 @@ public class SharingBoard extends BaseTimeEntity { @Column(columnDefinition = "MEDIUMTEXT", nullable = false) private String content; + + @Column(name = "view") + @ColumnDefault("0") + private Integer view; + + public void updateBoard(SharingDto.Request req) { + this.category = SharingCategory.valueOf(req.getCategory()); + this.title = req.getTitle(); + this.content = req.getContent(); + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java new file mode 100644 index 0000000..b92f8f9 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingBoardRepository.java @@ -0,0 +1,43 @@ +package com.umc.DongnaeFriend.domain.account.sharing.repository; + +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface SharingBoardRepository extends JpaRepository { + + +// private final EntityManager em; +// +// public SharingBoardRepository(EntityManager em) { +// this.em = em; +// } + +// public List findByKeywordAAndCategory(@Param("keyword") String keyword, @Param("category") String category, Pageable pageable) { +// return em.createQuery("SELECT new com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto.ListResponse(s.id, s.category, s.title, s.content, s.createdAt, s.view, likes), count(SharingSympathy.sharingBoard.id) as likes " + +// "FROM SharingBoard s left join SharingSympathy on s.id=SharingSympathy.sharingBoard.id " + +// "WHERE (s.title LIKE %:keyword% or s.content LIKE % :keyword%) and s.category = :category " + +// "group by s.id", SharingDto.ListResponse.class) +// .setParameter("keyword", keyword) +// .setParameter("category", category) +// .getResultList(); +// } + + + @Query(value = "SELECT sharing_board.*, COUNT(sharing_sympathy.sharing_board_id) AS cnt FROM sharing_board\n" + + "LEFT JOIN sharing_sympathy ON sharing_board.sharing_board_id = sharing_sympathy.sharing_board_id\n" + + "WHERE (sharing_board.title LIKE %:keyword% OR sharing_board.content LIKE %:keyword%)\n" + + "AND sharing_board.category = :category GROUP BY sharing_board.sharing_board_id ", nativeQuery = true) + List findByKeyword(@Param("keyword") String keyword, @Param("category") String category, Pageable pageable); + + List findAllByUserId(Long userId, Pageable pageable); + int countAllByUserId(Long userId); + + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingCommentRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingCommentRepository.java index 2884fab..06aa498 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingCommentRepository.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingCommentRepository.java @@ -7,15 +7,26 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + import java.util.List; import java.util.Objects; +@Repository public interface SharingCommentRepository extends JpaRepository { @Query("SELECT u FROM User u WHERE u.id = :user_id") User findByUserId(@Param("user_id") Long user_id); @Query("SELECT sb FROM SharingBoard sb WHERE sb.id = :sharing_board_id") SharingBoard findBySharingBoardId(@Param("sharing_board_id") Long sharing_board_id); - @Query("SELECT sc FROM SharingComment sc WHERE sc.sharingBoard = :sharingBoard") List findAllByBoard(@Param("sharingBoard") SharingBoard sharingBoard); + + + public int countAllBySharingBoardId(Long sharing_board_id); + int countAllByUserId(Long userId); + + @Query(value = "select c from SharingComment c join fetch c.sharingBoard sb " + + "where c.user.id = :userId order by c.createdAt desc") + List getCommentByUserIdAndBoard(@Param("userId") Long userId); + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingImgRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingImgRepository.java new file mode 100644 index 0000000..e5de29b --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingImgRepository.java @@ -0,0 +1,21 @@ +package com.umc.DongnaeFriend.domain.account.sharing.repository; + +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingImg; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeImg; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface SharingImgRepository extends JpaRepository { + + @Query(value = "SELECT * FROM sharing_img WHERE sharing_board_id = ?1 ORDER BY created_at ASC LIMIT 1", nativeQuery = true) + Optional findFirst(long sharing_board_id); + + List findAllBySharingBoard_Id(long id); + + void deleteAllById(long id); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingSympathyRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingSympathyRepository.java new file mode 100644 index 0000000..f559723 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/repository/SharingSympathyRepository.java @@ -0,0 +1,13 @@ +package com.umc.DongnaeFriend.domain.account.sharing.repository; + +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingSympathy; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface SharingSympathyRepository extends JpaRepository { + + int countAllBySharingBoardId(Long sharing_board_id); + int countAllByUserId(Long userId); + List findByUser_Id(long user_id); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java new file mode 100644 index 0000000..e85afc6 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingService.java @@ -0,0 +1,29 @@ +package com.umc.DongnaeFriend.domain.account.sharing.service; + +import com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto; +import org.springframework.data.domain.Pageable; + +import java.util.List; + +public interface AccountBookSharingService { + + List searchByKeyword(String keyword, int category, Pageable pageable); + + void createPost(SharingDto.Request req); + + /* + * [가계부 공유] 게시글 상세 조회 + */ + SharingDto.Response getBoard(long board_id); + + /* + * [가계부 공유] 게시글 수정 + */ + void updateBoard(long board_id, SharingDto.Request req); + + + /* + * [가계부 공유] 게시글 삭제 + */ + void deleteBoard(long board_id); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java new file mode 100644 index 0000000..ff68779 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/account/sharing/service/AccountBookSharingServiceImpl.java @@ -0,0 +1,191 @@ +package com.umc.DongnaeFriend.domain.account.sharing.service; + +import com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingImg; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingBoardRepository; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingCommentRepository; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingImgRepository; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingSympathyRepository; +import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; +import com.umc.DongnaeFriend.domain.type.Age; +import com.umc.DongnaeFriend.domain.type.Gender; +import com.umc.DongnaeFriend.domain.type.SharingCategory; +import com.umc.DongnaeFriend.domain.type.YesNo; +import com.umc.DongnaeFriend.domain.user.entity.User; +import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import com.umc.DongnaeFriend.global.exception.CustomException; +import com.umc.DongnaeFriend.global.exception.ErrorCode; +import com.umc.DongnaeFriend.global.util.FileUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import static com.umc.DongnaeFriend.global.util.TimeUtil.getTime; + +@Slf4j +@Service +public class AccountBookSharingServiceImpl implements AccountBookSharingService { + + @Autowired + private SharingBoardRepository sharingBoardRepository; + + @Autowired + private SharingImgRepository sharingImgRepository; + + @Autowired + private SharingCommentRepository sharingCommentRepository; + + @Autowired + private SharingSympathyRepository sharingSympathyRepository; + + @Autowired + private UserRepository userRepository; + + + /* + * [가계부 공유] 게시글 검색 + */ + @Override + public List searchByKeyword(String keyword, int category, Pageable pageable) { + //TODO : 전체 카테고리 처리 + List sharingBoards = sharingBoardRepository.findByKeyword(keyword, SharingCategory.valueOf(category).name(), pageable); + if (sharingBoards.isEmpty()) { + throw new CustomException(ErrorCode.NO_CONTENT_FOUND); + } + return getListResponses(sharingBoards); + } + + /* + * [가계부 공유] 게시글 등록 + */ + @Override + public void createPost(SharingDto.Request req) { + User user = getCurUser(); + sharingBoardRepository.save(req.toEntity(user)); + //TODO : Img 파일 업로드 + } + + + /* + * [가계부 공유] 게시글 상세 조회 + */ + @Override + public SharingDto.Response getBoard(long board_id) { + SharingBoard board = sharingBoardRepository.findById(board_id).orElseThrow(() -> + new CustomException(ErrorCode.NO_CONTENT_FOUND)); + + User user = getCurUser(); + + //Get Images + List images = sharingImgRepository.findAllBySharingBoard_Id(board_id); + + //Writer인지 검사 + boolean isWriter = Objects.equals(board.getUser().getId(), user.getId()); + + //LikeOrNot 검사 + boolean likeOrNot = !sharingSympathyRepository.findByUser_Id(user.getId()).isEmpty(); + + //TODO: ScrapRepository 필요 + //scrapOrNot 검사 + boolean scrapOrNot = false; + + return SharingDto.Response.builder() + .profileImage(board.getUser().getProfileImage()) + .nickname(board.getUser().getNickname()) + .category(board.getCategory().getValue()) + .title(board.getTitle()) + .content(board.getContent()) + .images(images.stream().map(SharingImg::getImageUrl).collect(Collectors.toList())) + .createdAt(getTime(board.getCreatedAt())) + .isWriter(isWriter) + .likeOrNot(likeOrNot) + .scrapOrNot(scrapOrNot) + .view(board.getView()).build(); + } + + /* + * [가계부 공유] 게시글 수정 + */ + @Override + public void updateBoard(long board_id, SharingDto.Request req) { + + SharingBoard board = sharingBoardRepository.findById(board_id).orElseThrow( + () -> new CustomException(ErrorCode.NO_CONTENT_FOUND)); + + //권한 검사 + if (!board.getUser().getId().equals(getCurUser().getId())) throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + + board.updateBoard(req); + sharingBoardRepository.save(board); + + sharingImgRepository.findAllBySharingBoard_Id(board_id); + + //TODO: File Upload + } + + /* + * [가계부 공유] 게시글 삭제 + */ + @Override + public void deleteBoard(long board_id) { + User user = getCurUser(); + Optional sharingBoard = sharingBoardRepository.findById(board_id); + if (sharingBoard.isEmpty()) { + throw new CustomException(ErrorCode.NO_CONTENT_FOUND); + } + + if (!Objects.equals(sharingBoard.get().getUser().getId(), user.getId())) { + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } + + + //게시글 삭제 + sharingBoardRepository.deleteById(board_id); + //이미지 삭제 + sharingImgRepository.findAllBySharingBoard_Id(board_id); + } + + + + + //ListResponse 변환 + private List getListResponses(List sharingBoardList) { + return sharingBoardList.stream() + .map(origin -> SharingDto.ListResponse.builder() + .id(origin.getId()) + .category(origin.getCategory().getValue()) + .title(origin.getTitle()) + .content(origin.getContent()) + .imageUrl( + sharingImgRepository.findFirst(origin.getId()).map(SharingImg::getImageUrl).orElse("") + ) + .createdAt( + getTime(origin.getCreatedAt()) + ) + .view(origin.getView()) + .commentCount( + sharingCommentRepository.countAllBySharingBoardId(origin.getId()) + ) + .likes( + sharingSympathyRepository.countAllBySharingBoardId(origin.getId()) + ) + .build()) + .collect(Collectors.toList()); + } + + + private User getCurUser() { + Long user_id = (Long) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + return userRepository.findById(user_id).orElseThrow(() -> + new CustomException(ErrorCode.UNAUTHORIZED_MEMBER) + ); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java new file mode 100644 index 0000000..ec1ea11 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/controller/DongnaeBoardController.java @@ -0,0 +1,111 @@ +package com.umc.DongnaeFriend.domain.dongnae.controller; + +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeBoardRepository; +import com.umc.DongnaeFriend.domain.dongnae.service.DongnaeBoardService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; + +import javax.naming.AuthenticationException; + +/* + * [ 가계부 공유 ] + * */ + +@Slf4j +@RestController +@RequestMapping("/town-information") +public class DongnaeBoardController { + + @Autowired + DongnaeBoardRepository dongnaeBoardRepository; + + @Autowired + DongnaeBoardService dongnaeBoardService; + + + /* + * [동네정보] 사용자 위치 정보 + */ + @GetMapping("/user/location") + public ResponseEntity getLocation() { + return ResponseEntity.ok(dongnaeBoardService.getUserLocation()); + } + + + /* + * [동네정보] 게시글 검색 + * @param keyword + * @param category + * @param sort + */ + @GetMapping("/search") + public ResponseEntity getBoards(@RequestParam("keyword") String keyword, + @RequestParam("category") int category, + Pageable pageable) { + + + log.info("User Id: " + SecurityContextHolder.getContext().getAuthentication().getPrincipal()); + return ResponseEntity.ok(dongnaeBoardService.searchByKeyword(keyword, category, pageable)); + } + + /* + * [동네정보] 게시글 목록조회 + * @param sort + */ + @GetMapping("") + public ResponseEntity postBoard(@RequestParam("sortBy") int sort) { + return ResponseEntity.ok(dongnaeBoardService.searchAll(sort)); + } + + + /* + * [동네정보] 게시글 등록 + * @param DongnaeBoardDto.Request + */ + @PostMapping("") + public ResponseEntity createBoard(@RequestBody DongnaeBoardDto.Request req) { + dongnaeBoardService.createBoard(req); + return ResponseEntity.ok("요청에 성공했습니다."); + } + + /* + * [동네정보] 게시글 상세 조회 + * @param board_id + */ + @GetMapping("/{townInformationId}") + public ResponseEntity getBoard(@PathVariable("townInformationId") int board_id) { + return ResponseEntity.ok(dongnaeBoardService.getBoard(board_id)); + } + + /* + * [동네정보] 게시글 수정 + * @param baord_id + * @param DongnaeBoardDto.Request + */ + @PutMapping("/{townInformationId}") + public ResponseEntity updateBoard(@PathVariable("townInformationId") int board_id, + @RequestBody DongnaeBoardDto.Request request) throws AuthenticationException { + dongnaeBoardService.updateBoard(board_id, request); + return ResponseEntity.ok("요청에 성공했습니다."); + } + + /* + * [동네정보] 게시글 삭제 + * @param board_id + */ + @DeleteMapping("/{townInformationId}") + public ResponseEntity deleteBoard(@PathVariable("townInformationId") int board_id) throws AuthenticationException { + dongnaeBoardService.deleteBoard(board_id); + return ResponseEntity.ok("요청에 성공했습니다."); + } + + + + + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java new file mode 100644 index 0000000..6c70431 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/DongnaeBoardDto.java @@ -0,0 +1,146 @@ +package com.umc.DongnaeFriend.domain.dongnae.dto; + + + +import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import com.umc.DongnaeFriend.domain.type.Age; +import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; +import com.umc.DongnaeFriend.domain.type.Gender; +import com.umc.DongnaeFriend.domain.type.YesNo; +import com.umc.DongnaeFriend.domain.user.entity.User; +import lombok.*; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.List; + + +public class DongnaeBoardDto { + + @Getter @Setter + @AllArgsConstructor + @NoArgsConstructor + public static class Request { + @NotNull(message = "카테고리는 필수입니다.") + private int category; + + @NotNull(message = "제목은 필수입니다.") + private String title; + @NotNull(message = "내응은 필수입니다.") + private String content; + private List images; + + @NotNull(message = "장소는 필수입니다.") + private String place; + + @NotNull(message = "자세한 장소는 필수입니다.") + private String placeLocation; + + + + public DongnaeBoard toEntity(User user, Dongnae dongnae) { + dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); + user = User.builder().id(1L).age(Age.AGE10).email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).townCertCnt(10).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); + + return DongnaeBoard.builder() + .user(user) + .category(DongnaeBoardCategory.valueOf(category) +// category == 0 ? RESTAURANT: +// category == 1 ? FACILITY: +// category == 2 ? SHARE_INFORMATION: +// category == 3 ? TOGETHER: +// category == 4 ? COMMUNICATION: +// category == 5 ? ETC : null + ) + .title(title) + .content(content) + .place(place) + .placeLocation(placeLocation) + + .dongnae(dongnae) + .view(0) + .build(); + } + + } + + + @Getter @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class ListResponse { + private Long id; + private String town; + + private int category; + + private String title; + + private String content; + + private String imageUrl; + + private String createdAt; + + private int view; + + private int commentCount; + + private int likes; + } + + + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class Response { + private String profileImage; + + private String nickname; + + private int category; + + private String title; + + private String content; + + private List images; + + private String place; + + private String placeLocation; + + private String createdAt; + + private int townCertification; + + //게시글 조회한 사람이 작성자인지? + private boolean isWriter; + + private boolean likeOrNot; + + private boolean scrapOrNot; + + private int view; + } + + /** + * 프로필 조회 시 필요한 정보 + */ + @Getter @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class DongnaeProfileListResponse { + private Long boardId; + private int category; + private String title; + private String imageUrl; + private String town; + private String createdAt; + private int commentCount; + private int likeCount; + } +} + diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/UserLocationDto.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/UserLocationDto.java new file mode 100644 index 0000000..d85af96 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/dto/UserLocationDto.java @@ -0,0 +1,13 @@ +package com.umc.DongnaeFriend.domain.dongnae.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import javax.validation.constraints.NotNull; + +@Getter +@AllArgsConstructor +public class UserLocationDto { + @NotNull(message = "동네 정보가 없습니다.") + private String town; +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/Dongnae.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/Dongnae.java index 62d39d5..1d542f3 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/Dongnae.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/Dongnae.java @@ -21,7 +21,7 @@ public class Dongnae extends BaseTimeEntity { private Long id; @Column(nullable = false) - private String townName; + private String townName; //동 이름 @Column(nullable = false) private String city; //시 diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java index fe9b18b..e25e247 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/entity/DongnaeBoard.java @@ -7,10 +7,12 @@ import static lombok.AccessLevel.PROTECTED; import com.umc.DongnaeFriend.domain.BaseTimeEntity; +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; import com.umc.DongnaeFriend.domain.user.entity.User; import javax.persistence.*; import lombok.*; +import org.hibernate.annotations.ColumnDefault; @Getter @Builder @@ -42,6 +44,21 @@ public class DongnaeBoard extends BaseTimeEntity { @Column(columnDefinition = "MEDIUMTEXT", nullable = false) private String content; + @Column(name = "view", nullable = false) + @ColumnDefault("0") + private Integer view = 0; + + private String place; // 사용자 장소 공유시 장소 이름(ex. "00키친") private String placeLocation; // 장소의 정확한 위치 + + public void updateBoard(DongnaeBoardDto.Request request) { + this.category = DongnaeBoardCategory.valueOf(request.getCategory()); + this.title = request.getTitle(); + this.content = request.getContent(); + this.place = request.getPlace(); + this.placeLocation = request.getPlaceLocation(); + } + + } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java new file mode 100644 index 0000000..54cd3d4 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeBoardRepository.java @@ -0,0 +1,39 @@ +package com.umc.DongnaeFriend.domain.dongnae.respository; + +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.security.core.parameters.P; +import org.springframework.stereotype.Repository; + + +import java.util.List; + +@Repository +public interface DongnaeBoardRepository extends JpaRepository { + + @Query(value = "SELECT dongnae_board.*, COUNT(dongnae_sympathy.dongnae_board_id) AS likes FROM dongnae_board\n" + + "LEFT JOIN dongnae_sympathy ON dongnae_board.dongnae_board_id = dongnae_sympathy.dongnae_board_id\n" + + "WHERE (dongnae_board.title LIKE %:keyword% OR dongnae_board.content LIKE %:keyword%)\n" + + "AND dongnae_board.category = :category GROUP BY dongnae_board.dongnae_board_id ", nativeQuery = true) + List findByKeyword(@Param("keyword") String keyword, @Param("category") String category, Pageable pageable); + + @Query(value = "select * from dongnae_board ORDER BY created_at DESC;", nativeQuery = true) + List findAllOrderByCreatedAt(); + + @Query(value = "SELECT dongnae_board.*, COUNT(dongnae_sympathy.dongnae_board_id) AS cnt FROM dongnae_board\n" + + "LEFT JOIN dongnae_sympathy ON dongnae_board.dongnae_board_id = dongnae_sympathy.dongnae_board_id\n" + + "GROUP BY dongnae_board.dongnae_board_id ORDER BY cnt DESC ;", nativeQuery = true) + List findAllOrderByLikes(); + + @Query(value = "select * from dongnae_board where category = ?1 ORDER BY created_at DESC LIMIT 1 ;", nativeQuery = true) + List findTwoByCategoryOrderByCreatedAt(String category); + + + public int countAllByUserId(Long userId); + + List findAllByUserId(Long userId); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeCommentRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeCommentRepository.java new file mode 100644 index 0000000..c5368cf --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeCommentRepository.java @@ -0,0 +1,19 @@ +package com.umc.DongnaeFriend.domain.dongnae.respository; + +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeComment; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface DongnaeCommentRepository extends JpaRepository { + public int countAllByDongnaeBoardId(Long dongnae_board_id); + public int countAllByUserId(Long userId); + + @Query(value = "select c from DongnaeComment c join fetch c.dongnaeBoard d " + + "where c.user.id = :userId order by c.createdAt desc") + List getCommentByUserIdAndBoard(@Param("userId") Long userId); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeImgRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeImgRepository.java new file mode 100644 index 0000000..d4de701 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeImgRepository.java @@ -0,0 +1,20 @@ +package com.umc.DongnaeFriend.domain.dongnae.respository; + +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeImg; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface DongnaeImgRepository extends JpaRepository { + + @Query(value = "SELECT * FROM dongnae_img WHERE dongnae_board_id = ?1 ORDER BY created_at ASC LIMIT 1", nativeQuery = true) + Optional findFirst(long dongnae_board_id); + + List findAllByDongnaeBoard_Id(long id); + + void deleteAllByDongnaeBoard_Id(Long board_id); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeRepository.java new file mode 100644 index 0000000..a350433 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeRepository.java @@ -0,0 +1,10 @@ +package com.umc.DongnaeFriend.domain.dongnae.respository; + +import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface DongnaeRepository extends JpaRepository { + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java new file mode 100644 index 0000000..1f274ba --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/respository/DongnaeSympathyRepository.java @@ -0,0 +1,15 @@ +package com.umc.DongnaeFriend.domain.dongnae.respository; + +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeSympathy; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.web.PageableDefault; + +import java.util.List; +import java.util.Optional; + +public interface DongnaeSympathyRepository extends JpaRepository { + int countAllByDongnaeBoardId(Long dongnae_board_id); + int countAllByUserId(Long userId); + + List findByUser_Id(long user_id); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java new file mode 100644 index 0000000..02c6e4d --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardService.java @@ -0,0 +1,26 @@ +package com.umc.DongnaeFriend.domain.dongnae.service; + +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; +import com.umc.DongnaeFriend.domain.dongnae.dto.UserLocationDto; +import org.springframework.data.domain.Pageable; + +import javax.naming.AuthenticationException; +import java.util.List; + +public interface DongnaeBoardService { + + List searchByKeyword(String keyword, int category, Pageable pageable); + + List searchAll(int sort); + + void createBoard(DongnaeBoardDto.Request req); + + + UserLocationDto getUserLocation(); + + DongnaeBoardDto.Response getBoard(long board_id); + + void updateBoard(long board_id, DongnaeBoardDto.Request request) throws AuthenticationException; + + void deleteBoard(long board_id) throws AuthenticationException; +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java new file mode 100644 index 0000000..f7e2e47 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/dongnae/service/DongnaeBoardServiceImpl.java @@ -0,0 +1,222 @@ +package com.umc.DongnaeFriend.domain.dongnae.service; + +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; +import com.umc.DongnaeFriend.domain.dongnae.dto.UserLocationDto; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeImg; +import com.umc.DongnaeFriend.domain.dongnae.respository.*; +import com.umc.DongnaeFriend.domain.type.DongnaeBoardCategory; +import com.umc.DongnaeFriend.domain.user.entity.User; +import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import com.umc.DongnaeFriend.global.exception.CustomException; +import com.umc.DongnaeFriend.global.exception.ErrorCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import static com.umc.DongnaeFriend.global.util.TimeUtil.getTime; + +@Slf4j +@Service +public class DongnaeBoardServiceImpl implements DongnaeBoardService { + + @Autowired + private DongnaeBoardRepository dongnaeBoardRepository; + + @Autowired + private DongnaeImgRepository dongnaeImgRepository; + + @Autowired + private DongnaeCommentRepository dongnaeCommentRepository; + + @Autowired + private DongnaeSympathyRepository dongnaeSympathyRepository; + + // 임시 유저, 동네 등록 // + @Autowired + private UserRepository userRepository; + + @Autowired + private DongnaeRepository dongnaeRepository; + + + /* + * [동네정보] 사용자 위치 정보 + */ + @Override + public UserLocationDto getUserLocation() { + return new UserLocationDto(getCurUser().getDongnae().getTownName()); + } + + + /* + * [동네정보] 게시글 검색 + * @param sort + */ + + @Override +// @Transactional(propagation = Propagation.REQUIRED) + public List searchByKeyword(String keyword, int category, Pageable pageable) { + String categoryName = DongnaeBoardCategory.valueOf(category).name(); + + List dongnaeBoardList = dongnaeBoardRepository.findByKeyword(keyword, categoryName, pageable); + + if (dongnaeBoardList.isEmpty()) { + throw new CustomException(ErrorCode.NO_CONTENT_FOUND); + } + + return getListResponses(dongnaeBoardList); + } + + /* + * [동네정보] 게시글 목록 조회 DELETED + * @param sort + */ + @Override + public List searchAll(int sort) { + + List dongnaeBoardList; + if (sort == 0) { + dongnaeBoardList = dongnaeBoardRepository.findAllOrderByCreatedAt(); + } else { + dongnaeBoardList = dongnaeBoardRepository.findAllOrderByLikes(); + } + + return getListResponses(dongnaeBoardList); + } + + /* + * [동네정보] 게시글 등록 + */ + @Override + public void createBoard(DongnaeBoardDto.Request req) { + User user = getCurUser(); + dongnaeBoardRepository.save(req.toEntity(user,user.getDongnae())); + } + + + + /* + * [동네정보] 게시글 상세 조회 + */ + @Override + @Transactional(propagation = Propagation.REQUIRED) + public DongnaeBoardDto.Response getBoard(long board_id) { + User user = getCurUser(); + DongnaeBoard board = dongnaeBoardRepository.findById(board_id).orElseThrow(() -> + new CustomException(ErrorCode.NO_CONTENT_FOUND)); + + + //Get Images + List images = dongnaeImgRepository.findAllByDongnaeBoard_Id(board_id); + + //Writer인지 검사 + boolean isWriter = Objects.equals(board.getUser().getId(), user.getId()); + + //LikeOrNot 검사 + boolean likeOrNot = !dongnaeSympathyRepository.findByUser_Id(user.getId()).isEmpty(); + + //TODO: ScrapRepository 필요 + //scrapOrNot 검사 + boolean scrapOrNot = false; + + return DongnaeBoardDto.Response.builder() + + .profileImage(board.getUser().getProfileImage()) + .nickname(board.getUser().getNickname()) + .category(board.getCategory().getValue()) + .title(board.getTitle()) + .content(board.getContent()) + .images(images.stream().map(DongnaeImg::getImageUrl).collect(Collectors.toList())) + .place(board.getPlace()) + .placeLocation(board.getPlaceLocation()) + .createdAt(getTime(board.getCreatedAt())) + .townCertification(user.getTownCertCnt()) + .isWriter(isWriter) + .likeOrNot(likeOrNot) + .scrapOrNot(scrapOrNot) + .view(board.getView()).build(); + } + + + /* + * [동네정보] 게시글 수정 + */ + @Override + public void updateBoard(long board_id, DongnaeBoardDto.Request request) { + User user = getCurUser(); + Optional board = dongnaeBoardRepository.findById(board_id); + if (board.isPresent()) { + //User Validaiton + if (!Objects.equals(board.get().getUser().getId(), user.getId())) { + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } + board.get().updateBoard(request); + dongnaeBoardRepository.save(board.get()); + } else { + throw new CustomException(ErrorCode.INVALID_VALUE); + } + } + + @Override + public void deleteBoard(long board_id) { + User user = getCurUser(); + Optional board = dongnaeBoardRepository.findById(board_id); + + if (board.isEmpty()) throw new CustomException(ErrorCode.NO_CONTENT_FOUND); + //User Validation + if (!Objects.equals(board.get().getUser().getId(), user.getId())) { + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } else { + dongnaeBoardRepository.deleteById(board_id); + } + + } + + + //ListResponse 변환 + private List getListResponses(List dongnaeBoardList) { + return dongnaeBoardList.stream() + .map(origin -> DongnaeBoardDto.ListResponse.builder() + .id(origin.getId()) + .town(origin.getPlace()) + .category(origin.getCategory().getValue()) + .title(origin.getTitle()) + .content(origin.getContent()) + .imageUrl( + dongnaeImgRepository.findFirst(origin.getId()).map(DongnaeImg::getImageUrl).orElse("") + ) + .createdAt( + getTime(origin.getCreatedAt()) + ) + .view(origin.getView()) + .commentCount( + dongnaeCommentRepository.countAllByDongnaeBoardId(origin.getId()) + ) + .likes( + dongnaeSympathyRepository.countAllByDongnaeBoardId(origin.getId()) + ) + .build()) + .collect(Collectors.toList()); + } + + + private User getCurUser() { + Long user_id = (Long) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + return userRepository.findById(user_id).orElseThrow(() -> + new CustomException(ErrorCode.UNAUTHORIZED_MEMBER) + ); + } +} + + + diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/AccountBookProfileController.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/AccountBookProfileController.java new file mode 100644 index 0000000..ba3a0d0 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/AccountBookProfileController.java @@ -0,0 +1,28 @@ +package com.umc.DongnaeFriend.domain.profile.controller; + +import com.umc.DongnaeFriend.domain.profile.dto.AccountBookProfileDto; +import com.umc.DongnaeFriend.domain.profile.service.AccountBookProfileService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequiredArgsConstructor +public class AccountBookProfileController { + + private final AccountBookProfileService accountBookProfileService; + + // 동네정보 프로필 조회 + @GetMapping({"/api/my/account-books", "/api/{userId}/account-books"}) + public ResponseEntity getProfile(@PathVariable(value = "userId", required = false) Long userId, + @RequestParam int category, Pageable pageable){ + return ResponseEntity.status(HttpStatus.OK).body(accountBookProfileService.getAbSharing(userId, category, pageable)); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/DongnaeProfileController.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/DongnaeProfileController.java new file mode 100644 index 0000000..9847446 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/DongnaeProfileController.java @@ -0,0 +1,34 @@ +package com.umc.DongnaeFriend.domain.profile.controller; + +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; +import com.umc.DongnaeFriend.domain.profile.dto.DongnaeProfileDto; +import com.umc.DongnaeFriend.domain.profile.dto.MyPageDto; +import com.umc.DongnaeFriend.domain.profile.service.DongnaeProfileService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Pageable; +import org.springframework.data.repository.query.Param; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@Slf4j +@RestController +@RequiredArgsConstructor +public class DongnaeProfileController { + + private final DongnaeProfileService dongnaeProfileService; + + // 동네정보 프로필 조회 + @GetMapping({"/api/my/town", "/api/{userId}/town"}) + public ResponseEntity getProfile(@PathVariable(value = "userId", required = false) Long userId, + @RequestParam int category, Pageable pageable){ + return ResponseEntity.status(HttpStatus.OK).body(dongnaeProfileService.getDongnaeProfile(userId, category, pageable)); + } + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/MyPageController.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/MyPageController.java new file mode 100644 index 0000000..228f78c --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/controller/MyPageController.java @@ -0,0 +1,34 @@ +package com.umc.DongnaeFriend.domain.profile.controller; + + +import com.umc.DongnaeFriend.domain.profile.dto.MyPageDto; +import com.umc.DongnaeFriend.domain.profile.service.MyPageService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +@Slf4j +@RestController +@RequiredArgsConstructor +public class MyPageController { + + private final MyPageService myPageService; + + @GetMapping("/api/user") + public ResponseEntity getMyPage(){ + return ResponseEntity.status(HttpStatus.OK).body(myPageService.getMyPage()); + } + + @PutMapping("/api/user") + public ResponseEntity updateMyPage(@RequestPart(value = "request", required = false) MyPageDto.MyPageRequestDto myPageRequest, + @RequestPart(value = "image", required = false) MultipartFile image){ + + log.info("updateMyPage - 프로필 사진 변경"); + myPageService.updateMyPage(myPageRequest, image); + + return new ResponseEntity<>(HttpStatus.OK); + } +} \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java new file mode 100644 index 0000000..bc06ca6 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/AccountBookProfileDto.java @@ -0,0 +1,26 @@ +package com.umc.DongnaeFriend.domain.profile.dto; + +import com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +public class AccountBookProfileDto { + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class AccountBookProfileResponse{ + + private Long userId; + private boolean isMine; + private int postTotalCount; + private int commentTotalCount; + private int likedTotalCount; + private UserProfileDto.UserProfileResponseDto profile; + private List content; + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java new file mode 100644 index 0000000..f0e74b3 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/DongnaeProfileDto.java @@ -0,0 +1,27 @@ +package com.umc.DongnaeFriend.domain.profile.dto; + +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + + +public class DongnaeProfileDto { + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class DongnaeProfileResponse{ + + private Long userId; + private boolean isMine; + private int postTotalCount; + private int commentTotalCount; + private int likedTotalCount; + private UserProfileDto.UserProfileResponseDto profile; + private List content; + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/MyPageDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/MyPageDto.java new file mode 100644 index 0000000..4eeb2e3 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/MyPageDto.java @@ -0,0 +1,53 @@ +package com.umc.DongnaeFriend.domain.profile.dto; + +import com.umc.DongnaeFriend.domain.dongnae.dto.UserLocationDto; +import com.umc.DongnaeFriend.domain.type.Age; +import com.umc.DongnaeFriend.domain.type.Gender; +import com.umc.DongnaeFriend.domain.type.YesNo; +import com.umc.DongnaeFriend.domain.user.entity.User; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +public class MyPageDto { + + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class MyPageResponseDto{ + private String nickname; + private String profileImage; + private String town; + private Age age; + private Gender gender; + + public static MyPageResponseDto of(User user, UserLocationDto userLocation){ + return new MyPageResponseDto( + user.getNickname(), + user.getProfileImage(), + userLocation.getTown(), + user.getAge(), + user.getGender()); + } + } + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class MyPageRequestDto{ + private String nickname; + private Age age; + //private String profileImage; + private Gender gender; + private YesNo infoCert; + + public User toEntity(){ + return User.builder() + .nickname(nickname) + //.profileImage(profileImage) + .age(age) + .gender(gender) + .infoCert(infoCert) + .build(); + } + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/UserProfileDto.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/UserProfileDto.java new file mode 100644 index 0000000..117ecbc --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/dto/UserProfileDto.java @@ -0,0 +1,31 @@ +package com.umc.DongnaeFriend.domain.profile.dto; + +import com.umc.DongnaeFriend.domain.dongnae.dto.UserLocationDto; +import com.umc.DongnaeFriend.domain.type.Age; +import com.umc.DongnaeFriend.domain.type.Gender; +import com.umc.DongnaeFriend.domain.user.entity.User; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +public class UserProfileDto{ + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class UserProfileResponseDto { + private String nickname; + private String profileImage; + private String town; + private Age age; + private Gender gender; + + public static UserProfileDto.UserProfileResponseDto of(User user) { + return new UserProfileDto.UserProfileResponseDto( + user.getNickname(), + user.getProfileImage(), + user.getDongnae().getTownName(), + user.getAge(), + user.getGender()); + } + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java new file mode 100644 index 0000000..e226e7d --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/AccountBookProfileService.java @@ -0,0 +1,106 @@ +package com.umc.DongnaeFriend.domain.profile.service; + +import com.umc.DongnaeFriend.domain.account.sharing.dto.SharingDto; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingComment; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingImg; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingBoardRepository; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingCommentRepository; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingImgRepository; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingSympathyRepository; +import com.umc.DongnaeFriend.domain.profile.dto.AccountBookProfileDto; +import com.umc.DongnaeFriend.domain.profile.dto.UserProfileDto; +import com.umc.DongnaeFriend.domain.user.entity.User; +import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +import static com.umc.DongnaeFriend.global.util.TimeUtil.getTime; + +/** + * TODO : 공감, 스크랩 게시물 조회 필요 + */ +@Service +@RequiredArgsConstructor +public class AccountBookProfileService { + + private final UserRepository userRepository; + private final SharingBoardRepository sharingBoardRepository; + private final SharingCommentRepository sharingCommentRepository; + private final SharingSympathyRepository sharingSympathyRepository; + private final SharingImgRepository sharingImgRepository; + + // 본인 or 타사용자 확인 + private User checkUser(Long userId){ + User user; + if(userId==null){ // 유저아이디가 없으면 본인 + user = findUser(); + }else{ + user = userRepository.findById(userId) + .orElseThrow(); + } + return user; + } + + /** + * 가계부 공유 프로필 조회 + */ + public AccountBookProfileDto.AccountBookProfileResponse getAbSharing(Long userId, int category, Pageable pageable){ + User user = checkUser(userId); + + // 유저 아이디가 있으면 타사용자, 유저아이디가 없으면 본인 + return AccountBookProfileDto.AccountBookProfileResponse.builder() + .userId(userId==null ? findUser().getId() : userId) + .isMine(user.getId().equals(findUser().getId())) + .postTotalCount(sharingBoardRepository.countAllByUserId(user.getId())) + .commentTotalCount(sharingCommentRepository.countAllByUserId(user.getId())) + .likedTotalCount(sharingSympathyRepository.countAllByUserId(user.getId())) + .profile(UserProfileDto.UserProfileResponseDto.of(user)) + .content(getWrittenContent(user.getId(), category, pageable)) + .build(); + } + + /** + * 가계부 공유 - 작성한 글 , 작성한 댓글의 게시글 조회 + */ + public List getWrittenContent(Long userId, int category, Pageable pageable) { + User user = checkUser(userId); + + List sharingBoardList; + if(category==0){ + sharingBoardList= sharingBoardRepository.findAllByUserId(user.getId(), pageable); + }else{ + sharingBoardList = sharingCommentRepository.getCommentByUserIdAndBoard(user.getId()) + .stream().map(SharingComment::getSharingBoard).distinct().collect(Collectors.toList()); + } + return getProfileListResponse(sharingBoardList); + } + + + //ListResponse 변환 + private List getProfileListResponse(List sharingBoardList){ + return sharingBoardList.stream() + .map(sharingBoard -> SharingDto.AccountBookProfileListResponse.builder() + .boardId(sharingBoard.getId()) + //.town(sharingBoard.getPlaceLocation()) + .category(sharingBoard.getCategory().getValue()) + .title(sharingBoard.getTitle()) + .imageUrl(sharingImgRepository.findFirst(sharingBoard.getId()).map(SharingImg::getImageUrl).orElse("")) + .createdAt(getTime(sharingBoard.getCreatedAt())) + .commentCount(sharingCommentRepository.countAllBySharingBoardId(sharingBoard.getId())) + .likeCount(sharingSympathyRepository.countAllBySharingBoardId(sharingBoard.getId())) + .build()) + .collect(Collectors.toList()); + } + + public User findUser() { + Object userId = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + return userRepository.findById((Long) userId) + .orElseThrow(); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java new file mode 100644 index 0000000..c305809 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/DongnaeProfileService.java @@ -0,0 +1,104 @@ +package com.umc.DongnaeFriend.domain.profile.service; + +import com.umc.DongnaeFriend.domain.dongnae.dto.DongnaeBoardDto; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeComment; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeImg; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeBoardRepository; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeCommentRepository; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeImgRepository; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeSympathyRepository; +import com.umc.DongnaeFriend.domain.profile.dto.DongnaeProfileDto; +import com.umc.DongnaeFriend.domain.profile.dto.UserProfileDto; +import com.umc.DongnaeFriend.domain.user.entity.User; +import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +import static com.umc.DongnaeFriend.global.util.TimeUtil.getTime; + +/** + * TODO : 공감, 스크랩 게시물 조회 필요 + */ +@Service +@RequiredArgsConstructor +public class DongnaeProfileService { + + private final DongnaeSympathyRepository dongnaeSympathyRepository; + private final DongnaeCommentRepository commentRepository; + private final DongnaeBoardRepository dongnaeBoardRepository; + private final DongnaeImgRepository dongnaeImgRepository; + private final UserRepository userRepository; + + // 본인 or 타사용자 확인 + private User checkUser(Long userId){ + User user; + if(userId==null){ // 유저아이디가 없으면 본인 + user = findUser(); + }else{ + user = userRepository.findById(userId) + .orElseThrow(); + } + return user; + } + + /** + * 동네 정보 프로필 조회 + */ + public DongnaeProfileDto.DongnaeProfileResponse getDongnaeProfile(Long userId, int category, Pageable pageable){ + // 유저 아이디가 있으면 타사용자, 유저아이디가 없으면 본인 + User user = checkUser(userId); + + return DongnaeProfileDto.DongnaeProfileResponse.builder() + .userId(userId==null ? findUser().getId() : userId) + .isMine(user.getId().equals(findUser().getId())) + .postTotalCount(dongnaeBoardRepository.countAllByUserId(user.getId())) + .commentTotalCount(commentRepository.countAllByUserId(user.getId())) + .likedTotalCount(dongnaeSympathyRepository.countAllByUserId(user.getId())) + .profile(UserProfileDto.UserProfileResponseDto.of(user)) + .content(getWrittenContent(user.getId(), category, pageable)) + .build(); + } + + /** + * 동네정보 - 작성한 글 , 작성한 댓글의 게시글 조회 + */ + public List getWrittenContent(Long userId, int category, Pageable pageable) { + User user = checkUser(userId); + + List dongnaeBoardList; + if(category==0){ + dongnaeBoardList= dongnaeBoardRepository.findAllByUserId(user.getId()); + }else{ + dongnaeBoardList = commentRepository.getCommentByUserIdAndBoard(user.getId()) + .stream().map(DongnaeComment::getDongnaeBoard).distinct().collect(Collectors.toList()); + } + return getProfileListResponse(dongnaeBoardList); + } + + //ListResponse 변환 + private List getProfileListResponse(List dongnaeBoardList){ + return dongnaeBoardList.stream() + .map(dongnaeBoard -> DongnaeBoardDto.DongnaeProfileListResponse.builder() + .boardId(dongnaeBoard.getId()) + .town(dongnaeBoard.getPlaceLocation()) + .category(dongnaeBoard.getCategory().getValue()) + .title(dongnaeBoard.getTitle()) + .imageUrl(dongnaeImgRepository.findFirst(dongnaeBoard.getId()).map(DongnaeImg::getImageUrl).orElse("")) + .createdAt(getTime(dongnaeBoard.getCreatedAt())) + .commentCount(commentRepository.countAllByDongnaeBoardId(dongnaeBoard.getId())) + .likeCount(dongnaeSympathyRepository.countAllByDongnaeBoardId(dongnaeBoard.getId())) + .build()) + .collect(Collectors.toList()); + } + public User findUser() { + Object userId = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + return userRepository.findById((Long) userId) + .orElseThrow(); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/profile/service/MyPageService.java b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/MyPageService.java new file mode 100644 index 0000000..73fea1e --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/profile/service/MyPageService.java @@ -0,0 +1,77 @@ +package com.umc.DongnaeFriend.domain.profile.service; + +import com.umc.DongnaeFriend.domain.dongnae.dto.UserLocationDto; +import com.umc.DongnaeFriend.domain.dongnae.entity.Dongnae; +import com.umc.DongnaeFriend.domain.profile.dto.MyPageDto; +import com.umc.DongnaeFriend.domain.type.Age; +import com.umc.DongnaeFriend.domain.type.Gender; +import com.umc.DongnaeFriend.domain.type.YesNo; +import com.umc.DongnaeFriend.domain.user.entity.User; +import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import com.umc.DongnaeFriend.global.util.FileUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; + +@Slf4j +@Service +@RequiredArgsConstructor +public class MyPageService { + + /** + * 사용자 정보 확인 필요 ! + */ + private final UserRepository userRepository; + + //임시 유저 & 동네 + Dongnae dongnae = Dongnae.builder().id(1L).gu("서울구").dong("서울동").city("서울시").townName("무슨마을").build(); + User user = User.builder().age(Age.AGE10).profileImage("profileImg").email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).townCertCnt(30).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); + + + public MyPageDto.MyPageResponseDto getMyPage(){ + User user = findUser(); + return MyPageDto.MyPageResponseDto.of(user, getUserLocation()); + } + + public void updateMyPage(MyPageDto.MyPageRequestDto myPageRequest, MultipartFile image){ + //User user = User.builder().age(Age.AGE10).profileImage("profileImg").email("email").dongnae(dongnae).gender(Gender.FEMALE).infoCert(YesNo.NO).townCert(YesNo.NO).id(1L).kakaoId(90L).nickname("nickname").refreshToken("refreshToken").build(); + + User user = findUser(); + String fileName = "ProfileImage_" + user.getId().toString()+".png"; + + log.info("fileName : " + fileName); + + try { + log.info("fileUpload 시작합니당"); + log.info("image : " + image.isEmpty()); + log.info("filename : " + fileName); + FileUtil.fileUpload(image, fileName); + + }catch (IOException e){ + throw new RuntimeException(e); + } + user.updateProfileImage(fileName); + log.info("프로필 이미지 업데이트완료"); + user.updateProfile(myPageRequest.toEntity()); + + log.info("유저 닉네임 : " + user.getNickname()); + log.info("유저 프로필 : " + user.getProfileImage()); + log.info("유저 age : " + user.getAge()); + log.info("유저 gender : " + user.getGender()); + log.info("유저 infocert : " + user.getInfoCert()); + } + public UserLocationDto getUserLocation(){ + return new UserLocationDto("한남동"); + } + + public User findUser(){ + Object userId = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + return userRepository.findById((Long)userId) + .orElseThrow(); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/report/controller/ReportController.java b/src/main/java/com/umc/DongnaeFriend/domain/report/controller/ReportController.java new file mode 100644 index 0000000..55ba2c5 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/report/controller/ReportController.java @@ -0,0 +1,25 @@ +package com.umc.DongnaeFriend.domain.report.controller; + +import com.umc.DongnaeFriend.domain.report.dto.ReportDto; +import com.umc.DongnaeFriend.domain.report.service.ReportService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/report") +public class ReportController { + + private final ReportService reportService; + + @PostMapping + public ResponseEntity reportBoard(@RequestBody ReportDto.ReportRequest request) { + reportService.report(request); + return ResponseEntity.ok().build(); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/report/dto/ReportDto.java b/src/main/java/com/umc/DongnaeFriend/domain/report/dto/ReportDto.java new file mode 100644 index 0000000..f5c3166 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/report/dto/ReportDto.java @@ -0,0 +1,41 @@ +package com.umc.DongnaeFriend.domain.report.dto; + +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingComment; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeComment; +import com.umc.DongnaeFriend.domain.report.entity.Report; +import com.umc.DongnaeFriend.domain.user.entity.User; +import javax.validation.constraints.NotBlank; +import lombok.Getter; +import lombok.NoArgsConstructor; + +public class ReportDto { + + @Getter + @NoArgsConstructor + public static class ReportRequest { + + private Long reportUserId; + private Long sharingBoardId; + private Long dongnaeBoardId; + private Long sharingCommentId; + private Long dongnaeCommentId; + + @NotBlank(message = "신고사유는 필수 값입니다.") + private String content; + + public Report toEntity(User user, User reportUser, DongnaeBoard db, SharingBoard sb, + DongnaeComment dc, SharingComment sc, String content) { + return Report.builder() + .user(user) + .reportUser(reportUser) + .dongnaeBoard(db) + .sharingBoard(sb) + .dongnaeComment(dc) + .sharingComment(sc) + .content(content) + .build(); + } + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/report/entity/Report.java b/src/main/java/com/umc/DongnaeFriend/domain/report/entity/Report.java new file mode 100644 index 0000000..429259f --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/report/entity/Report.java @@ -0,0 +1,61 @@ +package com.umc.DongnaeFriend.domain.report.entity; + +import static javax.persistence.FetchType.LAZY; +import static javax.persistence.GenerationType.IDENTITY; +import static lombok.AccessLevel.PRIVATE; +import static lombok.AccessLevel.PROTECTED; + +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingComment; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeComment; +import com.umc.DongnaeFriend.domain.user.entity.User; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Builder +@NoArgsConstructor(access = PROTECTED) +@AllArgsConstructor(access = PRIVATE) +@Entity +public class Report { + @Id + @GeneratedValue(strategy = IDENTITY) + @Column(name = "report_id") + private Long id; + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "user_id", nullable = false) + private User user; + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "report_user_id") + private User reportUser; + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "dongnae_board_id") + private DongnaeBoard dongnaeBoard; + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "sharing_board_id") + private SharingBoard sharingBoard; + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "dongnae_comment_id") + private DongnaeComment dongnaeComment; + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "sharing_comment_id") + private SharingComment sharingComment; + + @Column(columnDefinition = "MEDIUMTEXT", nullable = false) + private String content; //신고사유 +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepository.java new file mode 100644 index 0000000..612b6e3 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepository.java @@ -0,0 +1,8 @@ +package com.umc.DongnaeFriend.domain.report.repository; + +import com.umc.DongnaeFriend.domain.report.entity.Report; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ReportRepository extends JpaRepository, ReportRepositoryCustom { + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepositoryCustom.java b/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepositoryCustom.java new file mode 100644 index 0000000..284f95a --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepositoryCustom.java @@ -0,0 +1,10 @@ +package com.umc.DongnaeFriend.domain.report.repository; + +import com.umc.DongnaeFriend.domain.report.dto.ReportDto.ReportRequest; +import com.umc.DongnaeFriend.domain.report.entity.Report; +import java.util.Optional; + +public interface ReportRepositoryCustom { + + Optional findByUserAndPost(Long userId, ReportRequest request); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepositoryImpl.java b/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepositoryImpl.java new file mode 100644 index 0000000..58d5ca7 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/report/repository/ReportRepositoryImpl.java @@ -0,0 +1,59 @@ +package com.umc.DongnaeFriend.domain.report.repository; + +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; + +import static com.umc.DongnaeFriend.domain.report.entity.QReport.report; + +import com.umc.DongnaeFriend.domain.report.dto.ReportDto.ReportRequest; +import com.umc.DongnaeFriend.domain.report.entity.Report; +import java.util.Optional; +import javax.persistence.EntityManager; + +public class ReportRepositoryImpl implements ReportRepositoryCustom { + + private final JPAQueryFactory queryFactory; + private final EntityManager em; + + public ReportRepositoryImpl(EntityManager em) { + this.em = em; + this.queryFactory = new JPAQueryFactory(em); + } + + @Override + public Optional findByUserAndPost(Long userId, ReportRequest request) { + + Report result = queryFactory + .selectFrom(report) + .where( + userEq(userId), + dongnaeBoardEq(request.getDongnaeBoardId()), + sharingBoardEq(request.getSharingBoardId()), + dongnaeCommentEq(request.getDongnaeCommentId()), + sharingCommentEq(request.getSharingCommentId()) + ) + .fetchOne(); + return Optional.ofNullable(result); + } + + private BooleanExpression userEq(Long userId) { + return report.user.id.eq(userId); + } + + private BooleanExpression dongnaeBoardEq(Long dongnaeBoardId) { + return dongnaeBoardId == null ? null : report.dongnaeBoard.id.eq(dongnaeBoardId); + } + + private BooleanExpression sharingBoardEq(Long sharingBoardId) { + return sharingBoardId == null ? null : report.sharingBoard.id.eq(sharingBoardId); + } + + private BooleanExpression dongnaeCommentEq(Long dongnaeCommentId) { + return dongnaeCommentId == null ? null : report.dongnaeComment.id.eq(dongnaeCommentId); + } + + private BooleanExpression sharingCommentEq(Long sharingCommentId) { + return sharingCommentId == null ? null : report.sharingComment.id.eq(sharingCommentId); + } + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/report/service/ReportService.java b/src/main/java/com/umc/DongnaeFriend/domain/report/service/ReportService.java new file mode 100644 index 0000000..f598059 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/report/service/ReportService.java @@ -0,0 +1,88 @@ +package com.umc.DongnaeFriend.domain.report.service; + +import static com.umc.DongnaeFriend.global.exception.ErrorCode.COMMENT_NOT_EXISTS; +import static com.umc.DongnaeFriend.global.exception.ErrorCode.POST_NOT_EXISTS; +import static com.umc.DongnaeFriend.global.exception.ErrorCode.REPORT_ALREADY_EXISTS; +import static com.umc.DongnaeFriend.global.exception.ErrorCode.USER_NOT_FOUND; + +import com.umc.DongnaeFriend.domain.account.sharing.entity.QSharingBoard; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingBoard; +import com.umc.DongnaeFriend.domain.account.sharing.entity.SharingComment; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingBoardRepository; +import com.umc.DongnaeFriend.domain.account.sharing.repository.SharingCommentRepository; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeBoard; +import com.umc.DongnaeFriend.domain.dongnae.entity.DongnaeComment; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeBoardRepository; +import com.umc.DongnaeFriend.domain.dongnae.respository.DongnaeCommentRepository; +import com.umc.DongnaeFriend.domain.report.dto.ReportDto; +import com.umc.DongnaeFriend.domain.report.entity.Report; +import com.umc.DongnaeFriend.domain.report.repository.ReportRepository; +import com.umc.DongnaeFriend.domain.user.entity.User; +import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import com.umc.DongnaeFriend.global.exception.CustomException; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +@RequiredArgsConstructor +public class ReportService { + + private final UserRepository userRepository; + private final ReportRepository reportRepository; + private final DongnaeBoardRepository dongnaeBoardRepository; + private final DongnaeCommentRepository dongnaeCommentRepository; + private final SharingBoardRepository sharingBoardRepository; + private final SharingCommentRepository sharingCommentRepository; + + public void report(ReportDto.ReportRequest request) { + User user = userRepository.findById(getId()) + .orElseThrow(() -> new CustomException(USER_NOT_FOUND)); + + reportDuplicateCheck(user.getId(), request); + + request.toString(); + + User reportUser = null; + DongnaeBoard db = null; + SharingBoard sb = null; + DongnaeComment dc = null; + SharingComment sc = null; + + if (request.getReportUserId() != null) { + reportUser = userRepository.findById(request.getReportUserId()) + .orElseThrow(() -> new CustomException(USER_NOT_FOUND)); + } else if (request.getDongnaeBoardId() != null) { + db = dongnaeBoardRepository.findById(request.getDongnaeBoardId()) + .orElseThrow(() -> new CustomException(POST_NOT_EXISTS)); + } else if (request.getSharingBoardId() != null) { + sb = sharingBoardRepository.findById(request.getSharingBoardId()) + .orElseThrow(() -> new CustomException(POST_NOT_EXISTS)); + } else if (request.getDongnaeCommentId() != null) { + dc = dongnaeCommentRepository.findById(request.getDongnaeCommentId()) + .orElseThrow(() -> new CustomException(COMMENT_NOT_EXISTS)); + } else { + sc = sharingCommentRepository.findById(request.getSharingCommentId()) + .orElseThrow(() -> new CustomException(COMMENT_NOT_EXISTS)); + } + + Report report = request.toEntity(user, reportUser, db, sb, dc, sc, request.getContent()); + reportRepository.save(report); + } + + public Long getId() { + return (Long) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + } + + /** + * 신고 중복체크 + */ + public void reportDuplicateCheck(Long userId, ReportDto.ReportRequest request) { + reportRepository.findByUserAndPost(userId, request).ifPresent(report -> + { + throw new CustomException(REPORT_ALREADY_EXISTS); + }); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/type/Age.java b/src/main/java/com/umc/DongnaeFriend/domain/type/Age.java index 0228124..e55b91f 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/type/Age.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/type/Age.java @@ -22,4 +22,17 @@ public enum Age { public String getAge() { return this.age; } + + public static Age fromString(String strAge) { + if(strAge==""){ + return null; + } + + for(Age age : Age.values()){ + if((age.getAge().charAt(0))==(strAge.charAt(0))){ + return age; + } + } + return null; + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/type/DongnaeBoardCategory.java b/src/main/java/com/umc/DongnaeFriend/domain/type/DongnaeBoardCategory.java index 23ce7ee..b22db9f 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/type/DongnaeBoardCategory.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/type/DongnaeBoardCategory.java @@ -15,4 +15,13 @@ public enum DongnaeBoardCategory { private final Integer value; private final String category; + + public static DongnaeBoardCategory valueOf(Integer value) { + for (DongnaeBoardCategory category : DongnaeBoardCategory.values()) { + if (category.getValue().equals(value)) { + return category; + } + } + throw new IllegalArgumentException("Invalid Category: " + value); + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/type/Gender.java b/src/main/java/com/umc/DongnaeFriend/domain/type/Gender.java index 64f11eb..e5f1c83 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/type/Gender.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/type/Gender.java @@ -3,9 +3,11 @@ import com.fasterxml.jackson.annotation.JsonValue; import lombok.Getter; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; @Getter @RequiredArgsConstructor +@Slf4j public enum Gender { MALE(0, "남성"), FEMALE(1, "여성"); @@ -17,4 +19,14 @@ public enum Gender { public String getGender() { return this.gender; } + + public static Gender fromString(String strGender) { + + for(Gender gender : Gender.values()){ + if(gender.toString().equalsIgnoreCase(strGender)){ + return strGender.equals("male")? Gender.MALE : Gender.FEMALE; + } + } + return null; + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/type/SharingCategory.java b/src/main/java/com/umc/DongnaeFriend/domain/type/SharingCategory.java index bfd3248..e10aa9d 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/type/SharingCategory.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/type/SharingCategory.java @@ -1,5 +1,7 @@ package com.umc.DongnaeFriend.domain.type; +import com.umc.DongnaeFriend.global.exception.CustomException; +import com.umc.DongnaeFriend.global.exception.ErrorCode; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -13,4 +15,13 @@ public enum SharingCategory { private final Integer value; private final String category; + + public static SharingCategory valueOf(Integer value) { + for (SharingCategory category : SharingCategory.values()) { + if (category.getValue().equals(value)) { + return category; + } else throw new CustomException(ErrorCode.INVALID_VALUE); + } + throw new IllegalArgumentException("Invalid Category: " + value); + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/type/TransactionCategory.java b/src/main/java/com/umc/DongnaeFriend/domain/type/TransactionCategory.java index a77a048..0c1dfa4 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/type/TransactionCategory.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/type/TransactionCategory.java @@ -1,24 +1,35 @@ package com.umc.DongnaeFriend.domain.type; import com.fasterxml.jackson.annotation.JsonValue; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.RequiredArgsConstructor; @Getter @RequiredArgsConstructor public enum TransactionCategory { + FOODS(0, "식비"), - TRANSPORTATION(1, "교통비"), - CULTURE(2, "문화"), - DAILY_NECESSITY(3, "생필품"), - SECOND_HAND(4, "중고거래"), - FASHION(5, "미용/패션"), + CAFE_SNACK(1, "카페/간식"), + MART(2, "편의점/마트"), + ALCOHOL_PARTY(3, "술/유흥"), + SHOPPING(4, "쇼핑"), + HOBBY_LEISURE(5, "취미/여가"), HEALTH(6, "건강"), - EDUCATION(7, "교육"), - FIXED_EXPENSES(8, "고정 지출"), - OTT(9, "OTT"), - ETC(10, "기타"); + LIVING_COMMUNICATION(7, "주거/통신"), + INSURANCE_FINANCE(8, "보험/금융"), + BEAUTY(9, "미용"), + TRANSPORTATION(10, "교통비"), + TRAVEL_LODGE(11, "여행/숙박"), + EDUCATION(12, "교육"), + SAVING_INVESTMENT(13, "저축/투자"), + EXPENDITURE_ETC(14, "기타(지출)"), + SALARY(15, "월급"), + ALLOWANCE(16, "용돈"), + TRANSFER(17, "이월"), + WITHDRAW(18, "자산인출"), + INCOME_ETC(18, "기타(수입)"); private final Integer value; private final String category; diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java b/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java new file mode 100644 index 0000000..cc30211 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/contorller/UserController.java @@ -0,0 +1,80 @@ +package com.umc.DongnaeFriend.domain.user.contorller; + +import com.umc.DongnaeFriend.domain.user.dto.UserDto; +import com.umc.DongnaeFriend.domain.user.service.KakaoService; +import com.umc.DongnaeFriend.domain.user.service.UserService; +import com.umc.DongnaeFriend.global.exception.CustomException; +import com.umc.DongnaeFriend.global.exception.ErrorCode; +import com.umc.DongnaeFriend.global.util.JwtTokenProvider; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.repository.query.Param; +import org.springframework.http.*; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.HashMap; + +@RestController +@RequestMapping("/user") +@Slf4j +public class UserController { + + @Autowired + KakaoService kakaoService; + + @Autowired + UserService userService; + + @Autowired + JwtTokenProvider jwtTokenProvider; + + + + /** + * 유저 로그인 / 회원가입 + * 인증 절차 + */ + @PostMapping("/login") + public ResponseEntity userLogin(@RequestParam("accessToken") String accessToken, HttpServletRequest request, HttpServletResponse httpServletResponse) { + log.info("LoginController 진입"); + +// if (!type.equals("kakao")) { +// throw new CustomException(ErrorCode.SERVER_ERROR); +// } + + + try { + log.info("userLogin 진입"); + //사용자 정보 가져오기 + HashMap userInfo = kakaoService.getUserInfo(accessToken); + + //사용자 확인 기존 회원 -> 넘어가고, 없는 회원 -> 회원가입 + + UserDto.Response response = userService.userValidation(userInfo); + + return ResponseEntity.ok(response); + + } catch (IOException e) { + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } + } + + @PostMapping("/user/reissuance") + public ResponseEntity reiussnaceToken(String refreshToken) { + try { + + //토큰 재발급 + String access_token = userService.createAccessTokenFromRefreshToken(refreshToken); + return ResponseEntity.ok(access_token); + } catch (Exception e) { + // RefreshToken만료 + throw new CustomException(ErrorCode.INVALID_REFRESH_TOKEN); + } + } + + + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/dto/UserDto.java b/src/main/java/com/umc/DongnaeFriend/domain/user/dto/UserDto.java new file mode 100644 index 0000000..0ebf5bc --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/dto/UserDto.java @@ -0,0 +1,42 @@ +package com.umc.DongnaeFriend.domain.user.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +public class UserDto { + + @Getter + @AllArgsConstructor + public static class Request { + + String accessToken; + + String type; + + } + + @Getter + @Builder + @AllArgsConstructor + public static class Response { + + String accessToken; + + String refreshToken; + + } + + @Getter + @AllArgsConstructor + public static class SignUpDto { + + String nickName; + + String email; + + Long kakaoId; + + } + +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java b/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java index 1d96f63..2ed546f 100644 --- a/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/entity/User.java @@ -13,6 +13,7 @@ import com.umc.DongnaeFriend.domain.type.YesNo; import javax.persistence.*; import lombok.*; +import org.springframework.lang.Nullable; @Getter @Builder @@ -20,7 +21,7 @@ @AllArgsConstructor(access = PRIVATE) @Entity @Table(name = "users") -public class User extends BaseTimeEntity { +public class User extends BaseTimeEntity { @Id @GeneratedValue(strategy = IDENTITY) @@ -28,7 +29,8 @@ public class User extends BaseTimeEntity { private Long id; @ManyToOne(fetch = LAZY) - @JoinColumn(name = "dongnae_id", nullable = false) + @JoinColumn(name = "dongnae_id") + @Nullable private Dongnae dongnae; @Column(nullable = false) @@ -58,4 +60,45 @@ public class User extends BaseTimeEntity { private String refreshToken; private Long kakaoId; + + /** + * 유저 정보 업데이트 로직 + */ + public void updateProfile(User updateUser){ + updateNickname(updateUser.nickname); + updateGender(updateUser.gender); + updateAge(updateUser.age); + updateProfileImage(this.profileImage); + updateInfoCert(updateUser.infoCert); + } + + public void updateNickname(String nickname){ + if(nickname!=null){ + this.nickname=nickname; + } + } + + public void updateProfileImage(String profileImage){ + if(profileImage!=null){ + this.profileImage=profileImage; + } + } + + public void updateAge(Age age){ + if(age!=null){ + this.age =age; + } + } + + public void updateGender(Gender gender){ + if(gender!=null){ + this.gender=gender; + } + } + + public void updateInfoCert(YesNo infoCert){ + if(infoCert!=null){ + this.infoCert=infoCert; + } + } } diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java b/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java new file mode 100644 index 0000000..1807bef --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/repository/UserRepository.java @@ -0,0 +1,14 @@ +package com.umc.DongnaeFriend.domain.user.repository; + +import com.umc.DongnaeFriend.domain.user.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + +public interface UserRepository extends JpaRepository { + + Optional findById(Long id); + + Optional findByRefreshToken(String refresh_token); + + Optional findByKakaoId(Long id); +} diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoService.java b/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoService.java new file mode 100644 index 0000000..d3cd29f --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoService.java @@ -0,0 +1,16 @@ +package com.umc.DongnaeFriend.domain.user.service; + + +import org.springframework.beans.factory.annotation.Value; + +import java.io.IOException; +import java.util.HashMap; + +public interface KakaoService { + + + @SuppressWarnings("unchecked") + HashMap getUserInfo(String access_Token) throws IOException; +} + + diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java b/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java new file mode 100644 index 0000000..047549b --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/service/KakaoServiceimpl.java @@ -0,0 +1,84 @@ +package com.umc.DongnaeFriend.domain.user.service; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@Service +public class KakaoServiceimpl implements KakaoService { + +// @Autowired +// public IACDao dao; + + @SuppressWarnings("unchecked") + @Override + public HashMap getUserInfo(String access_Token) throws IOException { + // 클라이언트 요청 정보 + HashMap userInfo = new HashMap(); + + + //------kakao GET 요청------ + String reqURL = "https://kapi.kakao.com/v2/user/me"; + URL url = new URL(reqURL); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + conn.setRequestProperty("Authorization", "Bearer " + access_Token); + + int responseCode = conn.getResponseCode(); + System.out.println("responseCode : " + responseCode); + + BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); + + String line = ""; + String result = ""; + + while ((line = br.readLine()) != null) { + result += line; + } + System.out.println("response body : " + result); + System.out.println("result type" + result.getClass().getName()); // java.lang.String + + // jackson objectmapper 객체 생성 + ObjectMapper objectMapper = new ObjectMapper(); + // JSON String -> Map + Map jsonMap = objectMapper.readValue(result, new TypeReference>() { + }); + + + System.out.println(jsonMap.get("properties")); + + Long id = (Long) jsonMap.get("id"); + Map properties = (Map) jsonMap.get("properties"); + Map kakao_account = (Map) jsonMap.get("kakao_account"); + Map profile = (Map) kakao_account.get("profile"); + + log.info("profile : " + profile.toString()); + log.info("kakao_acount : " + kakao_account.toString()); + + String nickname = properties.get("nickname").toString(); + String profileImage = properties.get("profile_image").toString(); + String email = kakao_account.get("email").toString(); + String gender = kakao_account.getOrDefault("gender","").toString(); + String age = kakao_account.getOrDefault("age_range","").toString(); + + userInfo.put("id", id); + userInfo.put("nickname", nickname); + userInfo.put("profileImage", profileImage); + userInfo.put("email", email); + userInfo.put("age", age); + userInfo.put("gender", gender); + + return userInfo; + } + +} \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java b/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java new file mode 100644 index 0000000..85a6f40 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/domain/user/service/UserService.java @@ -0,0 +1,141 @@ +package com.umc.DongnaeFriend.domain.user.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.umc.DongnaeFriend.domain.type.Age; +import com.umc.DongnaeFriend.domain.type.Gender; +import com.umc.DongnaeFriend.domain.type.YesNo; +import com.umc.DongnaeFriend.domain.user.dto.UserDto; +import com.umc.DongnaeFriend.domain.user.entity.User; +import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import com.umc.DongnaeFriend.global.exception.CustomException; +import com.umc.DongnaeFriend.global.exception.ErrorCode; +import com.umc.DongnaeFriend.global.util.JwtTokenProvider; +import com.umc.DongnaeFriend.global.util.JwtUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.HashMap; +import java.util.Optional; + +@Service +@Slf4j +public class UserService { + + @Autowired + UserRepository userRepository; + + KakaoService kakaoService; + + @Autowired + JwtTokenProvider jwtTokenProvider; + + + public UserDto.Response userValidation(HashMap userInfo) { + Long kakao_id = (Long) userInfo.get("id"); + Optional user= userRepository.findByKakaoId(kakao_id); + if (user.isEmpty()) { + User new_user = userRegister(userInfo); + return UserDto.Response.builder() + .accessToken(jwtTokenProvider.createAccessToken(new_user.getId())) + .refreshToken(new_user.getRefreshToken()) + .build(); + } else { + return UserDto.Response.builder() + .accessToken(jwtTokenProvider.createAccessToken(user.get().getId())) + .refreshToken(user.get().getRefreshToken()) + .build(); + } + + } + + + //유저 회원가입 -> Refresh Token을 return + public User userRegister(HashMap userInfo) { + //필수 + String nickName = userInfo.get("nickname").toString(); + //필수 + String email = userInfo.get("email").toString(); + + String profileImage = userInfo.get("profileImage").toString(); + + Long kakaoId = (Long) userInfo.get("id"); + + String strGender = userInfo.getOrDefault("gender", "").toString(); + String strAge = userInfo.getOrDefault("age", "").toString(); + + Gender gender = Gender.fromString(strGender); + Age age = Age.fromString(strAge); + + + String refresh_Token = jwtTokenProvider.createRefreshToken((Long) userInfo.get("id")); + + return userRepository.save( + User.builder() + .nickname(nickName) +// .dongnae( +// +// ) + .email(email) + .gender(gender) + .age(age) + .townCert(YesNo.NO) + .townCertCnt(0) + .infoCert(YesNo.NO) + .profileImage(profileImage) + .kakaoId(kakaoId) + .refreshToken(refresh_Token) + .build() + ); + } + + // RefreshToken으로 AccessToken 재발급 + public String createAccessTokenFromRefreshToken(String refreshToken) { + String accessToken = ""; + + // 전달받은 RefreshToken 정보로 사용자 조회(유효하지 않은 토큰일 시, 예외 발생) + Optional userByRefreshToken =Optional.ofNullable(userRepository.findByRefreshToken(refreshToken) + .orElseThrow(()-> new CustomException(ErrorCode.INVALID_REFRESH_TOKEN,"해당 refreshToken 이 존재하지 않음"))); + + // AccessToken 재발행 + accessToken = jwtTokenProvider.createAccessToken(userByRefreshToken.get().getId()); + log.info("AcessToken 재발행 성공"); + + return accessToken; + } + + public String kakaoGetCode() { + + + try { + String reqURL= "https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=1ad317e194df665ca44dcb82d11a7093&redirect_uri=http://localhost:8080/callback"; + + URL url = new URL(reqURL); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + + + BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); + + String line = ""; + String result = ""; + + while ((line = br.readLine()) != null) { + result += line; + } + + ObjectMapper objectMapper = new ObjectMapper(); + HashMap jsonMap = objectMapper.readValue(result, HashMap.class); + + log.info(jsonMap.toString()); + return ""; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/global/exception/CustomException.java b/src/main/java/com/umc/DongnaeFriend/global/exception/CustomException.java new file mode 100644 index 0000000..0465158 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/exception/CustomException.java @@ -0,0 +1,20 @@ +package com.umc.DongnaeFriend.global.exception; + +import lombok.Getter; +@Getter +public class CustomException extends RuntimeException { + + private ErrorCode errorCode; + private String errorMessage; + + public CustomException(ErrorCode errorCode) { + this.errorCode = errorCode; + this.errorMessage = errorCode.getDetail(); + } + + //@Valid 오류처리 + public CustomException(ErrorCode errorCode, String errorMessage) { + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorCode.java b/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorCode.java new file mode 100644 index 0000000..1befb4b --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorCode.java @@ -0,0 +1,53 @@ +package com.umc.DongnaeFriend.global.exception; + +import static org.springframework.http.HttpStatus.*; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum ErrorCode { + /* 10* 가계부 */ + + /* 20* 동네정보 */ + POST_NOT_EXISTS(BAD_REQUEST, 200, "없는 게시글입니다."), + COMMENT_NOT_EXISTS(BAD_REQUEST, 201, "없는 댓글입니다."), + + /* 50* 스크랩 */ + + /* 60* 신고 */ + REPORT_ALREADY_EXISTS(BAD_REQUEST, 600, "이미 신고 처리가 되었습니다."), + + /* 200 NO_CONTENT : 자료를 찾을 수 없음 */ + NO_CONTENT_FOUND(NO_CONTENT, 204, "요청된 자료를 찾을 수 없습니다."), + + /* 400 BAD_REQUEST : 잘못된 요청 */ + INVALID_REFRESH_TOKEN(BAD_REQUEST, 400, "리프레시 토큰이 유효하지 않습니다"), + MISMATCH_REFRESH_TOKEN(BAD_REQUEST, 400, "리프레시 토큰의 유저 정보가 일치하지 않습니다"), + CANNOT_FOLLOW_MYSELF(BAD_REQUEST, 400,"자기 자신은 팔로우 할 수 없습니다"), + INVALID_VALUE(BAD_REQUEST, 400, "잘못된 값입니다." ), + + + /* 401 UNAUTHORIZED : 인증되지 않은 사용자 */ + INVALID_AUTH_TOKEN(UNAUTHORIZED,401, "권한 정보가 없는 토큰입니다"), + UNAUTHORIZED_MEMBER(UNAUTHORIZED,401, "현재 내 계정 정보가 존재하지 않습니다"), + + /* 404 NOT_FOUND : Resource 를 찾을 수 없음 */ + USER_NOT_FOUND(NOT_FOUND,404, "해당 유저 정보를 찾을 수 없습니다"), + REFRESH_TOKEN_NOT_FOUND(NOT_FOUND, 404,"로그아웃 된 사용자입니다"), + NOT_FOLLOW(NOT_FOUND,404, "팔로우 중이지 않습니다"), + + + /* 409 CONFLICT : Resource 의 현재 상태와 충돌. 보통 중복된 데이터 존재 */ + DUPLICATE_RESOURCE(CONFLICT,409, "데이터가 이미 존재합니다"), + + //500 INTERNAL SERVER ERROR + SERVER_ERROR(INTERNAL_SERVER_ERROR, 500, "서버 에러입니다."); + + + private final HttpStatus httpStatus; + private final int errorCode; + private final String detail; +} \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorResponse.java b/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorResponse.java new file mode 100644 index 0000000..82a6fe2 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/exception/ErrorResponse.java @@ -0,0 +1,16 @@ +package com.umc.DongnaeFriend.global.exception; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class ErrorResponse { + + private final String message; + + public ErrorResponse(CustomException e){ + this.message = e.getErrorMessage(); + } + +} diff --git a/src/main/java/com/umc/DongnaeFriend/global/exception/GlobalExceptionHandler.java b/src/main/java/com/umc/DongnaeFriend/global/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..137db6e --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/exception/GlobalExceptionHandler.java @@ -0,0 +1,42 @@ +package com.umc.DongnaeFriend.global.exception; + +import static com.umc.DongnaeFriend.global.exception.ErrorCode.*; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.*; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + //custom Exception + @ExceptionHandler({CustomException.class}) + protected ResponseEntity handlecustomException(CustomException e) { + return ResponseEntity + .status(e.getErrorCode().getHttpStatus()) + .body(new ErrorResponse(e)); + } + + //@valid Exception + @ExceptionHandler({MethodArgumentNotValidException.class}) + protected ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { + String message = e.getBindingResult().getFieldError().getDefaultMessage(); + CustomException validException = new CustomException(INVALID_VALUE, message); + + return ResponseEntity + .status(HttpStatus.BAD_REQUEST) + .body(new ErrorResponse(validException)); + } + + + //일반 예외처리 +// @ExceptionHandler({Exception.class}) +// protected ResponseEntity handleServerException(Exception ex) { +// CustomException exception = new CustomException(SERVER_ERROR); +// return ResponseEntity +// .status(SERVER_ERROR.getHttpStatus()) +// .body(new ErrorResponse(exception)); +// } + +} \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/global/security/JwtTokenFilter.java b/src/main/java/com/umc/DongnaeFriend/global/security/JwtTokenFilter.java new file mode 100644 index 0000000..ae2d9b5 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/security/JwtTokenFilter.java @@ -0,0 +1,72 @@ +package com.umc.DongnaeFriend.global.security; + +import com.umc.DongnaeFriend.global.util.JwtUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Configuration +@Slf4j +public class JwtTokenFilter extends OncePerRequestFilter { + + + private final JwtUtil jwtUtil; + + public JwtTokenFilter(JwtUtil jwtUtil) { + this.jwtUtil = jwtUtil; + } + + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + + log.info("JwtTokenFilter 진입"); + + // Request Header에서 JWT 토큰 가져오기 + String authorizationHeader = request.getHeader("Authorization"); + log.info("authorizationHeader : {}",authorizationHeader); + + //🛑 첫 로그인 시에도 이곳에서 걸리기 때문에 로그인이 안됨.(null) + if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { + String token = authorizationHeader.substring(7); + log.info("token : {}", token); + try { + // JWT 토큰 검증 + jwtUtil.validateToken(token); + log.info("JWT 토큰 검증완료"); + + // JWT 토큰에서 사용자 정보 추출 (예: 사용자 ID) + Long userId = jwtUtil.getUserIdFromToken(token); + + // 인증 객체 생성 + UsernamePasswordAuthenticationToken authenticationToken = + new UsernamePasswordAuthenticationToken( userId,null, null); + + // SecurityContextHolder에 인증 객체 저장 + SecurityContextHolder.getContext().setAuthentication(authenticationToken); + + filterChain.doFilter(request, response); + + + } catch (Exception e) { + e.printStackTrace(); + + // JWT 토큰 검증 실패 시, 인증 객체를 null로 설정 + SecurityContextHolder.clearContext(); + filterChain.doFilter(request, response); + } + } else { + log.info("Header None"); + filterChain.doFilter(request, response); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/global/util/FileUtil.java b/src/main/java/com/umc/DongnaeFriend/global/util/FileUtil.java new file mode 100644 index 0000000..7e7b8fe --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/util/FileUtil.java @@ -0,0 +1,21 @@ +package com.umc.DongnaeFriend.global.util; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; + +@Slf4j +public class FileUtil { + + public static void fileUpload(MultipartFile file, String fileName) throws IOException{ + String filePath = "/home/ubuntu/app/src/main/resources/static/img/"; + + log.info("fileupload 들어옴!!"); + File dest = new File(filePath + fileName); + + log.info("dest : " + dest); + file.transferTo(dest); + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java b/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java new file mode 100644 index 0000000..af5c405 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/util/JwtTokenProvider.java @@ -0,0 +1,71 @@ +package com.umc.DongnaeFriend.global.util; + +import com.umc.DongnaeFriend.config.JwtConfig; +import com.umc.DongnaeFriend.domain.user.repository.UserRepository; +import io.jsonwebtoken.*; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Date; + + + +@Log4j2 +@Component +public class JwtTokenProvider { + + private final JwtConfig jwtConfig; + + @Autowired + private UserRepository userRepository; + + public JwtTokenProvider(JwtConfig jwtConfig, UserRepository userRepository) { + this.jwtConfig = jwtConfig; + this.userRepository = userRepository; + } + + private final Long ACCESS_TOKEN_EXPIRE_LENGTH = 1000L * 60 * 60 * 24 * 14; //2WEEK + private final Long REFRESH_TOKEN_EXPIRE_LENGTH = 1000L * 60 * 60 * 24 * 30; //30DAY + + + //accessToken 생성 + public String createAccessToken(Long userId) { + + log.info("SECRET KEY FROM PROVIDER: "+ jwtConfig.SECRET_KEY); + Date now = new Date(); //현재 시간 + Date validity = new Date(now.getTime() + ACCESS_TOKEN_EXPIRE_LENGTH); + + +// CustomAuthentication user = (CustomAuthentication) authentication.getPrincipal(); +// +// Claims claims = Jwts.claims().setSubject(user.getUsername()); +// claims.put("userId", user.getId()); // 사용자 아이디 +// claims.put("email", user.getEmail()); // 사용자 이메일 + + + return Jwts.builder() + .signWith(SignatureAlgorithm.HS512, String.valueOf(jwtConfig.SECRET_KEY)) + .claim("userId", userId) + .setIssuedAt(now) //token 발행 시간 + .setExpiration(validity) + .compact(); + } + + // RefreshToken 생성 + public String createRefreshToken(Long userId) { + Date now = new Date(); + Date validity = new Date(now.getTime() + REFRESH_TOKEN_EXPIRE_LENGTH); + + return Jwts.builder() + .signWith(SignatureAlgorithm.HS512, String.valueOf(jwtConfig.SECRET_KEY)) + .claim("userId", userId) + .setIssuedAt(now) + .setExpiration(validity) + .compact(); + } + + + + +} \ No newline at end of file diff --git a/src/main/java/com/umc/DongnaeFriend/global/util/JwtUtil.java b/src/main/java/com/umc/DongnaeFriend/global/util/JwtUtil.java new file mode 100644 index 0000000..a1c15b9 --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/util/JwtUtil.java @@ -0,0 +1,61 @@ +package com.umc.DongnaeFriend.global.util; + +import com.umc.DongnaeFriend.config.JwtConfig; +import com.umc.DongnaeFriend.global.exception.CustomException; +import com.umc.DongnaeFriend.global.exception.ErrorCode; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + + +@Slf4j +@Component +public class JwtUtil { + + private final JwtConfig jwtConfig; + + public JwtUtil(JwtConfig jwtConfig) { + this.jwtConfig = jwtConfig; + } + + public Long getUserIdFromToken(String token) { + log.info("token에서 ID 추출"); + Claims claims = Jwts.parser().setSigningKey(jwtConfig.SECRET_KEY).parseClaimsJws(token).getBody(); + return Long.parseLong(claims.get("userId").toString()); + } + + //token 유효성 검증 + public Boolean validateToken(String token) { + try { + log.info("SECRET KEY :"+ jwtConfig.SECRET_KEY); + + Jwts.parser().setSigningKey(jwtConfig.SECRET_KEY).parseClaimsJws(token); + return true; + } catch (SignatureException e) { + log.info("Sign 오류"); + e.printStackTrace(); + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } catch (IllegalArgumentException e) { + log.info("잘못된 토큰"); + e.printStackTrace(); + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } catch (MalformedJwtException e) { + log.info("토큰 잘림"); + e.printStackTrace(); + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } catch (ExpiredJwtException e) { + log.info("만료된 토큰"); + e.printStackTrace(); + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } catch (NullPointerException e) { + log.info("토큰 없음"); + e.printStackTrace(); + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } catch (UnsupportedJwtException e) { + log.info("지원되지 않는 토큰"); + e.printStackTrace(); + throw new CustomException(ErrorCode.INVALID_AUTH_TOKEN); + } + } +} diff --git a/src/main/java/com/umc/DongnaeFriend/global/util/TimeUtil.java b/src/main/java/com/umc/DongnaeFriend/global/util/TimeUtil.java new file mode 100644 index 0000000..527175e --- /dev/null +++ b/src/main/java/com/umc/DongnaeFriend/global/util/TimeUtil.java @@ -0,0 +1,29 @@ +package com.umc.DongnaeFriend.global.util; + +import java.time.Duration; +import java.time.LocalDateTime; + +public class TimeUtil { + + //시간 계산 + public static String getTime(LocalDateTime time) { + LocalDateTime now = LocalDateTime.now(); // 현재 시간 + Duration duration = Duration.between(now, time); + + long days = -duration.toDays(); + long hours = -duration.toHours() % 24; + long minutes = -duration.toMinutes() % 60; + + if (days >= 1){ + if (days == 1) { + return "어제"; + } + return days + "일 전"; + } + + else if (hours >= 1) { + return hours + "시간 전"; + } else return minutes + "분 전"; + + } +} diff --git a/src/main/resources/.DS_Store b/src/main/resources/.DS_Store new file mode 100644 index 0000000..aec3550 Binary files /dev/null and b/src/main/resources/.DS_Store differ diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 7878137..ea93b81 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -17,4 +17,6 @@ spring: password: df1234 driver-class-name: com.mysql.cj.jdbc.Driver jpa: - hibernate.ddl-auto: create \ No newline at end of file + hibernate.ddl-auto: update +jwt: + secret-key: 6B64DCA4EA2F53EDIKU9AAB215FE7 diff --git a/.gradle/8.1.1/dependencies-accessors/gc.properties b/src/main/resources/static/img/.keep similarity index 100% rename from .gradle/8.1.1/dependencies-accessors/gc.properties rename to src/main/resources/static/img/.keep diff --git a/src/main/resources/static/img/ProfileImage_1.png b/src/main/resources/static/img/ProfileImage_1.png new file mode 100644 index 0000000..db2c4a5 Binary files /dev/null and b/src/main/resources/static/img/ProfileImage_1.png differ diff --git a/src/main/resources/templates/.DS_Store b/src/main/resources/templates/.DS_Store new file mode 100644 index 0000000..3c68b2b Binary files /dev/null and b/src/main/resources/templates/.DS_Store differ diff --git a/src/main/resources/templates/html/.DS_Store b/src/main/resources/templates/html/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/src/main/resources/templates/html/.DS_Store differ diff --git a/src/main/resources/templates/html/index.html b/src/main/resources/templates/html/index.html new file mode 100644 index 0000000..39a3ed4 --- /dev/null +++ b/src/main/resources/templates/html/index.html @@ -0,0 +1,15 @@ + + + + My Page + + +
+

동네친구 카카오 로그인

+ + kakoLogin + + +
+ + diff --git a/src/main/resources/templates/html/kakao_login_large_wide.png b/src/main/resources/templates/html/kakao_login_large_wide.png new file mode 100644 index 0000000..c0c1856 Binary files /dev/null and b/src/main/resources/templates/html/kakao_login_large_wide.png differ diff --git a/src/main/resources/templates/html/token.html b/src/main/resources/templates/html/token.html new file mode 100644 index 0000000..10b3429 --- /dev/null +++ b/src/main/resources/templates/html/token.html @@ -0,0 +1,10 @@ + + + + + Access Token + + +

ERROR...

+ + \ No newline at end of file