Skip to content
Merged
134 changes: 119 additions & 15 deletions src/main/java/Devroup/hidaddy/controller/UserController.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package Devroup.hidaddy.controller;

import Devroup.hidaddy.dto.user.*;
import Devroup.hidaddy.entity.Baby;
import Devroup.hidaddy.entity.User;
import Devroup.hidaddy.security.UserDetailsImpl;
import Devroup.hidaddy.service.BabyService;
import Devroup.hidaddy.service.UserService;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -14,16 +18,20 @@
import org.springframework.web.bind.annotation.*;
import io.swagger.v3.oas.annotations.tags.Tag;

import java.time.LocalDate;
import java.util.List;

@Tag(
name = "User",
description = "ํšŒ์› ์ •๋ณด, ์‚ฌ์šฉ์ž, ์•„๊ธฐ ๊ด€๋ จ API"
description = "ํšŒ์› ์ •๋ณด, ์•„๊ธฐ ๋“ฑ๋ก ๋ฐ ์„ ํƒ ๋“ฑ ์‚ฌ์šฉ์ž ๊ด€๋ จ API"
)
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/user")
public class UserController {

private final UserService userService;
private final BabyService babyService;

@GetMapping("")
@Operation(
Expand Down Expand Up @@ -68,6 +76,7 @@ public ResponseEntity<?> changeName(
return ResponseEntity.ok("์œ ์ € ์ด๋ฆ„ ๋ณ€๊ฒฝ ์™„๋ฃŒ");
}

// ์•„๊ธฐ ๋“ฑ๋ก (ํŠœํ† ๋ฆฌ์–ผ)
@Operation(summary = "์•„๊ธฐ ์ •๋ณด ๋“ฑ๋ก (ํŠœํ† ๋ฆฌ์–ผ)",
description = "๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ด๋ฆ„๊ณผ ์•„๊ธฐ ์ •๋ณด๋ฅผ ๋“ฑ๋กํ•˜๊ณ , ์„ ํƒ๋œ ์•„๊ธฐ ID๋„ ์ž๋™์œผ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.")
@ApiResponses({
Expand All @@ -87,42 +96,117 @@ public ResponseEntity<?> registerBaby(
return ResponseEntity.ok("์•„๊ธฐ ์ •๋ณด ๋“ฑ๋ก ์™„๋ฃŒ");
}

// ์ „์ฒด ์•„๊ธฐ ๋ชฉ๋ก ์กฐํšŒ
@Operation(summary = "์ „์ฒด ์•„๊ธฐ ๋ชฉ๋ก ์กฐํšŒ",
description = "๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž์˜ ์ „์ฒด ์•„๊ธฐ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "์•„๊ธฐ ๋ชฉ๋ก ์กฐํšŒ ์„ฑ๊ณต"),
@ApiResponse(responseCode = "401", description = "์ธ์ฆ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž (๋กœ๊ทธ์ธ ํ•„์š”)")
})
@GetMapping("/baby")
@Operation(
summary = "์„ ํƒ๋œ ์•„๊ธฐ ์ •๋ณด ์กฐํšŒ",
description = "๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•œ ์•„๊ธฐ์˜ ์ƒ์„ธ ์ •๋ณด(์ด๋ฆ„, D-day, ํ”„๋กœํ•„ ์ด๋ฏธ์ง€, ๋ฉ”์‹œ์ง€)๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. "
+ "Authorization ํ—ค๋”์— ์œ ํšจํ•œ Access Token์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค."
)
public ResponseEntity<List<BabyResponse>> getAllBabies(
@AuthenticationPrincipal UserDetailsImpl userDetails) {

if (userDetails == null) {
return ResponseEntity.status(401).build();
}

List<BabyResponse> babies = babyService.getBabies(userDetails.getUser());
return ResponseEntity.ok(babies);
}

// ํŠน์ • ์•„๊ธฐ ์ •๋ณด ์กฐํšŒ
@Operation(summary = "ํŠน์ • ์•„๊ธฐ ์ •๋ณด ์กฐํšŒ",
description = "์ง€์ •๋œ ์•„๊ธฐ ID์— ํ•ด๋‹นํ•˜๋Š” ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "์•„๊ธฐ ์ •๋ณด ์กฐํšŒ ์„ฑ๊ณต"),
@ApiResponse(responseCode = "401", description = "์ธ์ฆ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž (๋กœ๊ทธ์ธ ํ•„์š”)"),
@ApiResponse(responseCode = "403", description = "๊ถŒํ•œ ์—†์Œ"),
@ApiResponse(responseCode = "404", description = "ํ•ด๋‹น ์•„๊ธฐ ์—†์Œ")
})
@GetMapping("/baby/{babyId}")
public ResponseEntity<BabyResponse> getBaby(
@PathVariable Long babyId,
@AuthenticationPrincipal UserDetailsImpl userDetails) {

if (userDetails == null) return ResponseEntity.status(401).build();

BabyResponse baby = babyService.getBaby(userDetails.getUser(), babyId);
return ResponseEntity.ok(baby);
}

// ์•„๊ธฐ ์ˆ˜์ • (์ด๋ฆ„, ๋‚ ์งœ, ์ด๋ฏธ์ง€)
@PatchMapping(value = "/baby/{babyId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation(summary = "์•„๊ธฐ ์ •๋ณด ์ˆ˜์ • (JSON + ์ด๋ฏธ์ง€ Multipart)", description = "์ง€์ •๋œ ์•„๊ธฐ์˜ ์ด๋ฆ„, ์ถœ์‚ฐ ์˜ˆ์ •์ผ, ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ๋“ฑ์„ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "์ˆ˜์ • ์„ฑ๊ณต"),
@ApiResponse(responseCode = "400", description = "์ž˜๋ชป๋œ ์š”์ฒญ")
})
public ResponseEntity<BabyResponse> updateBaby(
@PathVariable Long babyId,
@RequestParam("name") String name,
@RequestParam("dueDate") @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate dueDate,
@RequestPart(value = "image", required = false) MultipartFile image,
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
if (userDetails == null) {
return ResponseEntity.status(401).build();
}

BabyUpdateRequest dto = new BabyUpdateRequest();
dto.setName(name);
dto.setDueDate(dueDate);

BabyResponse response = babyService.updateBaby(userDetails.getUser(), babyId, dto, image);
return ResponseEntity.ok(response);
}


// ์•„๊ธฐ ์‚ญ์ œ
@Operation(summary = "์•„๊ธฐ ์‚ญ์ œ", description = "์ง€์ •๋œ ์•„๊ธฐ ์ •๋ณด๋ฅผ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.")
@DeleteMapping("/baby/{babyId}")
public ResponseEntity<String> deleteBaby(@PathVariable Long babyId,
@AuthenticationPrincipal UserDetailsImpl userDetails) {
if (userDetails == null) return ResponseEntity.status(401).build();
babyService.deleteBaby(userDetails.getUser(), babyId);
return ResponseEntity.ok("์•„๊ธฐ ์‚ญ์ œ ์™„๋ฃŒ");
}

@Operation(summary = "์•„๊ธฐ ์ •๋ณด ๋“ฑ๋ก", description = "ํƒœ๋ช…๊ณผ ์ถœ์‚ฐ ์˜ˆ์ •์ผ๋งŒ ์ž…๋ ฅํ•˜์—ฌ ์•„๊ธฐ๋ฅผ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "์„ ํƒ๋œ ์•„๊ธฐ ์ •๋ณด ์กฐํšŒ ์„ฑ๊ณต"),
@ApiResponse(responseCode = "200", description = "์•„๊ธฐ ์ •๋ณด ๋“ฑ๋ก ์„ฑ๊ณต"),
@ApiResponse(responseCode = "401", description = "์ธ์ฆ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž (๋กœ๊ทธ์ธ ํ•„์š”)"),
@ApiResponse(responseCode = "400", description = "์„ ํƒ๋œ ์•„๊ธฐ๊ฐ€ ์—†๊ฑฐ๋‚˜ ํ•ด๋‹น ์•„๊ธฐ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ")
@ApiResponse(responseCode = "400", description = "์ž˜๋ชป๋œ ์š”์ฒญ")
})
public ResponseEntity<SelectedBabyResponse> getSelectedBabyInfo(@AuthenticationPrincipal UserDetailsImpl userDetails) {
@PostMapping("/baby/basic")
public ResponseEntity<BabyResponse> registerBabySimple(
@RequestBody BabyBasicRegisterRequest request,
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
if (userDetails == null) {
return ResponseEntity.status(401).build();
}

SelectedBabyResponse selectedBabyInfo = userService.getSelectedBabyInfo(userDetails.getUser());
return ResponseEntity.ok(selectedBabyInfo);
BabyResponse response = babyService.registerBabyBasic(request, userDetails.getUser());
return ResponseEntity.ok(response);
}

@PatchMapping("/selected-baby/{babyId}")
@Operation(summary = "์„ ํƒ๋œ ์•„๊ธฐ ๋ณ€๊ฒฝ",
description = "๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ๋“ฑ๋กํ•œ ์•„๊ธฐ ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒ๋œ ์•„๊ธฐ๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "์„ ํƒ๋œ ์•„๊ธฐ ๋ณ€๊ฒฝ ์„ฑ๊ณต"),
@ApiResponse(responseCode = "401", description = "์ธ์ฆ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž (๋กœ๊ทธ์ธ ํ•„์š”)"),
@ApiResponse(responseCode = "404", description = "ํ•ด๋‹น ์•„๊ธฐ ์ •๋ณด๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ")
})
@PatchMapping("/select-baby/{babyId}")
public ResponseEntity<?> selectBaby(@PathVariable Long babyId,
@AuthenticationPrincipal UserDetailsImpl userDetails) {
if (userDetails == null) {
return ResponseEntity.status(401).body("์ธ์ฆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.");
}

userService.changeSelectedBaby(userDetails.getUser(), babyId);
return ResponseEntity.ok("์„ ํƒ๋œ ์•„๊ธฐ ๋ณ€๊ฒฝ ์™„๋ฃŒ");
BabyResponse response = userService.changeSelectedBaby(userDetails.getUser(), babyId);
return ResponseEntity.ok(response);
}

@PatchMapping(value = "/profile-image", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
Expand All @@ -139,12 +223,32 @@ public ResponseEntity<?> selectBaby(@PathVariable Long babyId,
public ResponseEntity<String> uploadProfileImage(
@RequestPart(value = "image", required = true) MultipartFile image,
@AuthenticationPrincipal UserDetailsImpl userDetails) {

if (userDetails == null) {
return ResponseEntity.status(401).body("์ธ์ฆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.");
}

String imageUrl = userService.uploadProfileImage(userDetails.getUser(), image);
return ResponseEntity.ok(imageUrl);
}

@Operation(
summary = "์‚ฌ์šฉ์ž ๋ฐ ํŒŒํŠธ๋„ˆ ์ „ํ™”๋ฒˆํ˜ธ ๋“ฑ๋ก/์ˆ˜์ •",
description = "๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž์˜ `phone`๊ณผ `partnerphonee`์„ ๋“ฑ๋กํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค. "
+ "์š”์ฒญ ์‹œ JSON ๋ฐ”๋””๋กœ `phone`, `partnerphone` ๊ฐ’์„ ์ „๋‹ฌํ•˜๋ฉฐ, "
+ "๋‘˜ ์ค‘ ํ•˜๋‚˜๋งŒ ๋ณด๋‚ด๋„ ๋˜๊ณ , ๋ณด๋‚ด์ง€ ์•Š์€ ํ•„๋“œ๋Š” ๊ธฐ์กด ๊ฐ’์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. "
+ "Authorization ํ—ค๋”์— ์œ ํšจํ•œ Access Token์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค."
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "์ „ํ™”๋ฒˆํ˜ธ ๋“ฑ๋ก/์ˆ˜์ • ์„ฑ๊ณต"),
@ApiResponse(responseCode = "400", description = "์ž˜๋ชป๋œ ์š”์ฒญ (์ „ํ™”๋ฒˆํ˜ธ ํ˜•์‹ ์˜ค๋ฅ˜ ๋“ฑ)"),
@ApiResponse(responseCode = "401", description = "์ธ์ฆ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž (๋กœ๊ทธ์ธ ํ•„์š”)"),
@ApiResponse(responseCode = "404", description = "ํ•ด๋‹น ์œ ์ €๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ")
})
@PatchMapping("/phone")
public ResponseEntity<String> patchPhoneNumbers(@AuthenticationPrincipal UserDetailsImpl userDetails,
@RequestBody PhoneUpdateRequest dto) {
userService.updatePhoneNumbers(userDetails.getUser().getId(), dto);
return ResponseEntity.ok("์ „ํ™”๋ฒˆํ˜ธ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package Devroup.hidaddy.dto.user;

import lombok.Getter;

import java.time.LocalDate;
import java.time.LocalDateTime;

@Getter
public class BabyBasicRegisterRequest {

private String babyName; // ํƒœ๋ช…
private String dueDate; // ์˜ˆ: "2025-12-25" (yyyy-MM-dd ํ˜•์‹)

public LocalDateTime getParsedDueDate() {
if (dueDate == null || dueDate.isBlank()) {
throw new IllegalArgumentException("์ถœ์‚ฐ ์˜ˆ์ •์ผ์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.");
}
return LocalDate.parse(dueDate).atStartOfDay();
}
}
25 changes: 25 additions & 0 deletions src/main/java/Devroup/hidaddy/dto/user/BabyResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package Devroup.hidaddy.dto.user;

import Devroup.hidaddy.entity.Baby;
import lombok.Getter;
import lombok.NoArgsConstructor;
import com.fasterxml.jackson.annotation.JsonFormat;

import java.time.LocalDate;

@Getter
@NoArgsConstructor
public class BabyResponse {
private Long id;
private String name;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") // ๋‚ ์งœ ํฌ๋งท ์ง€์ •
private LocalDate dueDate;
private String profileImage;

public BabyResponse(Baby baby) {
this.id = baby.getId();
this.name = baby.getName();
this.dueDate = baby.getDueDate().toLocalDate();
this.profileImage = baby.getBabyImageUrl(); // ์žˆ์œผ๋ฉด ๊ฐ€์ ธ์˜ค๊ธฐ
}
}
15 changes: 15 additions & 0 deletions src/main/java/Devroup/hidaddy/dto/user/BabyUpdateRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package Devroup.hidaddy.dto.user;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;

import java.time.LocalDate;

@Getter
@Setter
public class BabyUpdateRequest {
private String name;
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate dueDate;
}
11 changes: 11 additions & 0 deletions src/main/java/Devroup/hidaddy/dto/user/PhoneUpdateRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package Devroup.hidaddy.dto.user;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class PhoneUpdateRequest {
private String Phone;
private String partnerPhone;
}
6 changes: 2 additions & 4 deletions src/main/java/Devroup/hidaddy/entity/Baby.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package Devroup.hidaddy.entity;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Builder;
import lombok.AllArgsConstructor;
import lombok.*;
import jakarta.persistence.*;
import java.time.LocalDateTime;

@Entity // JPA๊ฐ€ ์ด ํด๋ž˜์Šค๋ฅผ ์—”ํ‹ฐํ‹ฐ๋กœ ์ธ์‹ํ•˜๋„๋ก ์ง€์ •ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜
@Table(name = "baby") // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์‚ฌ์šฉ๋  ํ…Œ์ด๋ธ” ์ด๋ฆ„์„ 'baby'๋กœ ์ง€์ •
@Getter // Lombok: ๋ชจ๋“  ํ•„๋“œ์— ๋Œ€ํ•œ getter ๋ฉ”์†Œ๋“œ๋ฅผ ์ž๋™ ์ƒ์„ฑ
@Setter
@NoArgsConstructor // Lombok: ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์—†๋Š” ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ์ž๋™ ์ƒ์„ฑ
@AllArgsConstructor // Lombok: ๋ชจ๋“  ํ•„๋“œ๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๋Š” ์ƒ์„ฑ์ž๋ฅผ ์ž๋™ ์ƒ์„ฑ
@Builder // Lombok: ๋นŒ๋” ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›
Expand Down
Loading