From 59fc4b01169b02ec56e59b602655503c3781669e Mon Sep 17 00:00:00 2001 From: suno-boy Date: Wed, 18 Sep 2024 20:38:02 +0900 Subject: [PATCH 01/22] =?UTF-8?q?docs:=20=EC=B4=88=EA=B8=B0=20README.md=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 57 +++++++++++++++---------------------------------------- 1 file changed, 15 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index ac4296b..08bd96d 100644 --- a/README.md +++ b/README.md @@ -2,51 +2,24 @@ --- -# 그라운드 룰 +### 권순호가 맡은 구현 기능 목록 -- 추가 요망 +- **게스트(팀원) 관리 API** + - [ ] 프로젝트 링크 생성 + - [ ] 팀원이 수락하였을 때, 프로젝트에 팀원이 자동 추가되는 API + - [ ] 프로젝트 참여 코드 메일로 전달 + - [ ] 팀원 삭제 ---- +### 기능 구현 일정 -# 코드 컨벤션 +- 3week( 9/14(토) ~ 9/20(금) ) + - [ ] 프로젝트 링크 생성 + - [ ] 팀원 삭제 -- angular code conventions을 기반으로 커밋 메세지 작성 - - feat : 새로운 기능 추가 - - fix : 버그 수정 - - docs : 문서 변경 - - style : 코드 스타일 변경 (포매팅 수정, 세미콜론 추가 등) - - refactor : 코드 리팩토링 - - test : 테스트 코드 추가, 수정 - - chore : 빌드 프로세스, 도구 설정 변경 등 기타 작업 ---- +- 4week( 9/21(토) ~ 9/27(금) ) + - [ ] 프로젝트 참여 코드 메일로 전달 + -# 구현 기능 목록 - -- 인증(김동혁) - - 회원가입 - - 로그인 - - 코드로 참여 -- 프로젝트(김도헌) - - 프로젝트 리스트 조회 - - 프로젝트 기간 리스트 조회 - - 프로젝트 조회 - - 프로젝트 멤버 조회 - - 프로젝트 생성 - - 프로젝트 설정 수정 - - 프로젝트 삭제 -- 게스트(권순호) - - 게스트 생성 - - 게스트 수정 - - 게스트 삭제 - - 프로젝트 내 게스트 추가 - - 프로젝트 코드 메일로 전달 -- 태스크(조서영) - - 태스크 생성 - - 태스크 삭제 - - 태스크 수정 -- 이벤트 - - 독려 이메일 전달 - - 각 게스트별 진행도 조회 - - 태스크별 진행도 조회 -- ... \ No newline at end of file +- 5week( 9/28(토) ~ 10/4(금) ) + - [ ] 팀원이 수락하였을 때, 프로젝트에 팀원이 자동 추가되는 API \ No newline at end of file From f378597765d8f6032137f26258c9e824dd0639d7 Mon Sep 17 00:00:00 2001 From: Kim-DongHyuk <80240164+Kdonghs@users.noreply.github.com> Date: Thu, 19 Sep 2024 13:31:22 +0900 Subject: [PATCH 02/22] =?UTF-8?q?feat:=20oauth=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EB=B0=8F=20=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 +- .../com/example/team1_be/DTO/AuthDTO.java | 117 ++++++++++++++++++ .../example/team1_be/Team1BeApplication.java | 4 + .../team1_be/controller/AuthController.java | 25 ++++ .../team1_be/controller/TestController.java | 1 - .../example/team1_be/entity/UserEntity.java | 105 ++++++++++++++++ .../example/team1_be/entity/enums/Role.java | 22 ++++ .../example/team1_be/mapper/UserMapper.java | 12 ++ .../team1_be/repository/UserRepository.java | 12 ++ .../example/team1_be/service/AuthService.java | 71 +++++++++++ .../example/team1_be/util/auth/JwtToken.java | 91 ++++++++++++++ .../util/auth/OAuth2SuccessHandler.java | 36 ++++++ .../team1_be/util/auth/ParsingPram.java | 25 ++++ .../team1_be/util/auth/SecurityConfig.java | 72 +++++++++++ .../util/fiter/TokenAuthenticationFilter.java | 50 ++++++++ .../util/fiter/TokenExceptionFilter.java | 30 +++++ src/main/resources/application.properties | 6 +- 17 files changed, 678 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/example/team1_be/DTO/AuthDTO.java create mode 100644 src/main/java/com/example/team1_be/controller/AuthController.java create mode 100644 src/main/java/com/example/team1_be/entity/UserEntity.java create mode 100644 src/main/java/com/example/team1_be/entity/enums/Role.java create mode 100644 src/main/java/com/example/team1_be/mapper/UserMapper.java create mode 100644 src/main/java/com/example/team1_be/repository/UserRepository.java create mode 100644 src/main/java/com/example/team1_be/service/AuthService.java create mode 100644 src/main/java/com/example/team1_be/util/auth/JwtToken.java create mode 100644 src/main/java/com/example/team1_be/util/auth/OAuth2SuccessHandler.java create mode 100644 src/main/java/com/example/team1_be/util/auth/ParsingPram.java create mode 100644 src/main/java/com/example/team1_be/util/auth/SecurityConfig.java create mode 100644 src/main/java/com/example/team1_be/util/fiter/TokenAuthenticationFilter.java create mode 100644 src/main/java/com/example/team1_be/util/fiter/TokenExceptionFilter.java diff --git a/build.gradle b/build.gradle index 55aff05..71761ef 100644 --- a/build.gradle +++ b/build.gradle @@ -19,8 +19,8 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' -// implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' -// implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' + implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' // implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6' diff --git a/src/main/java/com/example/team1_be/DTO/AuthDTO.java b/src/main/java/com/example/team1_be/DTO/AuthDTO.java new file mode 100644 index 0000000..7da3baf --- /dev/null +++ b/src/main/java/com/example/team1_be/DTO/AuthDTO.java @@ -0,0 +1,117 @@ +package com.example.team1_be.DTO; + +import com.example.team1_be.entity.UserEntity; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.oauth2.core.user.OAuth2User; + +public class AuthDTO { + + // OAuth2에서 가져온 유저 정보 + public static class OAuthAttributes { + + private Map attributes; + private String nameAttributeKey; + private String name; + private String email; + private String picture; + + public OAuthAttributes(Map attributes, String nameAttributeKey, String name, + String email, + String picture) { + this.attributes = attributes; + this.nameAttributeKey = nameAttributeKey; + this.name = name; + this.email = email; + this.picture = picture; + } + + public Map getAttributes() { + return attributes; + } + + public String getNameAttributeKey() { + return nameAttributeKey; + } + + public String getName() { + return name; + } + + public String getEmail() { + return email; + } + + public String getPicture() { + return picture; + } + + public static OAuthAttributes ofGoogle(String usernameAttributeName, + Map attributes) { + return new OAuthAttributes(attributes, usernameAttributeName, + (String) attributes.get("name"), (String) attributes.get("email"), + (String) attributes.get("picture")); + } + } + + // OAuth2User 반환용 + public record PrincipalDetails( + UserEntity user, + Map attributes, + String attributeKey) implements OAuth2User, UserDetails { + + public UserEntity getUser() { + return user; + } + + @Override + public String getName() { + return attributes.get(attributeKey).toString(); + } + + @Override + public Map getAttributes() { + return attributes; + } + + @Override + public Collection getAuthorities() { + return Collections.singletonList( + new SimpleGrantedAuthority(user.getRole().getKey())); + } + + @Override + public String getPassword() { + return null; + } + + @Override + public String getUsername() { + return user.getRole().getKey(); + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + } +} diff --git a/src/main/java/com/example/team1_be/Team1BeApplication.java b/src/main/java/com/example/team1_be/Team1BeApplication.java index 390dd4f..b5e2d63 100644 --- a/src/main/java/com/example/team1_be/Team1BeApplication.java +++ b/src/main/java/com/example/team1_be/Team1BeApplication.java @@ -2,8 +2,12 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @SpringBootApplication +@ConfigurationPropertiesScan +@EnableJpaAuditing public class Team1BeApplication { public static void main(String[] args) { diff --git a/src/main/java/com/example/team1_be/controller/AuthController.java b/src/main/java/com/example/team1_be/controller/AuthController.java new file mode 100644 index 0000000..895e512 --- /dev/null +++ b/src/main/java/com/example/team1_be/controller/AuthController.java @@ -0,0 +1,25 @@ +package com.example.team1_be.controller; + +import com.example.team1_be.service.AuthService; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "인증기능 구현") +@RestController +@RequestMapping("/api/auth") +public class AuthController { + + private final AuthService authService; + + @Autowired + public AuthController(AuthService authService) { + this.authService = authService; + } + +// @GetMapping("/login/oauth2/code/google") +// public SingleResult login(OAuth2AuthenticationToken authenticationToken) { +// return new SingleResult<>(null); +// } +} diff --git a/src/main/java/com/example/team1_be/controller/TestController.java b/src/main/java/com/example/team1_be/controller/TestController.java index 8a7306e..9d50f3f 100644 --- a/src/main/java/com/example/team1_be/controller/TestController.java +++ b/src/main/java/com/example/team1_be/controller/TestController.java @@ -15,7 +15,6 @@ 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.RequestParam; import org.springframework.web.bind.annotation.RestController; @Tag(name = "참조") diff --git a/src/main/java/com/example/team1_be/entity/UserEntity.java b/src/main/java/com/example/team1_be/entity/UserEntity.java new file mode 100644 index 0000000..a7c8698 --- /dev/null +++ b/src/main/java/com/example/team1_be/entity/UserEntity.java @@ -0,0 +1,105 @@ +package com.example.team1_be.entity; + +import com.example.team1_be.entity.enums.Role; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.validation.constraints.NotNull; +import java.time.LocalDateTime; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@Entity(name = "users") +@EntityListeners(AuditingEntityListener.class) +public class UserEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column + private String name; + + @Column + private String email; + + @Column + private String picture; + + @Enumerated(EnumType.STRING) // Enum 타입은 문자열 형태로 저장해야 함 + @NotNull + private Role role; + + @NotNull + @Column + private Integer isDelete; + + @CreatedDate + private LocalDateTime createdAt; + + @LastModifiedDate + private LocalDateTime updatedAt; + + public UserEntity() { + + } + + public UserEntity(String name, String email, String picture) { + this.name = name; + this.email = email; + this.picture = picture; + this.isDelete = 0; + this.role = Role.USER; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getEmail() { + return email; + } + + public String getPicture() { + return picture; + } + + public @NotNull Role getRole() { + return role; + } + + public @NotNull Integer getIsDelete() { + return isDelete; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public void setIsDelete() { + this.isDelete = 1; + } + + public UserEntity update(String name, String picture) { + this.name = name; + this.picture = picture; + + return this; + } + + +} diff --git a/src/main/java/com/example/team1_be/entity/enums/Role.java b/src/main/java/com/example/team1_be/entity/enums/Role.java new file mode 100644 index 0000000..128cfba --- /dev/null +++ b/src/main/java/com/example/team1_be/entity/enums/Role.java @@ -0,0 +1,22 @@ +package com.example.team1_be.entity.enums; + +public enum Role { + ADMIN("ROLE_ADMIN", "관리자"), + USER("ROLE_USER", "사용자"); + + private final String key; + private final String title; + + Role(String key, String title) { + this.key = key; + this.title = title; + } + + public String getKey() { + return key; + } + + public String getTitle() { + return title; + } +} diff --git a/src/main/java/com/example/team1_be/mapper/UserMapper.java b/src/main/java/com/example/team1_be/mapper/UserMapper.java new file mode 100644 index 0000000..7d35914 --- /dev/null +++ b/src/main/java/com/example/team1_be/mapper/UserMapper.java @@ -0,0 +1,12 @@ +package com.example.team1_be.mapper; + +import com.example.team1_be.entity.UserEntity; +import org.springframework.stereotype.Component; + +@Component +public class UserMapper { + + public UserEntity toEntity(String userName, String email, String picture) { + return new UserEntity(userName, email, picture); + } +} diff --git a/src/main/java/com/example/team1_be/repository/UserRepository.java b/src/main/java/com/example/team1_be/repository/UserRepository.java new file mode 100644 index 0000000..02e5dea --- /dev/null +++ b/src/main/java/com/example/team1_be/repository/UserRepository.java @@ -0,0 +1,12 @@ +package com.example.team1_be.repository; + +import com.example.team1_be.entity.UserEntity; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository extends JpaRepository { + + Optional findByEmail(String email); +} diff --git a/src/main/java/com/example/team1_be/service/AuthService.java b/src/main/java/com/example/team1_be/service/AuthService.java new file mode 100644 index 0000000..3ab9380 --- /dev/null +++ b/src/main/java/com/example/team1_be/service/AuthService.java @@ -0,0 +1,71 @@ +package com.example.team1_be.service; + +import com.example.team1_be.DTO.AuthDTO; +import com.example.team1_be.DTO.AuthDTO.OAuthAttributes; +import com.example.team1_be.DTO.AuthDTO.PrincipalDetails; +import com.example.team1_be.entity.UserEntity; +import com.example.team1_be.mapper.UserMapper; +import com.example.team1_be.repository.UserRepository; +import java.util.Map; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class AuthService implements OAuth2UserService { + + private final UserRepository userRepository; + private final UserMapper userMapper; + + @Autowired + public AuthService(UserRepository userRepository, UserMapper userMapper) { + this.userRepository = userRepository; + this.userMapper = userMapper; + } + + @Transactional + @Override + public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { + OAuth2UserService delegate = new DefaultOAuth2UserService(); + OAuth2User oAuth2User = delegate.loadUser(userRequest); + + Map oAuth2UserAttributes = delegate.loadUser(userRequest).getAttributes(); + +// 로그인 플랫폼 확인 +// 추후 다른 OAuth2를 추가할 경우 사용 + String registrationId = userRequest.getClientRegistration().getRegistrationId(); + +// OAuth2 로그인 진행 시 키가 되는 필드 값 + String userNameAttributeName = userRequest.getClientRegistration() + .getProviderDetails() + .getUserInfoEndpoint() + .getUserNameAttributeName(); + +// 유저 정보 dto + AuthDTO.OAuthAttributes attributes = AuthDTO.OAuthAttributes.ofGoogle(userNameAttributeName, + oAuth2User.getAttributes()); + +// 기존에 회원가입 되어 있으면 로그인 +// 회원가입이 않되어 있으면 회원가입 후 로그인 + UserEntity user = saveOrUpdate(attributes); + + return new PrincipalDetails(user, oAuth2UserAttributes, userNameAttributeName); + } + + @Transactional + protected UserEntity saveOrUpdate(OAuthAttributes attributes) { + UserEntity user = userRepository.findByEmail(attributes.getEmail()) + // 구글 사용자 정보 업데이트(이미 가입된 사용자) => 업데이트 + .map(entity -> entity.update(attributes.getName(), attributes.getPicture())) + // 가입되지 않은 사용자 => User 엔티티 생성 + .orElse(userMapper.toEntity(attributes.getName(), attributes.getEmail(), + attributes.getPicture())); + + return userRepository.save(user); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/team1_be/util/auth/JwtToken.java b/src/main/java/com/example/team1_be/util/auth/JwtToken.java new file mode 100644 index 0000000..4a89517 --- /dev/null +++ b/src/main/java/com/example/team1_be/util/auth/JwtToken.java @@ -0,0 +1,91 @@ +package com.example.team1_be.util.auth; + + +import com.example.team1_be.DTO.AuthDTO.PrincipalDetails; +import com.example.team1_be.util.errorException.BaseHandler; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; +import java.security.Key; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.stereotype.Component; + +@Component +public class JwtToken { + + private Key secretKey; + private long tokenExpTime; + + public JwtToken(@Value("${jwt.secretKey}") String secretKey, + @Value("${jwt.tokenExpTime}") long tokenExpTime) { + this.secretKey = Keys.hmacShaKeyFor(secretKey.getBytes()); + this.tokenExpTime = tokenExpTime; + } + + public String createToken(Authentication authentication) { + ZonedDateTime now = ZonedDateTime.now().withZoneSameInstant(ZoneId.of("UTC")); + ZonedDateTime expirationDateTime = now.plusSeconds(tokenExpTime); + + String authorities = authentication.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.joining()); + + PrincipalDetails user = (PrincipalDetails) authentication.getPrincipal(); + + Claims claims = Jwts.claims(); + claims.put("authentication", authorities); + claims.put("email", user.getUser().getEmail()); + return Jwts.builder() + .setClaims(claims) + .setIssuedAt(Date.from(now.toInstant())) + .setExpiration(Date.from(expirationDateTime.toInstant())) + .signWith(secretKey, SignatureAlgorithm.HS256) + .compact(); + } + + public Claims validateToken(String token) { + try { + return Jwts.parserBuilder() + .setSigningKey(secretKey) + .build() + .parseClaimsJws(token) + .getBody(); + } catch (ExpiredJwtException e) { + throw new BaseHandler(HttpStatus.UNAUTHORIZED, "만료된 토큰 입니다."); + } catch (JwtException e) { + throw new BaseHandler(HttpStatus.UNAUTHORIZED, "유효하지 않은 JWT 토큰입니다."); + } + } + + public Authentication getAuthentication(String token) { + Claims claims = validateToken(token); + List authorities = getAuthorities(claims); + + return new UsernamePasswordAuthenticationToken(getEmail(token), token, authorities); + } + + private List getAuthorities(Claims claims) { + return Collections.singletonList( + new SimpleGrantedAuthority(claims.get("authentication", String.class))); + } + + public String getEmail(String token) { + Claims claims = validateToken(token); + return claims.get("email", String.class); + } + +} diff --git a/src/main/java/com/example/team1_be/util/auth/OAuth2SuccessHandler.java b/src/main/java/com/example/team1_be/util/auth/OAuth2SuccessHandler.java new file mode 100644 index 0000000..c3aad8c --- /dev/null +++ b/src/main/java/com/example/team1_be/util/auth/OAuth2SuccessHandler.java @@ -0,0 +1,36 @@ +package com.example.team1_be.util.auth; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; +import org.springframework.stereotype.Component; +import org.springframework.web.util.UriComponentsBuilder; + +@Component +public class OAuth2SuccessHandler implements AuthenticationSuccessHandler { + + private final JwtToken jwtToken; + private static final String URI = "/auth/success"; + + @Autowired + public OAuth2SuccessHandler(JwtToken jwtToken) { + this.jwtToken = jwtToken; + } + + @Override + public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, + Authentication authentication) throws IOException { + // 사용자 정보를 바탕으로 JWT 생성 + String token = jwtToken.createToken(authentication); + + // 토큰 전달을 위한 redirect + String redirectUrl = UriComponentsBuilder.fromUriString(URI) + .queryParam("accessToken", token) + .build().toUriString(); + + response.sendRedirect(redirectUrl); + } +} diff --git a/src/main/java/com/example/team1_be/util/auth/ParsingPram.java b/src/main/java/com/example/team1_be/util/auth/ParsingPram.java new file mode 100644 index 0000000..f36a25f --- /dev/null +++ b/src/main/java/com/example/team1_be/util/auth/ParsingPram.java @@ -0,0 +1,25 @@ +package com.example.team1_be.util.auth; + +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class ParsingPram { + + + private final JwtToken jwtToken; + private static final String AUTHORIZATION_HEADER = "Authorization"; + + @Autowired + public ParsingPram(JwtToken jwtToken) { + this.jwtToken = jwtToken; + } + + public String getEmail(HttpServletRequest request) { + String token = request.getHeader(AUTHORIZATION_HEADER); + token = token.substring(7); + return jwtToken.getEmail(token); + } + +} diff --git a/src/main/java/com/example/team1_be/util/auth/SecurityConfig.java b/src/main/java/com/example/team1_be/util/auth/SecurityConfig.java new file mode 100644 index 0000000..87b8f88 --- /dev/null +++ b/src/main/java/com/example/team1_be/util/auth/SecurityConfig.java @@ -0,0 +1,72 @@ +package com.example.team1_be.util.auth; + +import com.example.team1_be.service.AuthService; +import com.example.team1_be.util.fiter.TokenAuthenticationFilter; +import com.example.team1_be.util.fiter.TokenExceptionFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + private final AuthService authService; + private final OAuth2SuccessHandler successHandler; + private final TokenAuthenticationFilter tokenAuthenticationFilter; + private final TokenExceptionFilter tokenExceptionFilter; + + @Autowired + public SecurityConfig(AuthService authService, OAuth2SuccessHandler successHandler, + TokenAuthenticationFilter tokenAuthenticationFilter, + TokenExceptionFilter tokenExceptionFilter) { + this.authService = authService; + this.successHandler = successHandler; + this.tokenAuthenticationFilter = tokenAuthenticationFilter; + this.tokenExceptionFilter = tokenExceptionFilter; + } + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .csrf(AbstractHttpConfigurer::disable) + .cors(AbstractHttpConfigurer::disable) + .httpBasic(AbstractHttpConfigurer::disable) + .formLogin(AbstractHttpConfigurer::disable) + .logout(AbstractHttpConfigurer::disable) + .headers(c -> c.frameOptions().disable()) + .sessionManagement(c -> c.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + + .authorizeHttpRequests(request -> request +// swagger + .requestMatchers("/swagger", "/swagger-ui.html", "/swagger-ui/**", "/api-docs", + "/api-docs/**", "/v3/api-docs/**").permitAll() + .requestMatchers("/login/**", "/auth/**", "/oauth2/**") + .permitAll() +// 확장자 + .requestMatchers("/", "/error", "/favicon.ico", "/**/*.png", "/**/*.gif", + "/**/*.svg", "/**/*.jpg", "/**/*.html", "/**/*.css", "/**/*.js") + .permitAll() +// 인증, h2 + .requestMatchers("/auth/**", "/h2-console/**").permitAll() + .anyRequest() + .authenticated() + ) + + .oauth2Login(oauth -> oauth + .userInfoEndpoint(c -> c.userService(authService)) + .successHandler(successHandler) + ) + + .addFilterAfter(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) + .addFilterBefore(tokenExceptionFilter, tokenAuthenticationFilter.getClass()); + + return http.build(); + } +} diff --git a/src/main/java/com/example/team1_be/util/fiter/TokenAuthenticationFilter.java b/src/main/java/com/example/team1_be/util/fiter/TokenAuthenticationFilter.java new file mode 100644 index 0000000..b87de4b --- /dev/null +++ b/src/main/java/com/example/team1_be/util/fiter/TokenAuthenticationFilter.java @@ -0,0 +1,50 @@ +package com.example.team1_be.util.fiter; + +import com.example.team1_be.util.auth.JwtToken; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Date; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +@Component +public class TokenAuthenticationFilter extends OncePerRequestFilter { + + private final JwtToken jwtToken; + private static final String AUTHORIZATION_HEADER = "Authorization"; + private static final String BEARER_PREFIX = "Bearer "; + + @Autowired + public TokenAuthenticationFilter(JwtToken jwtToken) { + this.jwtToken = jwtToken; + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + + String path = request.getRequestURI(); + String method = request.getMethod(); + + String token = request.getHeader(AUTHORIZATION_HEADER); + if (token != null && token.startsWith(BEARER_PREFIX)) { + token = token.substring(7); + jwtToken.validateToken(token).getExpiration().after(new Date()); + setAuthentication(token); + } + + filterChain.doFilter(request, response); + } + + private void setAuthentication(String accessToken) { + Authentication authentication = jwtToken.getAuthentication(accessToken); + //현재 Request의 Security Context에 접근권한 설정 + SecurityContextHolder.getContext().setAuthentication(authentication); + } +} diff --git a/src/main/java/com/example/team1_be/util/fiter/TokenExceptionFilter.java b/src/main/java/com/example/team1_be/util/fiter/TokenExceptionFilter.java new file mode 100644 index 0000000..473dd5a --- /dev/null +++ b/src/main/java/com/example/team1_be/util/fiter/TokenExceptionFilter.java @@ -0,0 +1,30 @@ +package com.example.team1_be.util.fiter; + +import com.example.team1_be.util.errorException.BaseHandler; +import io.jsonwebtoken.ExpiredJwtException; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import org.springframework.http.HttpStatus; +import org.springframework.security.oauth2.jwt.JwtException; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +@Component +public class TokenExceptionFilter extends OncePerRequestFilter { + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + + try { + filterChain.doFilter(request, response); + } catch (ExpiredJwtException e) { + throw new BaseHandler(HttpStatus.UNAUTHORIZED, "만료된 토큰 입니다."); + } catch (JwtException e) { + throw new BaseHandler(HttpStatus.UNAUTHORIZED, "유효하지 않은 JWT 토큰입니다."); + } + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index f474091..02b3d51 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -14,7 +14,9 @@ spring.jpa.defer-datasource-initialization=true spring.jpa.properties.hibernate.format_sql=true spring.jpa.show-sql=true spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect -jwt.secretKey=*** +jwt.secretKey=testSecretKey20230327testSecretKey20230327testSecretKey20230327 jwt.tokenExpTime=3600 spring.profiles.active=dev -server.forward-headers-strategy=framework \ No newline at end of file +server.forward-headers-strategy=framework +spring.profiles.include=oauth +spring.mvc.pathmatch.matching-strategy=ant_path_matcher \ No newline at end of file From 902b24112e73e8fd17aa3c615f791bcdb48bd8e3 Mon Sep 17 00:00:00 2001 From: Kim-DongHyuk <80240164+Kdonghs@users.noreply.github.com> Date: Thu, 19 Sep 2024 13:31:44 +0900 Subject: [PATCH 03/22] docs: README.md --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index ac4296b..f991e8a 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,22 @@ - 인증(김동혁) - 회원가입 + - google oauth2로 구현 + - 몇 가지 예외처리된 경로를 제외하면 구글 로그인 요구 + - swagger3 + - h2-console + - / + - flow + - 토큰 검증 + - 토큰이 없다면 + - 로그인 + - 가입 정보가 없다면 회원가입 + - 성공시 토큰 생성 및 반환 + - GET Param으로 반환됨 + - 실패시 /error로 이동 + - 토큰이 있다면 + - 토큰 검증 + - 토큰 내부의 정보를 파싱 - 로그인 - 코드로 참여 - 프로젝트(김도헌) From 151c09cba300814d9353692adc0f26bb2ca53976 Mon Sep 17 00:00:00 2001 From: suno-boy Date: Thu, 19 Sep 2024 14:11:50 +0900 Subject: [PATCH 04/22] =?UTF-8?q?docs:=20README.md=20=EC=9B=90=EC=83=81?= =?UTF-8?q?=EB=B3=B5=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 57 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 08bd96d..4045161 100644 --- a/README.md +++ b/README.md @@ -2,24 +2,51 @@ --- -### 권순호가 맡은 구현 기능 목록 +# 그라운드 룰 -- **게스트(팀원) 관리 API** - - [ ] 프로젝트 링크 생성 - - [ ] 팀원이 수락하였을 때, 프로젝트에 팀원이 자동 추가되는 API - - [ ] 프로젝트 참여 코드 메일로 전달 - - [ ] 팀원 삭제 +- 추가 요망 -### 기능 구현 일정 - -- 3week( 9/14(토) ~ 9/20(금) ) - - [ ] 프로젝트 링크 생성 - - [ ] 팀원 삭제 +--- +# 코드 컨벤션 -- 4week( 9/21(토) ~ 9/27(금) ) - - [ ] 프로젝트 참여 코드 메일로 전달 +- angular code conventions을 기반으로 커밋 메세지 작성 + - feat : 새로운 기능 추가 + - fix : 버그 수정 + - docs : 문서 변경 + - style : 코드 스타일 변경 (포매팅 수정, 세미콜론 추가 등) + - refactor : 코드 리팩토링 + - test : 테스트 코드 추가, 수정 + - chore : 빌드 프로세스, 도구 설정 변경 등 기타 작업 +--- -- 5week( 9/28(토) ~ 10/4(금) ) - - [ ] 팀원이 수락하였을 때, 프로젝트에 팀원이 자동 추가되는 API \ No newline at end of file +# 구현 기능 목록 + +- 인증(김동혁) + - 회원가입 + - 로그인 + - 코드로 참여 +- 프로젝트(김도헌) + - 프로젝트 리스트 조회 + - 프로젝트 기간 리스트 조회 + - 프로젝트 조회 + - 프로젝트 멤버 조회 + - 프로젝트 생성 + - 프로젝트 설정 수정 + - 프로젝트 삭제 +- 게스트(권순호) + - 게스트 생성 + - 게스트 수정 + - 게스트 삭제 + - 프로젝트 내 게스트 추가 + - 프로젝트 코드 메일로 전달 +- 태스크(조서영) + - 태스크 생성 + - 태스크 삭제 + - 태스크 수정 +- 이벤트 + - 독려 이메일 전달 + - 각 게스트별 진행도 조회 + - 태스크별 진행도 조회 +- ... \ No newline at end of file From 738e630fb4247ae1d8ebae6e59db50de43593d72 Mon Sep 17 00:00:00 2001 From: sunandrabbit Date: Fri, 20 Sep 2024 12:48:31 +0900 Subject: [PATCH 05/22] =?UTF-8?q?feat=20:=20Base=20Entity=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/team1_be/entity/BaseEntity.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/main/java/com/example/team1_be/entity/BaseEntity.java diff --git a/src/main/java/com/example/team1_be/entity/BaseEntity.java b/src/main/java/com/example/team1_be/entity/BaseEntity.java new file mode 100644 index 0000000..11cf94f --- /dev/null +++ b/src/main/java/com/example/team1_be/entity/BaseEntity.java @@ -0,0 +1,30 @@ +package com.example.team1_be.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; +import java.time.LocalDateTime; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@EntityListeners(AuditingEntityListener.class) +@MappedSuperclass +public class BaseEntity { + + @CreatedDate + @Column(updatable = false) + private LocalDateTime createdAt; + + @LastModifiedDate + private LocalDateTime updatedAt; + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + +} \ No newline at end of file From 00f9bf74891c22303dbece05c0d2f51c76831ba1 Mon Sep 17 00:00:00 2001 From: sunandrabbit Date: Fri, 20 Sep 2024 12:48:46 +0900 Subject: [PATCH 06/22] =?UTF-8?q?feat=20:=20Project=20Entity=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/team1_be/entity/Project.java | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 src/main/java/com/example/team1_be/entity/Project.java diff --git a/src/main/java/com/example/team1_be/entity/Project.java b/src/main/java/com/example/team1_be/entity/Project.java new file mode 100644 index 0000000..28abd21 --- /dev/null +++ b/src/main/java/com/example/team1_be/entity/Project.java @@ -0,0 +1,155 @@ +package com.example.team1_be.entity; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Entity(name = "project") +public class Project extends BaseEntity{ + + public Project() { + + } + + public Project(String name, Object viewType, Integer isDelete, User user, + LocalDateTime startDate, + LocalDateTime endDate) { + this.name = name; + this.viewType = viewType; + this.isDelete = isDelete; + this.user = user; + this.startDate = startDate; + this.endDate = endDate; + } + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "project_id") + private Long id; + + @Column(name = "name") + private String name; + + @Column(name = "view_type") + private Object viewType; + + @Column(name = "is_delete") + private Integer isDelete; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @OneToMany(mappedBy = "project", cascade = CascadeType.ALL) + private List guests; + + @OneToMany(mappedBy = "project", cascade = CascadeType.ALL) + private List options; + + @Column(name = "start_date") + private LocalDateTime startDate; + + @Column(name = "end_date") + private LocalDateTime endDate; + + //Getters + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public Object getViewType() { + return viewType; + } + + public Integer getIsDelete() { + return isDelete; + } + + public User getUser() { + return user; + } + + public List getGuests() { + return guests; + } + + public List getOptions() { + return options; + } + + public LocalDateTime getStartDate() { + return startDate; + } + + public LocalDateTime getEndDate() { + return endDate; + } + + //Setters + public void setId(Long id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + + public void setViewType(Object viewType) { + this.viewType = viewType; + } + + public void setIsDelete(Integer isDelete) { + this.isDelete = isDelete; + } + + public void setUser(User user) { + this.user = user; + } + + public void setGuests(List guests) { + this.guests = guests; + } + + public void setOptions(List options) { + this.options = options; + } + + public void setStartDate(LocalDateTime startDate) { + this.startDate = startDate; + } + + public void setEndDate(LocalDateTime endDate) { + this.endDate = endDate; + } + + public void addGuest(Guest guest) { + if (this.guests == null) { + this.guests = new ArrayList<>(); + } + this.guests.add(guest); + guest.setProject(this); // 양방향 관계 설정 + } + + public void addOption(ProjectOption option) { + if (this.options == null) { + this.options = new ArrayList<>(); + } + this.options.add(option); + option.setProject(this); // 양방향 관계 설정 + } + +} From 5c5bcedd36d030ea7d47471e2f5e05fea0c0b16b Mon Sep 17 00:00:00 2001 From: sunandrabbit Date: Fri, 20 Sep 2024 12:49:09 +0900 Subject: [PATCH 07/22] =?UTF-8?q?feat=20:=20User=20Entity=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/team1_be/entity/User.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/main/java/com/example/team1_be/entity/User.java diff --git a/src/main/java/com/example/team1_be/entity/User.java b/src/main/java/com/example/team1_be/entity/User.java new file mode 100644 index 0000000..fffa8ae --- /dev/null +++ b/src/main/java/com/example/team1_be/entity/User.java @@ -0,0 +1,71 @@ +package com.example.team1_be.entity; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import java.util.ArrayList; +import java.util.List; + +@Entity(name = "user") +public class User extends BaseEntity{ + + public User() { + + } + + public User(String email, String password, Integer isDelete) { + this.email = email; + this.password = password; + this.isDelete = isDelete; + } + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "user_id") + private Long id; + + @Column(name = "email") + private String email; + + @Column(name = "password") + private String password; + + @Column(name = "is_delete") + private Integer isDelete; + + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) + private List projects; + + public Long getId() { + return id; + } + + public String getEmail() { + return email; + } + + public String getPassword() { + return password; + } + + public Integer getIsDelete() { + return isDelete; + } + + public List getProjects() { + return projects; + } + + public void addProject(Project project) { + if (this.projects == null) { + this.projects = new ArrayList<>(); + } + this.projects.add(project); + project.setUser(this); // 양방향 관계 설정 + } + +} From bac16bd70b582955c6fab3c2f5fb529a40af14f3 Mon Sep 17 00:00:00 2001 From: sunandrabbit Date: Fri, 20 Sep 2024 12:49:20 +0900 Subject: [PATCH 08/22] =?UTF-8?q?feat=20:=20Guest=20Entity=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/team1_be/entity/Guest.java | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/main/java/com/example/team1_be/entity/Guest.java diff --git a/src/main/java/com/example/team1_be/entity/Guest.java b/src/main/java/com/example/team1_be/entity/Guest.java new file mode 100644 index 0000000..6aa1e78 --- /dev/null +++ b/src/main/java/com/example/team1_be/entity/Guest.java @@ -0,0 +1,87 @@ +package com.example.team1_be.entity; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import java.util.ArrayList; +import java.util.List; + +@Entity(name = "guest") +public class Guest extends BaseEntity{ + + public Guest() { + + } + + public Guest(String email, String joinNumber, Integer isDelete, Project project) { + this.email = email; + this.joinNumber = joinNumber; + this.isDelete = isDelete; + this.project = project; + } + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "guest_id") + private Long id; + + @Column(name = "email") + private String email; + + @Column(name = "join_number") + private String joinNumber; + + @Column(name = "is_delete") + private Integer isDelete; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "project_id") + private Project project; + + @OneToMany(mappedBy = "owner", cascade = CascadeType.ALL) + private List tasks; + + public Long getId() { + return id; + } + + public String getEmail() { + return email; + } + + public String getJoinNumber() { + return joinNumber; + } + + public Integer getIsDelete() { + return isDelete; + } + + public Project getProject() { + return project; + } + + public List getTasks() { + return tasks; + } + + public void addTask(Task task) { + if (this.tasks == null) { + this.tasks = new ArrayList<>(); + } + this.tasks.add(task); + task.setOwner(this); // 양방향 관계 설정 + } + + public void setProject(Project project) { + this.project = project; + } + +} From ecc2b94b3d59d3f7988a5e28eb55c7818ec66983 Mon Sep 17 00:00:00 2001 From: sunandrabbit Date: Fri, 20 Sep 2024 12:49:35 +0900 Subject: [PATCH 09/22] =?UTF-8?q?feat=20:=20ProjectOption=20Entity=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../team1_be/entity/ProjectOption.java | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/main/java/com/example/team1_be/entity/ProjectOption.java diff --git a/src/main/java/com/example/team1_be/entity/ProjectOption.java b/src/main/java/com/example/team1_be/entity/ProjectOption.java new file mode 100644 index 0000000..da67fac --- /dev/null +++ b/src/main/java/com/example/team1_be/entity/ProjectOption.java @@ -0,0 +1,79 @@ +package com.example.team1_be.entity; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import java.util.ArrayList; +import java.util.List; + +@Entity(name = "project_option") +public class ProjectOption extends BaseEntity{ + + public ProjectOption() { + + } + + public ProjectOption(String name, Integer isDelete, Project project) { + this.name = name; + this.isDelete = isDelete; + this.project = project; + } + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "option_id") + private Long id; + + @Column(name = "name") + private String name; + + @Column(name = "is_delete") + private Integer isDelete; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "project_id") + private Project project; + + @OneToMany(mappedBy = "option", cascade = CascadeType.ALL) + private List details; + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public Integer getIsDelete() { + return isDelete; + } + + public Project getProject() { + return project; + } + + public List getDetails() { + return details; + } + + public void addDetail(ProjectOptionDetail detail) { + if (this.details == null) { + this.details = new ArrayList<>(); + } + this.details.add(detail); + detail.setOption(this); // 양방향 관계 설정 + } + + public void setProject(Project project) { + this.project = project; + } + +} From df53512a19daed048b272b2f3594587eb4689761 Mon Sep 17 00:00:00 2001 From: sunandrabbit Date: Fri, 20 Sep 2024 12:49:47 +0900 Subject: [PATCH 10/22] =?UTF-8?q?feat=20:=20ProjectOptionDetail=20Entity?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../team1_be/entity/ProjectOptionDetail.java | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/main/java/com/example/team1_be/entity/ProjectOptionDetail.java diff --git a/src/main/java/com/example/team1_be/entity/ProjectOptionDetail.java b/src/main/java/com/example/team1_be/entity/ProjectOptionDetail.java new file mode 100644 index 0000000..04127a7 --- /dev/null +++ b/src/main/java/com/example/team1_be/entity/ProjectOptionDetail.java @@ -0,0 +1,69 @@ +package com.example.team1_be.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; + +@Entity(name = "project_option_detail") +public class ProjectOptionDetail extends BaseEntity{ + + public ProjectOptionDetail() { + + } + + public ProjectOptionDetail(String name, String eventType, Integer isDelete, + ProjectOption option) { + this.name = name; + this.eventType = eventType; + this.isDelete = isDelete; + this.option = option; + } + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "detail_id") + private Long id; + + @Column(name = "name") + private String name; + + @Column(name = "event_type") + private String eventType; + + @Column(name = "is_delete") + private Integer isDelete; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "option_id") + private ProjectOption option; + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getEventType() { + return eventType; + } + + public Integer getIsDelete() { + return isDelete; + } + + public ProjectOption getOption() { + return option; + } + + public void setOption(ProjectOption option) { + this.option = option; + } + +} From 707a991db90fbe7b279198d9968e6087b2f8acd0 Mon Sep 17 00:00:00 2001 From: sunandrabbit Date: Fri, 20 Sep 2024 12:49:54 +0900 Subject: [PATCH 11/22] =?UTF-8?q?feat=20:=20Task=20Entity=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/team1_be/entity/Task.java | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 src/main/java/com/example/team1_be/entity/Task.java diff --git a/src/main/java/com/example/team1_be/entity/Task.java b/src/main/java/com/example/team1_be/entity/Task.java new file mode 100644 index 0000000..dda92aa --- /dev/null +++ b/src/main/java/com/example/team1_be/entity/Task.java @@ -0,0 +1,108 @@ +package com.example.team1_be.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToOne; +import java.time.LocalDateTime; + +@Entity(name = "task") +public class Task extends BaseEntity{ + + public Task() { + + } + + public Task(String name, String remark, Integer progress, Integer isDelete, Project project, + Guest owner, LocalDateTime startDate, LocalDateTime endDate) { + this.name = name; + this.remark = remark; + this.progress = progress; + this.isDelete = isDelete; + this.project = project; + this.owner = owner; + this.startDate = startDate; + this.endDate = endDate; + } + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "task_id") + private Long id; + + @Column(name = "name") + private String name; + + @Column(name = "remark") + private String remark; + + @Column(name = "progress") + private Integer progress; + + @Column(name = "is_delete") + private Integer isDelete; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "project_id") + private Project project; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "guest_id") + private Guest owner; + + @Column(name = "start_date") + private LocalDateTime startDate; + + @Column(name = "end_date") + private LocalDateTime endDate; + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getRemark() { + return remark; + } + + public Integer getProgress() { + return progress; + } + + public Integer getIsDelete() { + return isDelete; + } + + public Project getProject() { + return project; + } + + public Guest getOwner() { + return owner; + } + + public LocalDateTime getStartDate() { + return startDate; + } + + public LocalDateTime getEndDate() { + return endDate; + } + + public void setOwner(Guest owner) { + this.owner = owner; + } + + public void setProject(Project project) { + this.project = project; + } + +} From 78aefe7fceaf808ce3fd602c2ed1f1630f1088f4 Mon Sep 17 00:00:00 2001 From: sunandrabbit Date: Fri, 20 Sep 2024 12:50:07 +0900 Subject: [PATCH 12/22] =?UTF-8?q?feat=20:=20Project=20DTO=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/team1_be/DTO/ProjectDTO.java | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 src/main/java/com/example/team1_be/DTO/ProjectDTO.java diff --git a/src/main/java/com/example/team1_be/DTO/ProjectDTO.java b/src/main/java/com/example/team1_be/DTO/ProjectDTO.java new file mode 100644 index 0000000..5577b3b --- /dev/null +++ b/src/main/java/com/example/team1_be/DTO/ProjectDTO.java @@ -0,0 +1,171 @@ +package com.example.team1_be.DTO; + +import com.example.team1_be.entity.Guest; +import com.example.team1_be.entity.ProjectOption; +import com.example.team1_be.entity.User; +import com.example.team1_be.util.page.PageParam; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +public class ProjectDTO { + + public static class getList extends PageParam { + + } + + public static class create { + + private String name; + + private Object viewType; + + private Integer isDelete; + + private User user; + + private List guests; + + private List options; + + private LocalDateTime startDate; + + private LocalDateTime endDate; + + public create() { + } + + public create(String name, Object viewType, Integer isDelete, User user, + LocalDateTime startDate, + LocalDateTime endDate, + List guests, + List options) { + this.name = name; + this.viewType = viewType; + this.isDelete = isDelete; + this.user = user; + this.startDate = startDate; + this.endDate = endDate; + + if (guests == null) { + this.guests = new ArrayList<>(); + } else { + this.guests = guests; + } + + if (options == null) { + this.options = new ArrayList<>(); + } else { + this.options = options; + } + } + + public String getName() { + return name; + } + + public Object getViewType() { + return viewType; + } + + public Integer getIsDelete() { + return isDelete; + } + + public User getUser() { + return user; + } + + public List getGuests() { + return guests; + } + + public List getOptions() { + return options; + } + + public LocalDateTime getStartDate() { + return startDate; + } + + public LocalDateTime getEndDate() { + return endDate; + } + + } + + public static class update { + + private String name; + + private Object viewType; + + private User user; + + private List guests; + + private List options; + + private LocalDateTime startDate; + + private LocalDateTime endDate; + + public update() { + } + + public update(String name, Object viewType, User user, + LocalDateTime startDate, + LocalDateTime endDate, + List guests, + List options) { + this.name = name; + this.viewType = viewType; + this.user = user; + this.startDate = startDate; + this.endDate = endDate; + + if (guests == null) { + this.guests = new ArrayList<>(); + } else { + this.guests = guests; + } + + if (options == null) { + this.options = new ArrayList<>(); + } else { + this.options = options; + } + } + + public String getName() { + return name; + } + + public Object getViewType() { + return viewType; + } + + public User getUser() { + return user; + } + + public List getGuests() { + return guests; + } + + public List getOptions() { + return options; + } + + public LocalDateTime getStartDate() { + return startDate; + } + + public LocalDateTime getEndDate() { + return endDate; + } + + } + +} + From 12b277ca523416ca8b2bfad31b8f02b026ab7891 Mon Sep 17 00:00:00 2001 From: sunandrabbit Date: Fri, 20 Sep 2024 12:51:21 +0900 Subject: [PATCH 13/22] =?UTF-8?q?feat=20:=20Project=20Repository=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/team1_be/repository/ProjectRepository.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/com/example/team1_be/repository/ProjectRepository.java diff --git a/src/main/java/com/example/team1_be/repository/ProjectRepository.java b/src/main/java/com/example/team1_be/repository/ProjectRepository.java new file mode 100644 index 0000000..efec22d --- /dev/null +++ b/src/main/java/com/example/team1_be/repository/ProjectRepository.java @@ -0,0 +1,10 @@ +package com.example.team1_be.repository; + +import com.example.team1_be.entity.Project; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ProjectRepository extends JpaRepository { + Page findAll(Pageable pageable); +} From 1313414ef7315b746441fb00414f1ce4de37c861 Mon Sep 17 00:00:00 2001 From: sunandrabbit Date: Fri, 20 Sep 2024 12:51:30 +0900 Subject: [PATCH 14/22] =?UTF-8?q?feat=20:=20Project=20Controller=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ProjectController.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/main/java/com/example/team1_be/controller/ProjectController.java diff --git a/src/main/java/com/example/team1_be/controller/ProjectController.java b/src/main/java/com/example/team1_be/controller/ProjectController.java new file mode 100644 index 0000000..2c014b3 --- /dev/null +++ b/src/main/java/com/example/team1_be/controller/ProjectController.java @@ -0,0 +1,71 @@ +package com.example.team1_be.controller; + +import com.example.team1_be.DTO.ProjectDTO; +import com.example.team1_be.entity.Guest; +import com.example.team1_be.entity.Project; +import com.example.team1_be.service.ProjectService; +import com.example.team1_be.util.page.ListResult; +import com.example.team1_be.util.page.PageMapper; +import com.example.team1_be.util.page.PageResult; +import com.example.team1_be.util.page.SingleResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +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.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "프로젝트") +@RestController +@RequestMapping("/api/project") +public class ProjectController { + + private final ProjectService projectService; + + public ProjectController(ProjectService projectService) { + this.projectService = projectService; + } + + @Operation(summary = "프로젝트 리스트 조회") + @GetMapping + public PageResult getProjectList(@Valid ProjectDTO.getList param) { + return PageMapper.toPageResult(projectService.getProjectList(param)); + } + + @Operation(summary = "프로젝트 조회") + @GetMapping("/{id}") + public SingleResult getProject(@Valid @PathVariable long id) { + return new SingleResult<>(projectService.getProject(id)); + } + + @Operation(summary = "프로젝트 멤버 조회") + @GetMapping("/{id}/{members}") + public ListResult getProjectMembers(@Valid @PathVariable long id) { + return new ListResult<>(projectService.getProjectMembers(id)); + } + + @Operation(summary = "프로젝트 생성") + @PostMapping + public SingleResult createProject(@Valid @RequestBody ProjectDTO.create create) { + return new SingleResult<>(projectService.createProject(create)); + } + + @Operation(summary = "프로젝트 설정 수정") + @PutMapping("/{id}") + public SingleResult updateProject(@Valid @RequestBody ProjectDTO.update update, + @PathVariable long id) { + return new SingleResult<>(projectService.updateProject(id, update)); + } + + @Operation(summary = "프로젝트 삭제") + @DeleteMapping("/{id}") + public void deleteProject(@Valid @PathVariable long id) { + projectService.deleteProject(id); + } + +} From 625b5f1f03c08fb16f67e7aa9d0f7810fe82bda1 Mon Sep 17 00:00:00 2001 From: sunandrabbit Date: Fri, 20 Sep 2024 12:51:41 +0900 Subject: [PATCH 15/22] =?UTF-8?q?feat=20:=20Project=20Service=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../team1_be/service/ProjectService.java | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/main/java/com/example/team1_be/service/ProjectService.java diff --git a/src/main/java/com/example/team1_be/service/ProjectService.java b/src/main/java/com/example/team1_be/service/ProjectService.java new file mode 100644 index 0000000..b4f92a2 --- /dev/null +++ b/src/main/java/com/example/team1_be/service/ProjectService.java @@ -0,0 +1,84 @@ +package com.example.team1_be.service; + +import com.example.team1_be.DTO.ProjectDTO; +import com.example.team1_be.entity.Guest; +import com.example.team1_be.entity.Project; +import com.example.team1_be.entity.ProjectOption; +import com.example.team1_be.repository.ProjectRepository; +import com.example.team1_be.util.errorException.BaseHandler; +import java.util.List; +import org.springframework.data.domain.Page; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +@Service +public class ProjectService { + + private final ProjectRepository projectRepository; + + public ProjectService(ProjectRepository projectRepository) { + this.projectRepository = projectRepository; + } + + public Page getProjectList(ProjectDTO.getList param) { + return projectRepository.findAll(param.toPageable()); + } + + public Project getProject(long get) { + Project project = projectRepository.findById(get) + .orElseThrow(() -> new BaseHandler(HttpStatus.NOT_FOUND, "존재하지 않음")); + return project; + } + + public List getProjectMembers(long get) { + Project project = projectRepository.findById(get) + .orElseThrow(() -> new BaseHandler(HttpStatus.NOT_FOUND, "존재하지 않음")); + return project.getGuests(); + } + + public Project createProject(ProjectDTO.create create) { + Project project = new Project( + create.getName(), + create.getViewType(), + create.getIsDelete(), + create.getUser(), + create.getStartDate(), + create.getEndDate() + ); + + if (create.getGuests() != null) { + for (Guest guest : create.getGuests()) { + project.addGuest(guest); + } + } + + if (create.getOptions() != null) { + for (ProjectOption option : create.getOptions()) { + project.addOption(option); + } + } + projectRepository.save(project); + return project; + } + + public Project updateProject(long get, ProjectDTO.update update) { + Project project = projectRepository.findById(get) + .orElseThrow(() -> new BaseHandler(HttpStatus.NOT_FOUND, "존재하지 않음")); + + project.setName(update.getName()); + project.setViewType(update.getViewType()); + project.setUser(update.getUser()); + project.setGuests(update.getGuests()); + project.setOptions(update.getOptions()); + project.setStartDate(update.getStartDate()); + project.setEndDate(update.getEndDate()); + + projectRepository.save(project); + return project; + } + + public void deleteProject(long get) { + projectRepository.deleteById(get); + } + +} From 200750f475b7b036690fea3ae079b2cfafb74cb2 Mon Sep 17 00:00:00 2001 From: sunandrabbit Date: Fri, 20 Sep 2024 15:52:43 +0900 Subject: [PATCH 16/22] =?UTF-8?q?fix=20:=20annotation=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/example/team1_be/Team1BeApplication.java | 2 ++ .../java/com/example/team1_be/repository/ProjectRepository.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/main/java/com/example/team1_be/Team1BeApplication.java b/src/main/java/com/example/team1_be/Team1BeApplication.java index 390dd4f..b936142 100644 --- a/src/main/java/com/example/team1_be/Team1BeApplication.java +++ b/src/main/java/com/example/team1_be/Team1BeApplication.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @SpringBootApplication +@EnableJpaAuditing public class Team1BeApplication { public static void main(String[] args) { diff --git a/src/main/java/com/example/team1_be/repository/ProjectRepository.java b/src/main/java/com/example/team1_be/repository/ProjectRepository.java index efec22d..b3031a6 100644 --- a/src/main/java/com/example/team1_be/repository/ProjectRepository.java +++ b/src/main/java/com/example/team1_be/repository/ProjectRepository.java @@ -4,7 +4,9 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +@Repository public interface ProjectRepository extends JpaRepository { Page findAll(Pageable pageable); } From 190efda8e10a391a7c3c6b1acb750de5bfb60690 Mon Sep 17 00:00:00 2001 From: suno-boy Date: Fri, 20 Sep 2024 16:59:10 +0900 Subject: [PATCH 17/22] =?UTF-8?q?feat:=20=ED=8C=80=EC=9B=90=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=EC=9D=84=20?= =?UTF-8?q?=EC=9C=84=ED=95=9C=20Entity=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/team1_be/entity/MemberEntity.java | 37 +++++++++++++++++++ .../team1_be/repository/MemberRepository.java | 10 +++++ 2 files changed, 47 insertions(+) create mode 100644 src/main/java/com/example/team1_be/entity/MemberEntity.java create mode 100644 src/main/java/com/example/team1_be/repository/MemberRepository.java diff --git a/src/main/java/com/example/team1_be/entity/MemberEntity.java b/src/main/java/com/example/team1_be/entity/MemberEntity.java new file mode 100644 index 0000000..1a64930 --- /dev/null +++ b/src/main/java/com/example/team1_be/entity/MemberEntity.java @@ -0,0 +1,37 @@ +package com.example.team1_be.entity; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Entity +public class MemberEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String email; + + public MemberEntity(String email) { + this.email = email; + } + public MemberEntity() {} + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} + diff --git a/src/main/java/com/example/team1_be/repository/MemberRepository.java b/src/main/java/com/example/team1_be/repository/MemberRepository.java new file mode 100644 index 0000000..347ee3f --- /dev/null +++ b/src/main/java/com/example/team1_be/repository/MemberRepository.java @@ -0,0 +1,10 @@ +package com.example.team1_be.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.lang.reflect.Member; + +@Repository +public interface MemberRepository extends JpaRepository { +} From ed10a2b504f8b36d3dfcd1d5fbf8bcede769abff Mon Sep 17 00:00:00 2001 From: suno-boy Date: Fri, 20 Sep 2024 17:00:28 +0900 Subject: [PATCH 18/22] =?UTF-8?q?feat:=20=ED=8C=80=EC=9B=90=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EB=B0=8F=20=EB=A7=81=ED=81=AC?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../team1_be/DTO/AttendUrlResponseDTO.java | 13 ++++++++++ .../controller/AttendUrlController.java | 24 +++++++++++++++++++ .../team1_be/controller/MemberController.java | 22 +++++++++++++++++ .../team1_be/service/AttendURLService.java | 14 +++++++++++ .../team1_be/service/MemberService.java | 20 ++++++++++++++++ 5 files changed, 93 insertions(+) create mode 100644 src/main/java/com/example/team1_be/DTO/AttendUrlResponseDTO.java create mode 100644 src/main/java/com/example/team1_be/controller/AttendUrlController.java create mode 100644 src/main/java/com/example/team1_be/controller/MemberController.java create mode 100644 src/main/java/com/example/team1_be/service/AttendURLService.java create mode 100644 src/main/java/com/example/team1_be/service/MemberService.java diff --git a/src/main/java/com/example/team1_be/DTO/AttendUrlResponseDTO.java b/src/main/java/com/example/team1_be/DTO/AttendUrlResponseDTO.java new file mode 100644 index 0000000..c7ff3af --- /dev/null +++ b/src/main/java/com/example/team1_be/DTO/AttendUrlResponseDTO.java @@ -0,0 +1,13 @@ +package com.example.team1_be.DTO; + +public class AttendUrlResponseDTO { + String attendUrl; + + public String getAttendUrl() { + return attendUrl; + } + + public void setAttendUrl(String attendUrl) { + this.attendUrl = attendUrl; + } +} diff --git a/src/main/java/com/example/team1_be/controller/AttendUrlController.java b/src/main/java/com/example/team1_be/controller/AttendUrlController.java new file mode 100644 index 0000000..e9f065d --- /dev/null +++ b/src/main/java/com/example/team1_be/controller/AttendUrlController.java @@ -0,0 +1,24 @@ +package com.example.team1_be.controller; + +import com.example.team1_be.DTO.AttendUrlResponseDTO; +import com.example.team1_be.service.AttendURLService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class AttendUrlController { + + @Autowired + AttendURLService attendURLService; + + @PostMapping("/generate-url") + public ResponseEntity generateUrl() { + + AttendUrlResponseDTO attendUrlResponseDTO = new AttendUrlResponseDTO(); + attendUrlResponseDTO.setAttendUrl(attendURLService.generateAttendURL()); + return ResponseEntity.ok(attendUrlResponseDTO); + + } +} diff --git a/src/main/java/com/example/team1_be/controller/MemberController.java b/src/main/java/com/example/team1_be/controller/MemberController.java new file mode 100644 index 0000000..0f39ca7 --- /dev/null +++ b/src/main/java/com/example/team1_be/controller/MemberController.java @@ -0,0 +1,22 @@ +package com.example.team1_be.controller; + +import com.example.team1_be.service.MemberService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RequestMapping("/Member") +@RestController +public class MemberController { + @Autowired + MemberService memberService; + + @DeleteMapping("/{id}") + public ResponseEntity deleteMember(@PathVariable Long id) { + memberService.deleteMember(id); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/example/team1_be/service/AttendURLService.java b/src/main/java/com/example/team1_be/service/AttendURLService.java new file mode 100644 index 0000000..051a3b0 --- /dev/null +++ b/src/main/java/com/example/team1_be/service/AttendURLService.java @@ -0,0 +1,14 @@ +package com.example.team1_be.service; + +import org.springframework.stereotype.Service; +import java.util.UUID; + +@Service +public class AttendURLService { + + public String generateAttendURL() { + String generatedUrl = "https://example.com/" + UUID.randomUUID().toString(); + return generatedUrl; + } + +} diff --git a/src/main/java/com/example/team1_be/service/MemberService.java b/src/main/java/com/example/team1_be/service/MemberService.java new file mode 100644 index 0000000..fc34ffd --- /dev/null +++ b/src/main/java/com/example/team1_be/service/MemberService.java @@ -0,0 +1,20 @@ +package com.example.team1_be.service; + +import com.example.team1_be.repository.MemberRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class MemberService { + + @Autowired + private final MemberRepository memberRepository; + + public MemberService(MemberRepository memberRepository) { + this.memberRepository = memberRepository; + } + + public void deleteMember(Long id) { + memberRepository.deleteById(id); + } +} From f4fc1a61b46644eef3e10b784671070709fe86d4 Mon Sep 17 00:00:00 2001 From: suno-boy Date: Fri, 20 Sep 2024 17:14:02 +0900 Subject: [PATCH 19/22] =?UTF-8?q?fix:=20=ED=8C=80=EC=9B=90=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20Entity=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/team1_be/repository/MemberRepository.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/team1_be/repository/MemberRepository.java b/src/main/java/com/example/team1_be/repository/MemberRepository.java index 347ee3f..21c7c4e 100644 --- a/src/main/java/com/example/team1_be/repository/MemberRepository.java +++ b/src/main/java/com/example/team1_be/repository/MemberRepository.java @@ -1,10 +1,10 @@ package com.example.team1_be.repository; +import com.example.team1_be.entity.MemberEntity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import java.lang.reflect.Member; @Repository -public interface MemberRepository extends JpaRepository { +public interface MemberRepository extends JpaRepository { } From 19f45f49f8b04cd814defbe343efb6c067d95d5c Mon Sep 17 00:00:00 2001 From: seoyoung-dev Date: Fri, 20 Sep 2024 20:35:56 +0900 Subject: [PATCH 20/22] =?UTF-8?q?feat:=20Task=20Entity=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/team1_be/entity/Task.java | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/main/java/com/example/team1_be/entity/Task.java diff --git a/src/main/java/com/example/team1_be/entity/Task.java b/src/main/java/com/example/team1_be/entity/Task.java new file mode 100644 index 0000000..8dab686 --- /dev/null +++ b/src/main/java/com/example/team1_be/entity/Task.java @@ -0,0 +1,65 @@ +package com.example.team1_be.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +@Entity(name = "task") +public class Task { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "task_id") + private Long id; + + private String content; + + private String name; + + private Integer progress; + + public Task(Long id, String content, String name, Integer progress) { + this.id = id; + this.content = content; + this.name = name; + this.progress = progress; + } + + public Task() { + + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getProgress() { + return progress; + } + + public void setProgress(Integer progress) { + this.progress = progress; + } +} From b3119cac1bb910239429dc25adfc0ffec6527594 Mon Sep 17 00:00:00 2001 From: seoyoung-dev Date: Fri, 20 Sep 2024 20:36:12 +0900 Subject: [PATCH 21/22] =?UTF-8?q?feat:=20TaskDto=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/team1_be/DTO/TaskDto.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/main/java/com/example/team1_be/DTO/TaskDto.java diff --git a/src/main/java/com/example/team1_be/DTO/TaskDto.java b/src/main/java/com/example/team1_be/DTO/TaskDto.java new file mode 100644 index 0000000..0225205 --- /dev/null +++ b/src/main/java/com/example/team1_be/DTO/TaskDto.java @@ -0,0 +1,41 @@ +package com.example.team1_be.DTO; + +public class TaskDto { + + private Long id; + private String content; + private String name; + private Integer progress; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getProgress() { + return progress; + } + + public void setProgress(Integer progress) { + this.progress = progress; + } +} From 71d3b73327d9e6f9c2243aa6bcea32cb3e408f81 Mon Sep 17 00:00:00 2001 From: seoyoung-dev Date: Fri, 20 Sep 2024 20:36:22 +0900 Subject: [PATCH 22/22] =?UTF-8?q?feat:=20Task=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../team1_be/controller/TaskController.java | 21 +++++++++++++++++++ .../team1_be/repository/TaskRepository.java | 11 ++++++++++ .../example/team1_be/service/TaskService.java | 17 +++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 src/main/java/com/example/team1_be/controller/TaskController.java create mode 100644 src/main/java/com/example/team1_be/repository/TaskRepository.java create mode 100644 src/main/java/com/example/team1_be/service/TaskService.java diff --git a/src/main/java/com/example/team1_be/controller/TaskController.java b/src/main/java/com/example/team1_be/controller/TaskController.java new file mode 100644 index 0000000..5eb6b42 --- /dev/null +++ b/src/main/java/com/example/team1_be/controller/TaskController.java @@ -0,0 +1,21 @@ +package com.example.team1_be.controller; + +import com.example.team1_be.service.TaskService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/project") +public class TaskController { + + @Autowired + private TaskService taskService; + + @DeleteMapping("/{project_id}/task/{task_id}") + public void createTask(@PathVariable Long project_id, Long task_id) { + taskService.deleteTask(project_id, task_id); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/team1_be/repository/TaskRepository.java b/src/main/java/com/example/team1_be/repository/TaskRepository.java new file mode 100644 index 0000000..13e1bf8 --- /dev/null +++ b/src/main/java/com/example/team1_be/repository/TaskRepository.java @@ -0,0 +1,11 @@ +package com.example.team1_be.repository; + +import com.example.team1_be.entity.Task; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface TaskRepository extends JpaRepository { + + void deleteById(Long projectId, Long taskId); +} diff --git a/src/main/java/com/example/team1_be/service/TaskService.java b/src/main/java/com/example/team1_be/service/TaskService.java new file mode 100644 index 0000000..73f7652 --- /dev/null +++ b/src/main/java/com/example/team1_be/service/TaskService.java @@ -0,0 +1,17 @@ +package com.example.team1_be.service; + +import com.example.team1_be.repository.TaskRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class TaskService { + + @Autowired + private TaskRepository taskRepository; + + public void deleteTask(Long project_id, Long task_id) { + taskRepository.deleteById(project_id, task_id); + } + +}