Skip to content

Commit

Permalink
Merge pull request #33 from Triumers/develop
Browse files Browse the repository at this point in the history
[Feature] Newsnippet 서비스 구현
  • Loading branch information
moomint8 committed Apr 17, 2024
2 parents 04c9752 + 21a1b9c commit a854826
Show file tree
Hide file tree
Showing 73 changed files with 2,985 additions and 13 deletions.
8 changes: 4 additions & 4 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
### PR 타입(하나 이상의 PR 타입을 선택해주세요)
-[ ] 기능 추가
-[ ] 기능 삭제
-[ ] 버그 수정
-[ ] 의존성, 환경 변수, 빌드 관련 코드 업데이트
- [ ] 기능 추가
- [ ] 기능 삭제
- [ ] 버그 수정
- [ ] 의존성, 환경 변수, 빌드 관련 코드 업데이트

### 반영 브랜치
ex) feat/login -> dev
Expand Down
54 changes: 54 additions & 0 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@

name: Java CI with Gradle

on:
push:
branches: [ "develop" ]
pull_request:
branches: [ "develop" ]

jobs:
build:

runs-on: ubuntu-latest
permissions:
contents: read

steps:
- uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'corretto'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3

- name: Build with Gradle
run: ./gradlew build
env:
DB_URL: DB URL = ${{ secrets.DB_URL }}
DB_USER_NAME: USER = ${{ secrets.DB_USER_NAME }}
DB_PASSWORD: PSW = ${{ secrets.DB_PASSWORD }}


dependency-submission:

runs-on: ubuntu-latest
permissions:
contents: write

steps:
- uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'corretto'
cache: gradle

- name: Generate and submit dependency graph
uses: gradle/actions/dependency-submission@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0


3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ out/

### VS Code ###
.vscode/

### YMl ###
.yml
29 changes: 24 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,34 @@ repositories {
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'

// 편의성 라이브러리
developmentOnly 'org.springframework.boot:spring-boot-devtools'

// Lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'

// SpringSecurity 라이브러리
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'

// JWT
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
implementation 'io.jsonwebtoken:jjwt-impl:0.12.3'
implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3'

// DB 관련 라이브러리
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

// ModelMapper
implementation 'org.modelmapper:modelmapper:3.2.0'
}

tasks.named('test') {
useJUnitPlatform()
jar {
enabled = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.triumers.newsnippetback.Application.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.triumers.newsnippetback.common.exception.InsufficientAuthorityException;
import org.triumers.newsnippetback.domain.aggregate.enums.UserRole;
import org.triumers.newsnippetback.domain.aggregate.vo.ResponseMessageVO;

import java.util.Collection;
import java.util.Iterator;

@RestController
@RequestMapping("/admin")
public class AdminController {

@GetMapping("/health-check")
public ResponseEntity<ResponseMessageVO> healthCheck() {
try {
isAdmin();
} catch (InsufficientAuthorityException e) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ResponseMessageVO(e.getMessage()));
}
return ResponseEntity.status(HttpStatus.OK).body(new ResponseMessageVO("Server is online..."));
}

private void isAdmin() throws InsufficientAuthorityException {

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
Iterator<? extends GrantedAuthority> iter = authorities.iterator();
GrantedAuthority auth = iter.next();
String role = auth.getAuthority();

// System.out.println("사용자 아이디: " + SecurityContextHolder.getContext().getAuthentication().getName());
// System.out.println("사용자 ROLE: " + role);

if (!role.equals(UserRole.ADMIN.name())) {
throw new InsufficientAuthorityException();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package org.triumers.newsnippetback.Application.controller;

import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.triumers.newsnippetback.Application.service.AuthService;
import org.triumers.newsnippetback.common.exception.UserEmailDuplicateException;
import org.triumers.newsnippetback.common.exception.UserNicknameDuplicateException;
import org.triumers.newsnippetback.common.exception.WrongInputTypeException;
import org.triumers.newsnippetback.common.exception.WrongPasswordException;
import org.triumers.newsnippetback.domain.aggregate.enums.Provider;
import org.triumers.newsnippetback.domain.aggregate.vo.RequestModifyPasswordVO;
import org.triumers.newsnippetback.domain.aggregate.vo.RequestUserVO;
import org.triumers.newsnippetback.domain.aggregate.vo.ResponseMessageVO;
import org.triumers.newsnippetback.Application.dto.AuthDTO;
import org.triumers.newsnippetback.Application.dto.PasswordDTO;
import org.triumers.newsnippetback.Application.dto.UserDTO;

@RestController
@RequestMapping("/auth")
public class AuthController {

private final AuthService authService;

@Autowired
public AuthController(AuthService authService) {
this.authService = authService;
}

@PostMapping("/signup")
public ResponseEntity<ResponseMessageVO> signup(@RequestBody RequestUserVO request) {

AuthDTO user = new AuthDTO();

user.setName(request.getName());
user.setNickname(request.getNickname());
user.setEmail(request.getEmail());
user.setPassword(request.getPassword());
user.setProvider(Provider.LOCAL);

try {
authService.signup(user);

} catch (UserNicknameDuplicateException | UserEmailDuplicateException | WrongInputTypeException e) {

return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseMessageVO(e.getMessage()));
}

return ResponseEntity.status(HttpStatus.OK).body(
new ResponseMessageVO(user.getNickname() + "님 회원가입에 성공했습니다."));
}

@PostMapping("/exist/nickname")
public ResponseEntity<ResponseMessageVO> existNickname(@RequestBody RequestUserVO request) {

if (authService.existNickname(request.getNickname())) {

return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseMessageVO("[ERROR] 이미 존재하는 닉네임입니다."));
}

return ResponseEntity.status(HttpStatus.OK).body(new ResponseMessageVO("사용 가능한 닉네임입니다."));
}

@PostMapping("/exist/email")
public ResponseEntity<ResponseMessageVO> existEmail(@RequestBody RequestUserVO request) {

if (authService.existEmail(request.getEmail())) {

return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseMessageVO("[ERROR] 이미 존재하는 이메일입니다."));
}

return ResponseEntity.status(HttpStatus.OK).body(new ResponseMessageVO("사용 가능한 이메일입니다."));
}

@PostMapping("/modify/info")
public ResponseEntity<ResponseMessageVO> modifyUserInfo(@RequestBody RequestUserVO request) {

UserDTO userDTO = new UserDTO();
userDTO.setName(request.getName());
userDTO.setNickname(request.getNickname());

try {
authService.modifyUserInfo(userDTO);

return ResponseEntity.status(HttpStatus.OK).body(new ResponseMessageVO("변경 성공"));
} catch (ExpiredJwtException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseMessageVO("[ERROR] 로그인 이후 이용해주십시오."));
} catch (UserNicknameDuplicateException | WrongInputTypeException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseMessageVO(e.getMessage()));
}
}

@PostMapping("/modify/password")
public ResponseEntity<ResponseMessageVO> modifyPassword(@RequestBody RequestModifyPasswordVO request) {

PasswordDTO passwordDTO = new PasswordDTO(request.getOldPassword(), request.getNewPassword());

try {
authService.modifyPassword(passwordDTO);
return ResponseEntity.status(HttpStatus.OK).body(new ResponseMessageVO("변경 성공"));

} catch (ExpiredJwtException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseMessageVO("[ERROR] 로그인 이후 이용해주십시오."));
} catch (WrongPasswordException | WrongInputTypeException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseMessageVO(e.getMessage()));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.triumers.newsnippetback.Application.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.triumers.newsnippetback.Application.service.ManageService;
import org.triumers.newsnippetback.domain.aggregate.entity.Quiz;
import org.triumers.newsnippetback.Application.dto.CrawlingQuizDTO;
import org.triumers.newsnippetback.Application.dto.QuizDTO;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/manage")
public class ManageController {

private final ManageService manageService;

@Autowired
public ManageController(ManageService manageService) {
this.manageService = manageService;
}

@PostMapping("/findCrawlingQuiz")
public List<CrawlingQuizDTO> findCrawlingQuizList(@RequestBody Map<String, String> params) {
return manageService.selectCrawlingQuizListByDate(LocalDate.parse(params.get("date"),
DateTimeFormatter.ISO_DATE));
}

@GetMapping("/findCrawlingQuiz/{id}")
public CrawlingQuizDTO findCrawlingQuizById(@PathVariable int id){
return manageService.selectCrawlingQuizByID(id);
}

@GetMapping("/addQuiz/{id}")
public ResponseEntity<Quiz> addQuizInList(@PathVariable int id){
Quiz savedQuiz = manageService.insertSelectedQuizById(id);

return ResponseEntity.status(HttpStatus.OK).body(savedQuiz);
}

@GetMapping("/findSelectedQuiz")
public List<QuizDTO> findSelectedQuizList(){
return manageService.selectQuizListByDate(LocalDate.now().plusDays(1));
}

@DeleteMapping("/deleteQuiz/{id}")
public ResponseEntity<QuizDTO> deleteQuizInList(@PathVariable int id){
QuizDTO deletedQuiz = manageService.deleteQuizInListById(id);

return ResponseEntity.status(HttpStatus.OK).body(deletedQuiz);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package org.triumers.newsnippetback.Application.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.triumers.newsnippetback.Application.service.QuizService;
import org.triumers.newsnippetback.domain.aggregate.vo.QuizRequest;
import org.triumers.newsnippetback.domain.aggregate.vo.QuizResponse;
import org.triumers.newsnippetback.Application.dto.QuizDTO;

import java.time.LocalDate;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/quiz")
public class QuizController {

private final QuizService quizService;

@Autowired
public QuizController(QuizService quizService) {
this.quizService = quizService;
}

/* 해당 날짜의 출제되는 문제의 카테고리, 지문, 선택지, 정답률, 정답, 해설, 원본 링크 조회
* ㄴ 문제는 10개씩, 각 날짜마다 1번-10번까지 번호 부여 */
@PostMapping("/test")
public ResponseEntity<List<QuizResponse>> findQuizByDateAndNo(@RequestBody QuizRequest quizRequest) {
try {
LocalDate date = quizRequest.getDate();
List<QuizDTO> quizDTOs = quizService.findAllQuizzesByDate(date);
List<QuizResponse> quizResponses = quizDTOs.stream()
.map(quizDTO -> {
QuizResponse quizResponse = new QuizResponse();
quizResponse.setId(quizDTO.getId());
quizResponse.setNo(quizDTO.getNo());
quizResponse.setContent(quizDTO.getContent());
quizResponse.setOptionA(quizDTO.getOptionA());
quizResponse.setOptionB(quizDTO.getOptionB());
quizResponse.setOptionC(quizDTO.getOptionC());
quizResponse.setOptionD(quizDTO.getOptionD());
quizResponse.setCategoryName(quizDTO.getCategoryName());
quizResponse.setCorrectRate(quizDTO.getCorrectRate());
quizResponse.setAnswer(quizDTO.getAnswer());
quizResponse.setExplanation(quizDTO.getExplanation());
quizResponse.setNewsLink(quizDTO.getNewsLink());
return quizResponse;
})
.collect(Collectors.toList());
return ResponseEntity.ok().body(quizResponses);
} catch (NoSuchElementException e) {
return ResponseEntity.notFound().build();
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}
Loading

0 comments on commit a854826

Please sign in to comment.