Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 회원가입시 보드 임의 생성 추가, 카테고리 임의 생성 Service 제거 #64

Open
wants to merge 24 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b3341c7
feat: springboot security oauth2 google authorization 설정 추가, JWT/Cook…
gwanhyeon Apr 16, 2021
6516d03
refactor: 전체적인 리팩토링
kouz95 Apr 16, 2021
5b0b6db
Merge branch 'feature/6' of https://github.com/DDD-5/null-moodof-back…
gwanhyeon Apr 16, 2021
89fbe8c
Merge branch 'develop' of https://github.com/DDD-5/null-moodof-backen…
gwanhyeon Apr 24, 2021
4cc6d3d
Merge branch 'develop' of https://github.com/DDD-5/null-moodof-backen…
gwanhyeon Apr 29, 2021
091335f
Merge branch 'develop' of https://github.com/DDD-5/null-moodof-backen…
gwanhyeon May 1, 2021
4feadb5
Merge branch 'develop' of https://github.com/DDD-5/null-moodof-backen…
gwanhyeon May 6, 2021
1f25555
Merge branch 'develop' of https://github.com/DDD-5/null-moodof-backen…
gwanhyeon May 19, 2021
78fdaa8
feat: 상세 조회 태그 조건 추가 및 조회시 태그 없음 검색 추가
kouz95 May 22, 2021
72ce070
feat: BoardPhoto 순서 추가
kouz95 May 25, 2021
28f23de
feat: BoardPhoto 전체 조회 구현
kouz95 May 25, 2021
55d3be7
feat: storagePhoto 조회 사진 개수 추가
kouz95 May 25, 2021
2044485
Merge branch 'develop' of https://github.com/DDD-5/null-moodof-backen…
gwanhyeon May 27, 2021
f2862a6
fix: code conflict
gwanhyeon May 27, 2021
41344c8
feat: 공유 카테고리 URL생성, 공유 카테고리, 보드 리스트조회
gwanhyeon May 28, 2021
03a0c75
feat: 공유보드 조회, 공유 보관함 사진 상세조회 , 공유 URL 생성 API
gwanhyeon May 29, 2021
0495449
fix: 태그생성시 TagAttachment 생성시 TDD 공유 로직 수정
gwanhyeon May 29, 2021
d81572f
chore: profile dev ignore 추가
gwanhyeon May 29, 2021
6e53f61
Merge branch 'develop' of https://github.com/DDD-5/null-moodof-backen…
gwanhyeon May 29, 2021
ae231f1
fix: 불필요 코드 정리 및 삭제
gwanhyeon May 29, 2021
d45907a
fix: git ignore 불필요 코드 참조 삭제
gwanhyeon May 29, 2021
8f228f9
feat: 공유 URI AES256 -> SHA256 암호화 변경, 코드리뷰 사항 반영
gwanhyeon May 31, 2021
6bb52b8
Merge branch 'develop' of https://github.com/DDD-5/null-moodof-backen…
gwanhyeon May 31, 2021
3ed4cec
feat: 회원가입시 보드 임의 생성 추가, 카테고리 임의 생성 Service 제거
gwanhyeon May 31, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ out/
### VS Code ###
.vscode/

application-security.yml
application-security.yml
/src/main/resources/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.firewall.StrictHttpFirewall;

@RequiredArgsConstructor
@Configuration
Expand Down Expand Up @@ -49,6 +52,19 @@ public void configure(AuthenticationManagerBuilder authenticationManagerBuilder)
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder());
}
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
web.httpFirewall(allowUrlEncodedSlashHttpFirewall());
}

@Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
firewall.setAllowUrlEncodedSlash(true);
return firewall;
}


@Bean
public PasswordEncoder passwordEncoder() {
Expand Down Expand Up @@ -93,7 +109,8 @@ protected void configure(HttpSecurity http) throws Exception {
"/webjars/**",
"/v2/**",
"/swagger-resources/**",
"/api/public/**"
"/api/public/**",
"/api/public/**/**"
).permitAll()
.anyRequest()
.authenticated()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public List<CategoryDTO.CategoryWithBoardResponse> findAllByUserId(Long userId)
board.userId,
board.name,
board.categoryId,
board.sharedKey,
board.createdDate,
board.lastModifiedDate))
.from(board)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ private List<BoardDTO.BoardResponse> findBoards(Long storagePhotoId) {
board.userId,
board.name,
board.categoryId,
board.sharedKey,
board.createdDate,
board.lastModifiedDate
))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.ddd.moodof.adapter.infrastructure.security.encrypt;

import org.springframework.stereotype.Component;
import java.security.MessageDigest;

@Component
public class EncryptUtil {

public static String encryptSHA256(String msg){
try{
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(msg.getBytes("UTF-8"));
StringBuffer hexString = new StringBuffer();

for (byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}

return hexString.toString();
} catch(Exception ex){
throw new RuntimeException(ex);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import com.ddd.moodof.adapter.infrastructure.security.exception.OAuth2AuthenticationProcessingException;
import com.ddd.moodof.adapter.infrastructure.security.oauth2.user.OAuth2UserInfo;
import com.ddd.moodof.adapter.infrastructure.security.oauth2.user.OAuth2UserInfoFactory;
import com.ddd.moodof.domain.model.category.CategoryInitializer;
import com.ddd.moodof.application.BoardService;
import com.ddd.moodof.application.CategoryService;
import com.ddd.moodof.application.dto.BoardDTO;
import com.ddd.moodof.application.dto.CategoryDTO;
import com.ddd.moodof.domain.model.user.AuthProvider;
import com.ddd.moodof.domain.model.user.User;
import com.ddd.moodof.domain.model.user.UserRepository;
Expand All @@ -24,8 +27,11 @@
@Service
public class CustomOAuth2UserService extends DefaultOAuth2UserService {

public static final String CATEGORY_SUB_TITLE = "님의 카테고리";
public static final String BOARD_SUB_TITLE = "님의 보드";
private final UserRepository userRepository;
private final CategoryInitializer categoryInitializer;
private final BoardService boardService;
private final CategoryService categoryService;

@Override
@Transactional
Expand Down Expand Up @@ -68,7 +74,13 @@ private OAuth2User processOAuth2User(OAuth2UserRequest oAuth2UserRequest, OAuth2
private User registerNewUser(OAuth2UserRequest oAuth2UserRequest, OAuth2UserInfo oAuth2UserInfo) {
User user = new User(null, oAuth2UserInfo.getEmail(), null, oAuth2UserInfo.getName(), oAuth2UserInfo.getImageUrl(), null, null, AuthProvider.valueOf(oAuth2UserRequest.getClientRegistration().getRegistrationId()), oAuth2UserInfo.getId());
User saved = userRepository.save(user);
categoryInitializer.create(saved.getId(), saved.getNickname());

CategoryDTO.CreateCategoryRequest category = new CategoryDTO.CreateCategoryRequest(user.getNickname()+ CATEGORY_SUB_TITLE,0L);
CategoryDTO.CategoryResponse responseCategory = categoryService.create(category, user.getId());

BoardDTO.CreateBoard board = new BoardDTO.CreateBoard(0L, responseCategory.getId(), user.getNickname()+ BOARD_SUB_TITLE);
boardService.create(user.getId(), board);

return saved;
}
private User updateExistingUser(User existingUser, OAuth2UserInfo oAuth2UserInfo) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.servlet.http.HttpServletRequest;
import java.net.URI;

@RequiredArgsConstructor
Expand Down Expand Up @@ -45,4 +46,9 @@ public ResponseEntity<BoardDTO.BoardResponse> delete(@LoginUserId Long userId, @
boardService.delete(userId, id);
return ResponseEntity.noContent().build();
}
@GetMapping("/{id}")
public ResponseEntity<BoardDTO.BoardSharedResponse> getSharedKey(@LoginUserId Long userId, @PathVariable Long id, HttpServletRequest httpServletRequest){
BoardDTO.BoardSharedResponse response = boardService.getSharedURI(userId, id, httpServletRequest);
return ResponseEntity.ok(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.ddd.moodof.adapter.presentation;

import com.ddd.moodof.adapter.presentation.api.PublicBoardAPI;
import com.ddd.moodof.application.BoardPhotoService;
import com.ddd.moodof.application.StoragePhotoService;
import com.ddd.moodof.application.dto.BoardPhotoDTO;
import com.ddd.moodof.application.dto.StoragePhotoDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RequiredArgsConstructor
@RequestMapping(PublicBoardController.API_PUBLIC_BOARDS)
@RestController
public class PublicBoardController implements PublicBoardAPI {

public static final String API_PUBLIC_BOARDS = "/api/public/boards";

private final StoragePhotoService storagePhotoService;

private final BoardPhotoService boardPhotoService;

@Override
@GetMapping("/{sharedKey}")
public ResponseEntity<List<BoardPhotoDTO.BoardPhotoResponse>> findAllByBoard(@PathVariable String sharedKey) {
List<BoardPhotoDTO.BoardPhotoResponse> responses = boardPhotoService.findAllBySharedKey(sharedKey);
return ResponseEntity.ok(responses);
}

@Override
@GetMapping("/{sharedKey}/detail/{id}")
public ResponseEntity<StoragePhotoDTO.StoragePhotoDetailResponse> getSharedBoardDetail(
@PathVariable String sharedKey,
@PathVariable Long id,
@RequestParam(required = false, value = "tagIds") List<Long> tagIds){
StoragePhotoDTO.StoragePhotoDetailResponse response = storagePhotoService.findSharedBoardDetail(sharedKey, id, tagIds);
return ResponseEntity.ok(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.ddd.moodof.adapter.presentation;

import java.lang.annotation.*;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SharedBoardId {
String value() default "";
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

import com.ddd.moodof.adapter.presentation.LoginUserId;
import com.ddd.moodof.application.dto.BoardDTO;
import com.ddd.moodof.application.dto.SharedDTO;
import io.swagger.annotations.ApiImplicitParam;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;

public interface BoardAPI {
@ApiImplicitParam(name = "Authorization", value = "Access Token", required = true, paramType = "header", dataTypeClass = String.class, example = "Bearer access_token")
@PostMapping
Expand All @@ -23,4 +26,5 @@ public interface BoardAPI {
@ApiImplicitParam(name = "Authorization", value = "Access Token", required = true, paramType = "header", dataTypeClass = String.class, example = "Bearer access_token")
@DeleteMapping("/{id}")
ResponseEntity<BoardDTO.BoardResponse> delete(@ApiIgnore @LoginUserId Long userId, @PathVariable Long id);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.ddd.moodof.adapter.presentation.api;
import com.ddd.moodof.application.dto.BoardPhotoDTO;
import com.ddd.moodof.application.dto.StoragePhotoDTO;
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 java.util.List;

public interface PublicBoardAPI {
@GetMapping("/{sharedKey}")
ResponseEntity<List<BoardPhotoDTO.BoardPhotoResponse>> findAllByBoard(@PathVariable String sharedKey);

@GetMapping("/{sharedKey}/detail/{id}")
ResponseEntity<StoragePhotoDTO.StoragePhotoDetailResponse> getSharedBoardDetail(@PathVariable String sharedKey, @PathVariable Long id, @RequestParam(required = false, value = "tagIds") List<Long> tagIds);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.ddd.moodof.application.dto.BoardPhotoDTO;
import com.ddd.moodof.application.verifier.BoardPhotoVerifier;
import com.ddd.moodof.domain.model.board.Board;
import com.ddd.moodof.domain.model.board.BoardRepository;
import com.ddd.moodof.domain.model.board.photo.BoardPhoto;
import com.ddd.moodof.domain.model.board.photo.BoardPhotoRepository;
import lombok.RequiredArgsConstructor;
Expand All @@ -19,6 +21,7 @@ public class BoardPhotoService {

private final BoardPhotoRepository boardPhotoRepository;
private final BoardPhotoVerifier boardPhotoVerifier;
private final BoardRepository boardRepository;

public List<BoardPhotoDTO.BoardPhotoResponse> addPhotos(Long userId, BoardPhotoDTO.AddBoardPhoto request) {
// TODO: 2021/05/25 StoragePhoto 삭제 대응
Expand Down Expand Up @@ -61,4 +64,10 @@ public List<BoardPhotoDTO.BoardPhotoResponse> findAllByBoardId(Long boardId, Lon
List<BoardPhoto> boardPhotos = boardPhotoRepository.findAllByBoardIdAndUserId(boardId, userId);
return BoardPhotoDTO.BoardPhotoResponse.listFrom(boardPhotos);
}
public List<BoardPhotoDTO.BoardPhotoResponse> findAllBySharedKey(String sharedKey) {
Board board = boardRepository.findBySharedKey(sharedKey)
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 sharedKey =" + sharedKey));
List<BoardPhoto> boardPhotos = boardPhotoRepository.findAllByBoardIdAndUserId(board.getId(), board.getUserId());
return BoardPhotoDTO.BoardPhotoResponse.listFrom(boardPhotos);
}
}
59 changes: 57 additions & 2 deletions src/main/java/com/ddd/moodof/application/BoardService.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.ddd.moodof.application;

import com.ddd.moodof.adapter.infrastructure.security.encrypt.EncryptUtil;
import com.ddd.moodof.application.dto.BoardDTO;
import com.ddd.moodof.application.verifier.BoardVerifier;
import com.ddd.moodof.domain.model.board.Board;
import com.ddd.moodof.domain.model.board.BoardRepository;
import com.ddd.moodof.domain.model.board.BoardSequenceUpdater;
import lombok.RequiredArgsConstructor;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.stereotype.Service;

import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;

@RequiredArgsConstructor
Expand All @@ -16,9 +20,14 @@ public class BoardService {
public static final int MAX_BOARD_IN_CATEGORY_COUNT = 10;

private final BoardRepository boardRepository;

private final BoardVerifier boardVerifier;

private final BoardSequenceUpdater boardSequenceUpdater;

public static final String LOCALHOST = "localhost";


@Transactional
public BoardDTO.BoardResponse create(Long userId, BoardDTO.CreateBoard request) {
if (boardRepository.countByCategoryId(request.getCategoryId()) >= MAX_BOARD_IN_CATEGORY_COUNT) {
Expand All @@ -27,13 +36,19 @@ public BoardDTO.BoardResponse create(Long userId, BoardDTO.CreateBoard request)

Board board = boardVerifier.toEntity(request.getPreviousBoardId(), request.getCategoryId(), request.getName(), userId);
Board saved = boardRepository.save(board);

encryptByBoardId(userId, saved);
boardRepository.findByUserIdAndPreviousBoardIdAndIdNot(userId, request.getPreviousBoardId(), saved.getId())
.ifPresent(it -> it.changePreviousBoardId(saved.getId(), userId));

return BoardDTO.BoardResponse.from(saved);
}

public void encryptByBoardId(Long userId, Board saved) {
String sharedKey = EncryptUtil.encryptSHA256(Long.toString(saved.getId()));
saved.updateSharedkey(sharedKey, userId);
boardRepository.save(saved);
}

public BoardDTO.BoardResponse changeName(Long userId, Long id, BoardDTO.ChangeBoardName request) {
Board board = boardRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 보드입니다. id = " + id));
Expand All @@ -58,4 +73,44 @@ public void delete(Long userId, Long id) {
}
boardRepository.deleteById(id);
}

public BoardDTO.BoardSharedResponse getSharedURI(Long userId, Long id, HttpServletRequest httpServletRequest) {
Board board = boardRepository.findByIdAndUserId(id, userId)
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 Board, id = " + id));
String requestURI = getUrl(httpServletRequest);
String sharedKey = board.getSharedKey();
String sharedURI = generatedURI(requestURI, sharedKey);
return BoardDTO.BoardSharedResponse.from(id,sharedURI, sharedKey);
}

public String getUrl(HttpServletRequest request) {
ServletServerHttpRequest httpRequest = new ServletServerHttpRequest(request);
UriComponents uriComponents = UriComponentsBuilder.fromHttpRequest(httpRequest).build();

String scheme = uriComponents.getScheme();
String serverName = request.getServerName();
int serverPort = request.getServerPort();
String contextPath = request.getRequestURI();
StringBuilder url = new StringBuilder();

url.append(scheme).append("://");
url.append(serverName);

if (serverName.equals(LOCALHOST)) {
url.append(":").append("8080");
}else {
if (serverPort != 80 && serverPort != 443) {
url.append(":").append(serverPort);
}
}
url.append(contextPath);
return url.toString();
}

private String generatedURI(String requestURL, String sharedKey) {
return UriComponentsBuilder.fromUriString(requestURL)
.path(sharedKey)
.build()
.toUriString();
}
}
Loading