Skip to content

Commit

Permalink
Merge pull request #69 from backendoori/feat-post-put-delete
Browse files Browse the repository at this point in the history
🚀 게시글 수정/삭제 기능 구현
  • Loading branch information
Sehee-Lee-01 authored Jan 17, 2024
2 parents 31ffa64 + 14d09b8 commit e9d8d53
Show file tree
Hide file tree
Showing 25 changed files with 1,107 additions and 191 deletions.
38 changes: 17 additions & 21 deletions mysql/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,19 @@ CREATE TABLE users
certified TINYINT(1) NOT NULL,
created_at DATETIME(6) NULL,
updated_at DATETIME(6) NULL,
CONSTRAINT users_pk
PRIMARY KEY (id),
CONSTRAINT users_email_index
UNIQUE (email)

CONSTRAINT users_pk PRIMARY KEY (id),
CONSTRAINT users_email_index UNIQUE (email)
);

CREATE TABLE avatar_items
(
id BIGINT AUTO_INCREMENT,
image VARCHAR(500) NOT NULL,
type VARCHAR(30) NOT NULL,
sex VARCHAR(10) NOT NULL,
CONSTRAINT avatar_items_pk
PRIMARY KEY (id)
id BIGINT AUTO_INCREMENT,
image_url VARCHAR(500) NOT NULL,
type VARCHAR(30) NOT NULL,
sex VARCHAR(10) NOT NULL,

CONSTRAINT avatar_items_pk PRIMARY KEY (id)
);

CREATE TABLE posts
Expand All @@ -34,16 +33,15 @@ CREATE TABLE posts
user_id BIGINT NOT NULL,
title VARCHAR(30) NOT NULL,
content VARCHAR(255) NOT NULL,
image VARCHAR(500) NULL,
image_url VARCHAR(500) NULL,
created_at DATETIME(6) NULL,
updated_at DATETIME(6) NULL,
like_cnt INTEGER NULL,
min_temperature DOUBLE NOT NULL,
max_temperature DOUBLE NOT NULL,
CONSTRAINT posts_pk
PRIMARY KEY (id),
FOREIGN KEY (user_id)
REFERENCES users (id)

CONSTRAINT posts_pk PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id)
);

CREATE TABLE likes
Expand All @@ -54,10 +52,8 @@ CREATE TABLE likes
is_like TINYINT NOT NULL,
created_at DATETIME(6) NULL,
updated_at DATETIME(6) NULL,
CONSTRAINT posts_pk
PRIMARY KEY (id),
FOREIGN KEY (user_id)
REFERENCES users (id),
FOREIGN KEY (post_id)
REFERENCES posts (id)

CONSTRAINT posts_pk PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id),
FOREIGN KEY (post_id) REFERENCES posts (id)
);
10 changes: 5 additions & 5 deletions src/main/java/com/backendoori/ootw/avatar/domain/AvatarItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ public class AvatarItem {
@Column(name = "id")
private Long id;

@Column(name = "image", nullable = false)
private String image;
@Column(name = "image_url", nullable = false)
private String imageUrl;

@Column(name = "type", nullable = false, columnDefinition = "varchar(30)")
@Enumerated(EnumType.STRING)
Expand All @@ -39,12 +39,12 @@ public class AvatarItem {
@Enumerated(EnumType.STRING)
private Sex sex;

private AvatarItem(String image, String type, String sex) {
validateImage(image);
private AvatarItem(String imageUrl, String type, String sex) {
validateImage(imageUrl);
validateItemType(type);
validateSex(sex);

this.image = image;
this.imageUrl = imageUrl;
this.itemType = ItemType.valueOf(type);
this.sex = Sex.valueOf(sex);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public static AvatarItemResponse from(AvatarItem avatarItem) {
avatarItem.getId(),
avatarItem.getItemType().name(),
avatarItem.getSex().name(),
avatarItem.getImage());
avatarItem.getImageUrl());
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.backendoori.ootw.config;

import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
Expand All @@ -10,13 +13,19 @@ public class HttpRequestsConfigurer
implements Customizer<AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry> {

private static final String AUTH_RESOURCE = "/api/v1/auth/**";
private static final String POST_RESOURCE = "/api/v1/posts/**";
private static final String AVATAR_RESOURCE = "/api/v1/avatar-items/**";

@Override
public void customize(
AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry authorizeRequests) {
authorizeRequests
.requestMatchers(AUTH_RESOURCE)
.permitAll()
.requestMatchers(antMatcher(HttpMethod.GET, POST_RESOURCE))
.permitAll()
.requestMatchers(antMatcher(HttpMethod.GET, AVATAR_RESOURCE))
.permitAll()
.anyRequest()
.authenticated();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,23 @@
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.HandlerMethodValidationException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;

@Slf4j
@RestControllerAdvice
public class GlobalControllerAdvice {

public static final String DEFAULT_MESSAGE = "유효하지 않은 요청 입니다.";

@ExceptionHandler({MissingServletRequestPartException.class, MultipartException.class})
public ResponseEntity<ErrorResponse> handleMissingServletRequestPartException(Exception e) {
ErrorResponse errorResponse = new ErrorResponse(e.getMessage());

return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(errorResponse);
}

@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ErrorResponse> handleIllegalArgumentException(IllegalArgumentException e) {
ErrorResponse errorResponse = new ErrorResponse(e.getMessage());
Expand Down Expand Up @@ -65,6 +75,14 @@ public ResponseEntity<ErrorResponse> handleAuthenticationException(Authenticatio
.body(errorResponse);
}

@ExceptionHandler(PermissionException.class)
public ResponseEntity<ErrorResponse> handlePermissionException(PermissionException e) {
ErrorResponse errorResponse = new ErrorResponse(e.getMessage());

return ResponseEntity.status(HttpStatus.FORBIDDEN)
.body(errorResponse);
}

@ExceptionHandler(NoSuchElementException.class)
public ResponseEntity<ErrorResponse> handleNoSuchElementException(NoSuchElementException e) {
ErrorResponse errorResponse = new ErrorResponse(e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.backendoori.ootw.exception;

public class PermissionException extends RuntimeException {

public static final String DEFAULT_MESSAGE = "요청에 대한 권한이 없습니다.";

public PermissionException() {
super(DEFAULT_MESSAGE);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@
import java.net.URI;
import java.util.List;
import com.backendoori.ootw.common.validation.Image;
import com.backendoori.ootw.post.dto.PostReadResponse;
import com.backendoori.ootw.post.dto.PostSaveRequest;
import com.backendoori.ootw.post.dto.PostSaveResponse;
import com.backendoori.ootw.post.dto.request.PostSaveRequest;
import com.backendoori.ootw.post.dto.request.PostUpdateRequest;
import com.backendoori.ootw.post.dto.response.PostReadResponse;
import com.backendoori.ootw.post.dto.response.PostSaveUpdateResponse;
import com.backendoori.ootw.post.service.PostService;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Positive;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -26,29 +30,51 @@ public class PostController {

private final PostService postService;

@GetMapping("/{postId}")
public ResponseEntity<PostReadResponse> readDetailByPostId(@PathVariable @Positive Long postId) {
return ResponseEntity.status(HttpStatus.OK)
.body(postService.getDetailByPostId(postId));
}

@GetMapping
public ResponseEntity<List<PostReadResponse>> readAll() {
return ResponseEntity.status(HttpStatus.OK)
.body(postService.getAll());
}

@DeleteMapping("/{postId}")
public ResponseEntity<Void> delete(@PathVariable @Positive Long postId) {
postService.delete(postId);

return ResponseEntity.status(HttpStatus.NO_CONTENT)
.build();
}

@PostMapping
public ResponseEntity<PostSaveResponse> save(
public ResponseEntity<PostSaveUpdateResponse> save(
@RequestPart(required = false) @Image(ignoreCase = true) MultipartFile postImg,
@RequestPart @Valid PostSaveRequest request) {
PostSaveResponse response = postService.save(request, postImg);

URI postUri = URI.create("/api/v1/posts/" + response.postId());
PostSaveUpdateResponse response = postService.save(request, postImg);

return ResponseEntity.status(HttpStatus.CREATED)
.location(postUri)
.location(getPostUri(response.postId()))
.body(response);
}

@GetMapping("/{postId}")
public ResponseEntity<PostReadResponse> readDetailByPostId(@PathVariable Long postId) {
return ResponseEntity.status(HttpStatus.OK)
.body(postService.getDetailByPostId(postId));
@PutMapping("/{postId}")
public ResponseEntity<PostSaveUpdateResponse> update(
@PathVariable @Positive Long postId,
@RequestPart(required = false) @Image(ignoreCase = true) MultipartFile postImg,
@RequestPart @Valid PostUpdateRequest request) {
PostSaveUpdateResponse response = postService.update(postId, postImg, request);

return ResponseEntity.status(HttpStatus.CREATED)
.location(getPostUri(response.postId()))
.body(response);
}

@GetMapping
public ResponseEntity<List<PostReadResponse>> readAll() {
return ResponseEntity.status(HttpStatus.OK)
.body(postService.getAll());
private URI getPostUri(Long postId) {
return URI.create("/api/v1/posts/" + postId);
}

}
23 changes: 19 additions & 4 deletions src/main/java/com/backendoori/ootw/post/domain/Post.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.backendoori.ootw.post.domain;

import static com.backendoori.ootw.post.validation.PostValidator.validateContent;
import static com.backendoori.ootw.post.validation.PostValidator.validatePostSaveRequest;
import static com.backendoori.ootw.post.validation.PostValidator.validateTemperatureArrange;
import static com.backendoori.ootw.post.validation.PostValidator.validateTitle;
import static com.backendoori.ootw.post.validation.PostValidator.validateUser;

import com.backendoori.ootw.common.BaseEntity;
import com.backendoori.ootw.post.dto.PostSaveRequest;
import com.backendoori.ootw.post.dto.request.PostSaveRequest;
import com.backendoori.ootw.user.domain.User;
import com.backendoori.ootw.weather.domain.TemperatureArrange;
import jakarta.persistence.Column;
Expand Down Expand Up @@ -43,8 +45,8 @@ public class Post extends BaseEntity {
@Column(name = "content", nullable = false)
private String content;

@Column(name = "image")
private String image;
@Column(name = "image_url")
private String imageUrl;

@Embedded
private TemperatureArrange temperatureArrange;
Expand All @@ -60,7 +62,7 @@ private Post(User user, PostSaveRequest request, String imgUrl, TemperatureArran
this.user = user;
this.title = request.title();
this.content = request.content();
this.image = imgUrl;
this.imageUrl = imgUrl;
this.temperatureArrange = temperatureArrange;
}

Expand All @@ -76,4 +78,17 @@ public void decreaseLikeCnt() {
this.likeCnt--;
}

public void updateTitle(String title) {
validateTitle(title);
this.title = title;
}

public void updateContent(String content) {
validateContent(content);
this.content = content;
}

public void updateImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.backendoori.ootw.post.dto;
package com.backendoori.ootw.post.dto.request;

import static com.backendoori.ootw.post.validation.Message.BLANK_POST_CONTENT;
import static com.backendoori.ootw.post.validation.Message.BLANK_POST_TITLE;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.backendoori.ootw.post.dto.request;

import static com.backendoori.ootw.post.validation.Message.BLANK_POST_CONTENT;
import static com.backendoori.ootw.post.validation.Message.BLANK_POST_TITLE;
import static com.backendoori.ootw.post.validation.Message.INVALID_POST_CONTENT;
import static com.backendoori.ootw.post.validation.Message.INVALID_POST_TITLE;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

public record PostUpdateRequest(
@NotBlank(message = BLANK_POST_TITLE)
@Size(max = 30, message = INVALID_POST_TITLE)
String title,

@NotBlank(message = BLANK_POST_CONTENT)
@Size(max = 500, message = INVALID_POST_CONTENT)
String content
) {

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.backendoori.ootw.post.dto;
package com.backendoori.ootw.post.dto.response;

import java.time.LocalDateTime;
import java.util.Objects;
import com.backendoori.ootw.post.domain.Post;
import com.backendoori.ootw.weather.dto.TemperatureArrangeDto;
import lombok.AllArgsConstructor;
Expand All @@ -28,7 +27,7 @@ public static PostReadResponse from(Post post) {
WriterDto.from(post.getUser()),
post.getTitle(),
post.getContent(),
post.getImage(),
post.getImageUrl(),
post.getCreatedAt(),
post.getUpdatedAt(),
TemperatureArrangeDto.from(post.getTemperatureArrange()),
Expand Down
Loading

0 comments on commit e9d8d53

Please sign in to comment.