Merge branch 'backend' into 'master'
Revert "Merge branch 'Be/Report' into 'backend'" See merge request s11-webmobile1-sub2/S11P12A701!191
This commit is contained in:
commit
464d1558f4
23
backend/.gitlab-ci.yml
Normal file
23
backend/.gitlab-ci.yml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
deploy-to-server:
|
||||||
|
stage: deploy
|
||||||
|
only:
|
||||||
|
- backend
|
||||||
|
before_script:
|
||||||
|
- echo 'start deployment'
|
||||||
|
- whoami
|
||||||
|
script:
|
||||||
|
- cd /home/ubuntu/gitlab_runner/
|
||||||
|
- git pull origin backend
|
||||||
|
- cd backend
|
||||||
|
# - kill $(lsof -t -i:8000)
|
||||||
|
- ./gradlew build
|
||||||
|
# - cd /home/ubuntu/s03p12a112/backend/target/
|
||||||
|
# - setsid nohup java -jar backend-0.0.1-SNAPSHOT.jar > /dev/null 2>&1 &
|
||||||
|
# - cd /home/ubuntu/s03p12a112/frontend/
|
||||||
|
# - sudo npm install
|
||||||
|
# - sudo npm run build
|
||||||
|
# - sudo service nginx restart
|
||||||
|
after_script:
|
||||||
|
- echo 'deployment is done'
|
||||||
|
tags:
|
||||||
|
- edu
|
@ -1,38 +1,50 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'org.springframework.boot' version '3.3.1'
|
id 'org.springframework.boot' version '3.2.7'
|
||||||
id 'io.spring.dependency-management' version '1.1.5'
|
id 'io.spring.dependency-management' version '1.1.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
group = 'com.edufocus'
|
group = 'io.openvidu'
|
||||||
version = '0.0.1-SNAPSHOT'
|
version = '0.0.1-SNAPSHOT'
|
||||||
|
description = 'Basic server application built for Java with Spring Boot'
|
||||||
java {
|
sourceCompatibility = '17'
|
||||||
toolchain {
|
targetCompatibility = '17'
|
||||||
languageVersion = JavaLanguageVersion.of(17)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
configurations {
|
|
||||||
compileOnly {
|
|
||||||
extendsFrom annotationProcessor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||||
compileOnly 'org.projectlombok:lombok'
|
implementation 'org.openpnp:opencv:4.9.0-0'
|
||||||
runtimeOnly 'com.mysql:mysql-connector-j'
|
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||||
annotationProcessor 'org.projectlombok:lombok'
|
implementation 'io.livekit:livekit-server:0.5.11'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||||
|
implementation 'mysql:mysql-connector-java:8.0.33'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-websocket'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-amqp'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-reactor-netty'
|
||||||
|
testImplementation 'org.springframework.amqp:spring-rabbit-test'
|
||||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
implementation group: 'io.livekit', name: 'livekit-server', version: '0.6.1'
|
||||||
|
implementation 'org.projectlombok:lombok'
|
||||||
|
annotationProcessor 'org.projectlombok:lombok'
|
||||||
|
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.4.0'
|
||||||
|
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'
|
||||||
|
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
|
||||||
|
implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5'
|
||||||
|
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-mail', version: '3.2.5'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-mail'
|
||||||
|
implementation 'org.mindrot:jbcrypt:0.4'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
implementation group: 'org.glassfish.jaxb', name: 'jaxb-runtime', version: '4.0.5'
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.named('test') {
|
test {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
}
|
}
|
@ -2,7 +2,11 @@ package com.edufocus.edufocus;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
|
@EnableAsync
|
||||||
|
@EnableJpaAuditing
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class EdufocusApplication {
|
public class EdufocusApplication {
|
||||||
|
|
||||||
|
@ -0,0 +1,139 @@
|
|||||||
|
package com.edufocus.edufocus.board.controller;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.board.entity.dto.*;
|
||||||
|
import com.edufocus.edufocus.board.entity.vo.Board;
|
||||||
|
import com.edufocus.edufocus.board.entity.vo.Comment;
|
||||||
|
import com.edufocus.edufocus.board.service.BoardService;
|
||||||
|
import com.edufocus.edufocus.user.util.JWTUtil;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.validation.constraints.Positive;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Haneol Kim
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/board")
|
||||||
|
public class BoardController {
|
||||||
|
|
||||||
|
private final JWTUtil jwtUtil;
|
||||||
|
private final BoardService boardService;
|
||||||
|
|
||||||
|
public BoardController(BoardService boardService, JWTUtil jwtUtil){
|
||||||
|
this.boardService = boardService;
|
||||||
|
this.jwtUtil = jwtUtil;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping()
|
||||||
|
public ResponseEntity<List<ResponseBoardSummaryDto>> searchBoards(
|
||||||
|
@RequestParam(value = "category", required = false, defaultValue = "announcement") String category,
|
||||||
|
@RequestParam(value = "lectureId") long lectureId,
|
||||||
|
@RequestParam(value = "pageNo", required = false, defaultValue = "0") int pageNo
|
||||||
|
){
|
||||||
|
List<ResponseBoardSummaryDto> boardSummaries = boardService.findBoards(pageNo, category, lectureId);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(boardSummaries, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/{boardId}")
|
||||||
|
public ResponseEntity<ResponseBoardDetailDto> getBoardDetail(
|
||||||
|
@PathVariable int boardId,
|
||||||
|
HttpServletRequest request
|
||||||
|
){
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
|
||||||
|
ResponseBoardDetailDto responseBoardDetailDto = boardService.findBoardDetail(userId, boardId);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(responseBoardDetailDto, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public ResponseEntity<?> addBoard(
|
||||||
|
@RequestBody RequestBoardDto requestBoardDto,
|
||||||
|
HttpServletRequest request
|
||||||
|
){
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
|
||||||
|
boardService.createBoard(userId, requestBoardDto);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping(value = "/{boardId}")
|
||||||
|
public ResponseEntity<?> updateBoard(
|
||||||
|
@PathVariable long boardId,
|
||||||
|
@RequestBody RequestBoardUpdateDto requestBoardUpdateDto
|
||||||
|
){
|
||||||
|
boardService.updateBoard(boardId, requestBoardUpdateDto);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping(value = "/{boardId}")
|
||||||
|
public ResponseEntity<?> deleteBoard(
|
||||||
|
@PathVariable int boardId
|
||||||
|
){
|
||||||
|
boardService.deleteBoard(boardId);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/comment/{boardId}")
|
||||||
|
public ResponseEntity<List<ResponseCommentDto>> getComments(
|
||||||
|
@PathVariable int boardId,
|
||||||
|
HttpServletRequest request
|
||||||
|
){
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
|
||||||
|
List<ResponseCommentDto> comments = boardService.findComments(userId, boardId);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(comments, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/comment/{boardId}")
|
||||||
|
public ResponseEntity<?> addComment(
|
||||||
|
@PathVariable int boardId,
|
||||||
|
@RequestBody RequestCommentDto requestCommentDto,
|
||||||
|
HttpServletRequest request
|
||||||
|
){
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
|
||||||
|
boardService.createComment(userId, boardId, requestCommentDto);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping(value = "/comment/{commentId}")
|
||||||
|
public ResponseEntity<?> updateComment(
|
||||||
|
@PathVariable int commentId,
|
||||||
|
@RequestBody RequestCommentDto requestCommentDto
|
||||||
|
){
|
||||||
|
boardService.updateComment(commentId, requestCommentDto);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping(value = "/comment/{commentId}")
|
||||||
|
public ResponseEntity<?> deleteComment(
|
||||||
|
@PathVariable int commentId
|
||||||
|
){
|
||||||
|
boardService.deleteComment(commentId);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ExceptionHandler()
|
||||||
|
public ResponseEntity<?> NoContentException(Exception e){
|
||||||
|
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.edufocus.edufocus.board.entity.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.board.entity.vo.Board;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class RequestBoardDto {
|
||||||
|
private long lectureId;
|
||||||
|
private String title;
|
||||||
|
private String category;
|
||||||
|
private String content;
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.edufocus.edufocus.board.entity.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class RequestBoardUpdateDto {
|
||||||
|
private String title;
|
||||||
|
private String content;
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.edufocus.edufocus.board.entity.dto;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class RequestCommentDto {
|
||||||
|
private String content;
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.edufocus.edufocus.board.entity.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ResponseBoardDetailDto {
|
||||||
|
private long id;
|
||||||
|
private String name;
|
||||||
|
private String title;
|
||||||
|
private String content;
|
||||||
|
private boolean isMine;
|
||||||
|
private Date createdAt;
|
||||||
|
private Date modifiedAt;
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.edufocus.edufocus.board.entity.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ResponseBoardSummaryDto {
|
||||||
|
private long id;
|
||||||
|
private String name;
|
||||||
|
private String title;
|
||||||
|
private Date createdAt;
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.edufocus.edufocus.board.entity.dto;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ResponseCommentDto {
|
||||||
|
private long id;
|
||||||
|
private String name;
|
||||||
|
private String content;
|
||||||
|
private boolean isMine;
|
||||||
|
private Date createAt;
|
||||||
|
private Date modifiedAt;
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
package com.edufocus.edufocus.board.entity.vo;
|
||||||
|
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.board.entity.dto.ResponseBoardDetailDto;
|
||||||
|
import com.edufocus.edufocus.board.entity.dto.ResponseBoardSummaryDto;
|
||||||
|
import com.edufocus.edufocus.lecture.entity.Lecture;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.User;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
|
import org.hibernate.annotations.OnDelete;
|
||||||
|
import org.hibernate.annotations.OnDeleteAction;
|
||||||
|
import org.hibernate.annotations.UpdateTimestamp;
|
||||||
|
import org.springframework.data.annotation.CreatedDate;
|
||||||
|
import org.springframework.data.annotation.LastModifiedDate;
|
||||||
|
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Setter
|
||||||
|
@EntityListeners(AuditingEntityListener.class)
|
||||||
|
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
|
||||||
|
public class Board {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String category;
|
||||||
|
|
||||||
|
@Column(columnDefinition = "TEXT", nullable = false)
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
@Column(nullable = true)
|
||||||
|
private int viewCount;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@CreationTimestamp
|
||||||
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
|
private Date createdAt;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@UpdateTimestamp
|
||||||
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
|
private Date modifiedAt;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "user_id")
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "lecture_id")
|
||||||
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
|
private Lecture lecture;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "board")
|
||||||
|
private List<Comment> comments;
|
||||||
|
|
||||||
|
public ResponseBoardSummaryDto makeSummaryDto() {
|
||||||
|
return ResponseBoardSummaryDto.builder()
|
||||||
|
.id(id)
|
||||||
|
.title(title)
|
||||||
|
.name(user.getName())
|
||||||
|
.createdAt(createdAt)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResponseBoardDetailDto makeDetailDto(long userId) {
|
||||||
|
return ResponseBoardDetailDto.builder()
|
||||||
|
.id(id)
|
||||||
|
.name(user.getName())
|
||||||
|
.title(title)
|
||||||
|
.content(content)
|
||||||
|
.isMine(user.getId() == userId)
|
||||||
|
.createdAt(createdAt)
|
||||||
|
.modifiedAt(modifiedAt)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
package com.edufocus.edufocus.board.entity.vo;
|
||||||
|
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.board.entity.dto.ResponseCommentDto;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.User;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
|
import org.hibernate.annotations.OnDelete;
|
||||||
|
import org.hibernate.annotations.OnDeleteAction;
|
||||||
|
import org.hibernate.annotations.UpdateTimestamp;
|
||||||
|
import org.springframework.data.annotation.CreatedDate;
|
||||||
|
import org.springframework.data.annotation.LastModifiedDate;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Setter
|
||||||
|
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
|
||||||
|
public class Comment {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@Column(columnDefinition = "TEXT", nullable = false)
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@CreationTimestamp
|
||||||
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
|
private Date createdAt;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
|
private Date modifiedAt;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "user_id")
|
||||||
|
User user;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "board_id")
|
||||||
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
|
Board board;
|
||||||
|
|
||||||
|
public ResponseCommentDto makeCommentDto(long userId) {
|
||||||
|
return ResponseCommentDto.builder()
|
||||||
|
.id(id)
|
||||||
|
.name(user.getName())
|
||||||
|
.content(content)
|
||||||
|
.isMine(user.getId() == userId)
|
||||||
|
.createAt(createdAt)
|
||||||
|
.modifiedAt(modifiedAt)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.edufocus.edufocus.board.repository;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.board.entity.vo.Board;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
|
||||||
|
|
||||||
|
public interface BoardRepository extends JpaRepository<Board, Long> {
|
||||||
|
|
||||||
|
@Query("select b from Board b join fetch b.user where b.category =:category and b.lecture.id=:lectureId")
|
||||||
|
Page<Board> findByLectureIdAndCategory(Long lectureId, String category, Pageable pageable);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.edufocus.edufocus.board.repository;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.board.entity.vo.Comment;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface CommentRepository extends JpaRepository<Comment, Long> {
|
||||||
|
|
||||||
|
@Query("select c from Comment c join fetch c.user where c.board.id =:boardId")
|
||||||
|
List<Comment> findByBoardId(long boardId);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.edufocus.edufocus.board.service;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.board.entity.dto.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface BoardService {
|
||||||
|
|
||||||
|
public void createBoard(long userId, RequestBoardDto requestBoardDto);
|
||||||
|
|
||||||
|
public List<ResponseBoardSummaryDto> findBoards(int pageNo, String category, long lectureId);
|
||||||
|
|
||||||
|
public ResponseBoardDetailDto findBoardDetail(long userId, long boardId);
|
||||||
|
|
||||||
|
public void updateBoard(long boardId, RequestBoardUpdateDto requestBoardUpdateDto);
|
||||||
|
|
||||||
|
public void deleteBoard(long boardId);
|
||||||
|
|
||||||
|
public void createComment(long userId, long boardId, RequestCommentDto requestCommentDto);
|
||||||
|
|
||||||
|
public List<ResponseCommentDto> findComments(long userId, long boardId);
|
||||||
|
|
||||||
|
public void updateComment(long commentId, RequestCommentDto requestCommentDto);
|
||||||
|
|
||||||
|
public void deleteComment(long commentId);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,132 @@
|
|||||||
|
package com.edufocus.edufocus.board.service;
|
||||||
|
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.board.entity.dto.*;
|
||||||
|
import com.edufocus.edufocus.board.entity.vo.Board;
|
||||||
|
import com.edufocus.edufocus.board.entity.vo.Comment;
|
||||||
|
import com.edufocus.edufocus.board.repository.BoardRepository;
|
||||||
|
import com.edufocus.edufocus.board.repository.CommentRepository;
|
||||||
|
import com.edufocus.edufocus.lecture.entity.Lecture;
|
||||||
|
import com.edufocus.edufocus.lecture.repository.LectureRepository;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.User;
|
||||||
|
import com.edufocus.edufocus.user.model.repository.UserRepository;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class BoardServiceImpl implements BoardService {
|
||||||
|
|
||||||
|
private static final int PAGE_SIZE = 10;
|
||||||
|
|
||||||
|
private final BoardRepository boardRepository;
|
||||||
|
private final CommentRepository commentRepository;
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
private final LectureRepository lectureRepository;
|
||||||
|
|
||||||
|
public BoardServiceImpl(BoardRepository boardRepository, CommentRepository commentRepository, UserRepository userRepository, LectureRepository lectureRepository){
|
||||||
|
this.boardRepository = boardRepository;
|
||||||
|
this.commentRepository = commentRepository;
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
this.lectureRepository = lectureRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public List<ResponseBoardSummaryDto> findBoards(int pageNo, String category, long lectureId) {
|
||||||
|
Pageable pageable = PageRequest.of(pageNo, PAGE_SIZE, Sort.by("id").descending());
|
||||||
|
|
||||||
|
List<Board> boards = boardRepository.findByLectureIdAndCategory(lectureId, category, pageable).getContent();
|
||||||
|
|
||||||
|
return boards.stream().map(Board::makeSummaryDto)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public ResponseBoardDetailDto findBoardDetail(long userId, long boardId) {
|
||||||
|
return boardRepository.findById(boardId)
|
||||||
|
.orElseThrow(NoSuchElementException::new)
|
||||||
|
.makeDetailDto(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void createBoard(long userId, RequestBoardDto requestBoardDto) {
|
||||||
|
User user = userRepository.getReferenceById(userId);
|
||||||
|
Lecture lecture = lectureRepository.getReferenceById(requestBoardDto.getLectureId());
|
||||||
|
|
||||||
|
Board board = Board.builder()
|
||||||
|
.title(requestBoardDto.getTitle())
|
||||||
|
.category(requestBoardDto.getCategory())
|
||||||
|
.content(requestBoardDto.getContent())
|
||||||
|
.user(user)
|
||||||
|
.lecture(lecture)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
boardRepository.save(board);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void updateBoard(long boardId, RequestBoardUpdateDto requestBoardUpdateDto) {
|
||||||
|
Board board = boardRepository.getReferenceById(boardId);
|
||||||
|
|
||||||
|
board.setTitle(requestBoardUpdateDto.getTitle());
|
||||||
|
board.setContent(requestBoardUpdateDto.getContent());
|
||||||
|
|
||||||
|
boardRepository.save(board);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void deleteBoard(long boardId) {
|
||||||
|
Board board = boardRepository.getReferenceById(boardId);
|
||||||
|
|
||||||
|
boardRepository.delete(board);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public List<ResponseCommentDto> findComments(long userId, long boardId) {
|
||||||
|
return commentRepository.findByBoardId(boardId).stream()
|
||||||
|
.map((Comment c) -> c.makeCommentDto(userId))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void createComment(long userId, long boardId, RequestCommentDto requestCommentDto) {
|
||||||
|
User user = userRepository.getReferenceById(userId);
|
||||||
|
Board board = boardRepository.getReferenceById(boardId);
|
||||||
|
|
||||||
|
Comment comment = Comment.builder()
|
||||||
|
.content(requestCommentDto.getContent())
|
||||||
|
.board(board)
|
||||||
|
.user(user)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
commentRepository.save(comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void updateComment(long commentId, RequestCommentDto requestCommentDto) {
|
||||||
|
Comment comment = commentRepository.getReferenceById(commentId);
|
||||||
|
|
||||||
|
comment.setContent(requestCommentDto.getContent());
|
||||||
|
|
||||||
|
commentRepository.save(comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void deleteComment(long commentId) {
|
||||||
|
Comment comment = commentRepository.getReferenceById(commentId);
|
||||||
|
|
||||||
|
commentRepository.delete(comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.edufocus.edufocus.global.config;
|
||||||
|
|
||||||
|
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.AsyncConfigurer;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebMvc
|
||||||
|
public class AsyncConfig implements AsyncConfigurer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Bean(name = "mailExecutor")
|
||||||
|
public Executor getAsyncExecutor() {
|
||||||
|
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||||
|
executor.setCorePoolSize(5);
|
||||||
|
executor.setMaxPoolSize(10);
|
||||||
|
executor.setQueueCapacity(500);
|
||||||
|
executor.setThreadNamePrefix("MailExecutor-");
|
||||||
|
executor.initialize();
|
||||||
|
return executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
|
||||||
|
return AsyncConfigurer.super.getAsyncUncaughtExceptionHandler();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.edufocus.edufocus.global.config;
|
||||||
|
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.global.properties.ImagePathProperties;
|
||||||
|
import com.edufocus.edufocus.global.properties.MailProperties;
|
||||||
|
import com.edufocus.edufocus.global.properties.RabbitMQProperties;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties({
|
||||||
|
RabbitMQProperties.class,
|
||||||
|
ImagePathProperties.class,
|
||||||
|
MailProperties.class
|
||||||
|
})
|
||||||
|
public class PropertiesConfig {
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.edufocus.edufocus.global.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class RedisConfig {
|
||||||
|
|
||||||
|
@Value("${spring.data.redis.host}")
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
@Value("${spring.data.redis.port}")
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RedisConnectionFactory redisConnectionFactory() {
|
||||||
|
return new LettuceConnectionFactory(host, port);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.edufocus.edufocus.global.constant;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public enum RabbitMQConstant {
|
||||||
|
|
||||||
|
CHAT_QUEUE_NAME("chat.queue"),
|
||||||
|
CHAT_EXCHANGE("chat.exchange"),
|
||||||
|
ROUTING_KEY("*.room.*"),
|
||||||
|
ROUTING_KEY_PREFIX("*.room.");;
|
||||||
|
private final String constant;
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.edufocus.edufocus.global.properties;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@ConfigurationProperties(prefix = "image")
|
||||||
|
public class ImagePathProperties {
|
||||||
|
private final String path;
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.edufocus.edufocus.global.properties;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@ConfigurationProperties(prefix = "spring.mail")
|
||||||
|
public class MailProperties {
|
||||||
|
private final String host;
|
||||||
|
private final Integer port;
|
||||||
|
private final String name;
|
||||||
|
private final String password;
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.edufocus.edufocus.global.properties;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@ConfigurationProperties(prefix = "spring.rabbitmq")
|
||||||
|
public class RabbitMQProperties {
|
||||||
|
private final String host;
|
||||||
|
private final Integer port;
|
||||||
|
private final String username;
|
||||||
|
private final String password;
|
||||||
|
}
|
@ -0,0 +1,107 @@
|
|||||||
|
package com.edufocus.edufocus.lecture.controller;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.lecture.entity.Lecture;
|
||||||
|
import com.edufocus.edufocus.lecture.entity.LectureCreateRequest;
|
||||||
|
import com.edufocus.edufocus.lecture.entity.LectureSearchResponse;
|
||||||
|
import com.edufocus.edufocus.lecture.entity.LectureDetailResponse;
|
||||||
|
import com.edufocus.edufocus.lecture.service.LectureService;
|
||||||
|
import com.edufocus.edufocus.user.util.JWTUtil;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/lecture")
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class LectureController {
|
||||||
|
|
||||||
|
private final LectureService lectureService;
|
||||||
|
private final JWTUtil jwtUtil;
|
||||||
|
|
||||||
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
|
public ResponseEntity<?> createLecture(@RequestHeader("Authorization") String accessToken, @RequestPart LectureCreateRequest lectureCreateRequest
|
||||||
|
, @RequestPart(value = "image", required = false) MultipartFile image) throws Exception {
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
|
||||||
|
|
||||||
|
Lecture lecture = lectureService.findLectureByTitle(lectureCreateRequest.getTitle());
|
||||||
|
if (lecture != null) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.CONFLICT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image != null && !image.getContentType().startsWith("image")) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
lectureService.createLecture(userId, lectureCreateRequest, image);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.CREATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{lectureId}")
|
||||||
|
public ResponseEntity<?> updateLecture(@RequestHeader("Authorization") String accessToken, @PathVariable Long lectureId, @RequestBody LectureCreateRequest lectureCreateRequest) {
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
|
||||||
|
|
||||||
|
if (!lectureService.updateLecture(userId, lectureId, lectureCreateRequest)) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@DeleteMapping("/{lectureId}")
|
||||||
|
public ResponseEntity<?> deleteLecture(@RequestHeader("Authorization") String accessToken, @PathVariable long lectureId) {
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
|
||||||
|
|
||||||
|
if (!lectureService.deleteLecture(userId, lectureId)) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public ResponseEntity<?> findAllLecture() {
|
||||||
|
List<LectureSearchResponse> lectures = lectureService.findAllLecture();
|
||||||
|
|
||||||
|
return new ResponseEntity<>(lectures, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{lectureId}")
|
||||||
|
public ResponseEntity<?> findById(@RequestHeader(value = "Authorization", required = false) String accessToken, @PathVariable long lectureId) {
|
||||||
|
Long userId = null;
|
||||||
|
|
||||||
|
if (accessToken != null) {
|
||||||
|
userId = Long.parseLong(jwtUtil.getUserId(accessToken));
|
||||||
|
}
|
||||||
|
LectureDetailResponse lectureDetailResponse = lectureService.findLectureById(userId, lectureId);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(lectureDetailResponse, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/mylecture")
|
||||||
|
public ResponseEntity<?> findMyLecture(@RequestHeader(value = "Authorization", required = false) String accessToken) {
|
||||||
|
|
||||||
|
if (accessToken == null) {
|
||||||
|
return new ResponseEntity<>(new ArrayList<>(), HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
|
||||||
|
|
||||||
|
List<LectureSearchResponse> myLectures = lectureService.findMyLecture(userId);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(myLectures, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/isLive/{lectureId}")
|
||||||
|
public ResponseEntity<Boolean> checkIsLive(@PathVariable long lectureId) {
|
||||||
|
return new ResponseEntity<>(lectureService.getState(lectureId), HttpStatus.OK);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package com.edufocus.edufocus.lecture.entity;
|
||||||
|
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.User;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Lecture {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "user_id")
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@Column(columnDefinition = "text")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@Column(columnDefinition = "text")
|
||||||
|
private String plan;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String image;
|
||||||
|
|
||||||
|
@Column(name = "start_date")
|
||||||
|
@Temporal(TemporalType.DATE)
|
||||||
|
private Date startDate;
|
||||||
|
|
||||||
|
@Column(name = "end_date")
|
||||||
|
@Temporal(TemporalType.DATE)
|
||||||
|
private Date endDate;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String time;
|
||||||
|
|
||||||
|
@Column(columnDefinition = "boolean default false")
|
||||||
|
private boolean online;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.edufocus.edufocus.lecture.entity;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class LectureCreateRequest {
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
private String plan;
|
||||||
|
|
||||||
|
private Date startDate;
|
||||||
|
|
||||||
|
private Date endDate;
|
||||||
|
|
||||||
|
private String time;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.edufocus.edufocus.lecture.entity;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class LectureDetailResponse {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String teacherName;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
private String plan;
|
||||||
|
|
||||||
|
private String image;
|
||||||
|
|
||||||
|
private Date startDate;
|
||||||
|
|
||||||
|
private Date endDate;
|
||||||
|
|
||||||
|
private String time;
|
||||||
|
|
||||||
|
private boolean online;
|
||||||
|
|
||||||
|
private String status;
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.edufocus.edufocus.lecture.entity;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class LectureSearchResponse {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String image;
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.edufocus.edufocus.lecture.entity;
|
||||||
|
|
||||||
|
public enum UserStatus {
|
||||||
|
MANAGED_BY_ME, // 내가 관리하는 강의 - 강사
|
||||||
|
MANAGED_BY_OTHERS, // 내가 관리하지 않은 강의 - 강사
|
||||||
|
ENROLLED, // 내가 수강 중인 강의 - 학생
|
||||||
|
PENDING, // 내가 수강신청하고 승인 대기 중인 강의 - 학생
|
||||||
|
NOT_ENROLLED // 내가 수강신청하지 않은 강의 - 학생/비로그인
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.edufocus.edufocus.lecture.repository;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.lecture.entity.Lecture;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface LectureRepository extends JpaRepository<Lecture, Long> {
|
||||||
|
Lecture findByTitle(String title);
|
||||||
|
|
||||||
|
List<Lecture> findAllByUserId(Long userId);
|
||||||
|
|
||||||
|
List<Lecture> findLecturesByUserIdOrderById(Long userId);
|
||||||
|
|
||||||
|
Lecture findByIdAndUserId(long id, long userId);
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.edufocus.edufocus.lecture.service;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.lecture.entity.Lecture;
|
||||||
|
import com.edufocus.edufocus.lecture.entity.LectureCreateRequest;
|
||||||
|
import com.edufocus.edufocus.lecture.entity.LectureSearchResponse;
|
||||||
|
import com.edufocus.edufocus.lecture.entity.LectureDetailResponse;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public interface LectureService {
|
||||||
|
|
||||||
|
void createLecture(long userId, LectureCreateRequest lectureCreateRequest, MultipartFile image) throws Exception;
|
||||||
|
|
||||||
|
boolean updateLecture(long userId, long lectureId, LectureCreateRequest lectureCreateRequest);
|
||||||
|
|
||||||
|
boolean deleteLecture(long userId, long LectureId);
|
||||||
|
|
||||||
|
List<LectureSearchResponse> findAllLecture();
|
||||||
|
|
||||||
|
String getUserStatus(Long userId, Lecture lecture);
|
||||||
|
|
||||||
|
LectureDetailResponse findLectureById(Long userId, long lectureId);
|
||||||
|
|
||||||
|
List<LectureSearchResponse> findMyLecture(long userId);
|
||||||
|
|
||||||
|
Lecture findLectureByTitle(String title);
|
||||||
|
|
||||||
|
void startClass(Long lectureId);
|
||||||
|
|
||||||
|
void stopClass(Long lectureId);
|
||||||
|
|
||||||
|
boolean getState(Long lectureId);
|
||||||
|
|
||||||
|
boolean checkTeacher(Long userId, Long lectureId);
|
||||||
|
}
|
@ -0,0 +1,302 @@
|
|||||||
|
package com.edufocus.edufocus.lecture.service;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.global.properties.ImagePathProperties;
|
||||||
|
import com.edufocus.edufocus.lecture.entity.*;
|
||||||
|
import com.edufocus.edufocus.lecture.repository.LectureRepository;
|
||||||
|
import com.edufocus.edufocus.registration.entity.Registration;
|
||||||
|
import com.edufocus.edufocus.registration.entity.RegistrationStatus;
|
||||||
|
import com.edufocus.edufocus.registration.repository.RegistrationRepository;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.User;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.UserRole;
|
||||||
|
import com.edufocus.edufocus.user.model.repository.UserRepository;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class LectureServiceImpl implements LectureService {
|
||||||
|
|
||||||
|
private final ImagePathProperties imagePathProperties;
|
||||||
|
|
||||||
|
private final LectureRepository lectureRepository;
|
||||||
|
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
private final RegistrationRepository registrationRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createLecture(long userId, LectureCreateRequest lectureCreateRequest, MultipartFile image) throws IOException {
|
||||||
|
User user = userRepository.findById(userId).orElse(null);
|
||||||
|
|
||||||
|
Lecture lecture = Lecture.builder()
|
||||||
|
.user(user)
|
||||||
|
.title(lectureCreateRequest.getTitle())
|
||||||
|
.description(lectureCreateRequest.getDescription())
|
||||||
|
.plan(lectureCreateRequest.getPlan())
|
||||||
|
.startDate(lectureCreateRequest.getStartDate())
|
||||||
|
.endDate(lectureCreateRequest.getEndDate())
|
||||||
|
.time(lectureCreateRequest.getTime())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if (image != null) {
|
||||||
|
String uid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
String imagePath = imagePathProperties.getPath();
|
||||||
|
|
||||||
|
File checkPathFile = new File(imagePath);
|
||||||
|
if (!checkPathFile.exists()) {
|
||||||
|
checkPathFile.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
File savingImage = new File(imagePath + "/" + uid + "_" + image.getOriginalFilename());
|
||||||
|
image.transferTo(savingImage.toPath());
|
||||||
|
String savePath = savingImage.toPath().toString();
|
||||||
|
|
||||||
|
lecture.setImage(savePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
lectureRepository.save(lecture);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean updateLecture(long userId, long lectureId, LectureCreateRequest lectureCreateRequest) {
|
||||||
|
Optional<Lecture> findLecture = lectureRepository.findById(lectureId);
|
||||||
|
|
||||||
|
if (findLecture.isEmpty() || findLecture.get().getUser().getId() != userId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Lecture lecture = findLecture.get();
|
||||||
|
|
||||||
|
if (lectureCreateRequest.getTitle() != null) {
|
||||||
|
lecture.setTitle(lectureCreateRequest.getTitle());
|
||||||
|
}
|
||||||
|
if (lectureCreateRequest.getDescription() != null) {
|
||||||
|
lecture.setDescription(lectureCreateRequest.getDescription());
|
||||||
|
}
|
||||||
|
if (lectureCreateRequest.getPlan() != null) {
|
||||||
|
lecture.setPlan(lectureCreateRequest.getPlan());
|
||||||
|
}
|
||||||
|
if (lectureCreateRequest.getStartDate() != null) {
|
||||||
|
lecture.setStartDate(lectureCreateRequest.getStartDate());
|
||||||
|
}
|
||||||
|
if (lectureCreateRequest.getEndDate() != null) {
|
||||||
|
lecture.setEndDate(lectureCreateRequest.getEndDate());
|
||||||
|
}
|
||||||
|
if (lectureCreateRequest.getTime() != null) {
|
||||||
|
lecture.setTime(lectureCreateRequest.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
lectureRepository.save(lecture);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteLecture(long userId, long lectureId) {
|
||||||
|
Optional<Lecture> findLecture = lectureRepository.findById(lectureId);
|
||||||
|
|
||||||
|
if (findLecture.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Lecture lecture = findLecture.get();
|
||||||
|
|
||||||
|
if (lecture.getUser().getId() != userId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String image = lecture.getImage();
|
||||||
|
if (image != null) {
|
||||||
|
File file = new File(lecture.getImage());
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
lectureRepository.deleteById(lectureId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<LectureSearchResponse> findAllLecture() {
|
||||||
|
List<Lecture> lectureList = lectureRepository.findAll(Sort.by(Sort.Direction.DESC, "id"));
|
||||||
|
|
||||||
|
List<LectureSearchResponse> lectureSearchResponseList = new ArrayList<>();
|
||||||
|
for (Lecture lecture : lectureList) {
|
||||||
|
LectureSearchResponse lectureSearchResponse = LectureSearchResponse.builder()
|
||||||
|
.id(lecture.getId())
|
||||||
|
.title(lecture.getTitle())
|
||||||
|
.image(lecture.getImage()).build();
|
||||||
|
|
||||||
|
lectureSearchResponseList.add(lectureSearchResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lectureSearchResponseList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserStatus(Long userId, Lecture lecture) {
|
||||||
|
if (userId == null) {
|
||||||
|
return String.valueOf(UserStatus.NOT_ENROLLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = userRepository.findById(userId).orElseThrow(NoSuchElementException::new);
|
||||||
|
UserRole userRole = user.getRole();
|
||||||
|
|
||||||
|
if (userRole == UserRole.ADMIN) {
|
||||||
|
if (lecture.getUser() == user) {
|
||||||
|
return String.valueOf(UserStatus.MANAGED_BY_ME);
|
||||||
|
}
|
||||||
|
return String.valueOf(UserStatus.MANAGED_BY_OTHERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Registration registration = registrationRepository.findByUserIdAndLectureId(userId, lecture.getId());
|
||||||
|
|
||||||
|
if (registration == null) {
|
||||||
|
return String.valueOf(UserStatus.NOT_ENROLLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registration.getStatus() == RegistrationStatus.ACCEPTED) {
|
||||||
|
return String.valueOf(UserStatus.ENROLLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.valueOf(UserStatus.PENDING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LectureDetailResponse findLectureById(Long userId, long lectureId) {
|
||||||
|
Lecture lecture = lectureRepository.findById(lectureId).orElseThrow(NoSuchElementException::new);
|
||||||
|
|
||||||
|
String userStatus = getUserStatus(userId, lecture);
|
||||||
|
|
||||||
|
return LectureDetailResponse.builder()
|
||||||
|
.id(lecture.getId())
|
||||||
|
.title(lecture.getTitle())
|
||||||
|
.description(lecture.getDescription())
|
||||||
|
.plan(lecture.getPlan())
|
||||||
|
.image(lecture.getImage())
|
||||||
|
.startDate(lecture.getStartDate())
|
||||||
|
.endDate(lecture.getEndDate())
|
||||||
|
.time(lecture.getTime())
|
||||||
|
.online(lecture.isOnline())
|
||||||
|
.teacherName(lecture.getUser().getName())
|
||||||
|
.status(userStatus)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<LectureSearchResponse> findMyLecture(long userId) {
|
||||||
|
User user = userRepository.findById(userId).orElseThrow(NoSuchElementException::new);
|
||||||
|
|
||||||
|
List<LectureSearchResponse> myLectureList = new ArrayList<>();
|
||||||
|
|
||||||
|
if (user.getRole() == UserRole.ADMIN) {
|
||||||
|
List<Lecture> lectureList = lectureRepository.findLecturesByUserIdOrderById(userId);
|
||||||
|
for (Lecture lecture : lectureList) {
|
||||||
|
LectureSearchResponse lectureSearchResponse = LectureSearchResponse.builder()
|
||||||
|
.id(lecture.getId())
|
||||||
|
.title(lecture.getTitle())
|
||||||
|
.image(lecture.getImage()).build();
|
||||||
|
|
||||||
|
myLectureList.add(lectureSearchResponse);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
List<Registration> registrationList = registrationRepository.findAllByUserId(userId);
|
||||||
|
|
||||||
|
for (Registration registration : registrationList) {
|
||||||
|
Lecture lecture = registration.getLecture();
|
||||||
|
|
||||||
|
if (registration.getStatus() == RegistrationStatus.ACCEPTED) {
|
||||||
|
LectureSearchResponse lectureSearchResponse = LectureSearchResponse.builder()
|
||||||
|
.id(lecture.getId())
|
||||||
|
.title(lecture.getTitle())
|
||||||
|
.image(lecture.getImage()).build();
|
||||||
|
|
||||||
|
myLectureList.add(lectureSearchResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(myLectureList, new Comparator<LectureSearchResponse>() {
|
||||||
|
@Override
|
||||||
|
public int compare(LectureSearchResponse lsr1, LectureSearchResponse lsr2) {
|
||||||
|
long lsr1Id = lsr1.getId();
|
||||||
|
long lsr2Id = lsr2.getId();
|
||||||
|
if (lsr2Id > lsr1Id)
|
||||||
|
return 1;
|
||||||
|
else if (lsr2Id == lsr1Id)
|
||||||
|
return 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return myLectureList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Lecture findLectureByTitle(String title) {
|
||||||
|
return lectureRepository.findByTitle(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startClass(Long id) {
|
||||||
|
|
||||||
|
Optional<Lecture> lecture = lectureRepository.findById(id);
|
||||||
|
|
||||||
|
|
||||||
|
if (!lecture.isPresent()) {
|
||||||
|
throw new RuntimeException("Lecture not found with id: " + id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Lecture l;
|
||||||
|
l = lecture.get();
|
||||||
|
if (l.isOnline() == false) {
|
||||||
|
l.setOnline(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lectureRepository.save(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopClass(Long id) {
|
||||||
|
Optional<Lecture> lecture = lectureRepository.findById(id);
|
||||||
|
|
||||||
|
|
||||||
|
if (!lecture.isPresent()) {
|
||||||
|
throw new RuntimeException("Lecture not found with id: " + id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Lecture l;
|
||||||
|
l = lecture.get();
|
||||||
|
if (l.isOnline()) {
|
||||||
|
l.setOnline(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lectureRepository.save(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getState(Long lectureId) {
|
||||||
|
|
||||||
|
Lecture lecture = lectureRepository.findById(lectureId).orElse(null);
|
||||||
|
return lecture.isOnline();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkTeacher(Long userId, Long lectureId) {
|
||||||
|
Optional<Lecture> lecture = lectureRepository.findById(lectureId);
|
||||||
|
|
||||||
|
return lecture.isPresent() && lecture.get().getUser().getId() == userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.edufocus.edufocus.mail.controller;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.mail.service.MailService;
|
||||||
|
import com.edufocus.edufocus.user.model.service.UserService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/mail")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MailController {
|
||||||
|
|
||||||
|
private final MailService mailService;
|
||||||
|
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
|
@PostMapping("/sendcode")
|
||||||
|
public ResponseEntity<?> sendMail(@RequestParam String email) {
|
||||||
|
if (!userService.isEmailExist(email)) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
mailService.sendMail(email);
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/verify")
|
||||||
|
public ResponseEntity<?> verifyCode(@RequestParam String code, @RequestParam String email) {
|
||||||
|
if (!mailService.verifyCode(code, email)) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.edufocus.edufocus.mail.service;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public interface MailService {
|
||||||
|
|
||||||
|
void sendMail(String to);
|
||||||
|
|
||||||
|
String createRandomCode();
|
||||||
|
|
||||||
|
boolean verifyCode(String code, String email);
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
package com.edufocus.edufocus.mail.service;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.redis.util.RedisUtil;
|
||||||
|
import com.edufocus.edufocus.user.model.repository.UserRepository;
|
||||||
|
import com.edufocus.edufocus.user.model.service.UserService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.mail.SimpleMailMessage;
|
||||||
|
import org.springframework.mail.javamail.JavaMailSender;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
@ToString
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MailServiceImpl implements MailService {
|
||||||
|
|
||||||
|
private final JavaMailSender mailSender;
|
||||||
|
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
|
private final RedisUtil redisUtil;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Async("mailExecutor")
|
||||||
|
public void sendMail(String email) {
|
||||||
|
String code = createRandomCode();
|
||||||
|
|
||||||
|
if (redisUtil.exists(email)) {
|
||||||
|
redisUtil.deleteData(redisUtil.getData(email));
|
||||||
|
}
|
||||||
|
|
||||||
|
redisUtil.setDataExpire(code, email, 60 * 5L);
|
||||||
|
redisUtil.setDataExpire(email, code, 60 * 5L);
|
||||||
|
|
||||||
|
SimpleMailMessage mail = createEmail(email, "[EDUFOCUS] 비밀번호 찾기 안내", code);
|
||||||
|
mailSender.send(mail);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean verifyCode(String code, String email) {
|
||||||
|
String registedEmail = redisUtil.getData(code);
|
||||||
|
|
||||||
|
return registedEmail != null && registedEmail.equals(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SimpleMailMessage createEmail(String to, String title, String code) {
|
||||||
|
SimpleMailMessage message = new SimpleMailMessage();
|
||||||
|
message.setFrom("EDUFOCUS");
|
||||||
|
message.setTo(to);
|
||||||
|
message.setSubject(title);
|
||||||
|
message.setText("인증번호 6자리입니다 : " + code);
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createRandomCode() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
Random random = new Random();
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
sb.append((char) (random.nextInt(26) + 65));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
sb.append(random.nextInt(10));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,157 @@
|
|||||||
|
package com.edufocus.edufocus.qna.controller;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.qna.entity.Qna;
|
||||||
|
import com.edufocus.edufocus.qna.entity.QnaRequestDto;
|
||||||
|
import com.edufocus.edufocus.qna.entity.QnaResponseDto;
|
||||||
|
import com.edufocus.edufocus.qna.service.QnaService;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.User;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.UserRole;
|
||||||
|
import com.edufocus.edufocus.user.model.repository.UserRepository;
|
||||||
|
import com.edufocus.edufocus.user.util.JWTUtil;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/qna")
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class QnaController {
|
||||||
|
private final QnaService qnaService;
|
||||||
|
private final JWTUtil jwtUtil;
|
||||||
|
private static int PAGE_SIZE = 10;
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
@PostMapping("/{lecture_id}")
|
||||||
|
public ResponseEntity<QnaResponseDto> createQna(@PathVariable("lecture_id") Long lecture_id, @RequestBody QnaRequestDto qnaRequestDto, HttpServletRequest request) {
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
|
||||||
|
QnaResponseDto qnaResponseDto = qnaService.createQna(userId, qnaRequestDto, lecture_id);
|
||||||
|
return new ResponseEntity<>(qnaResponseDto, HttpStatus.CREATED);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping({"/answer/create/{qna_id}"})
|
||||||
|
public ResponseEntity<QnaResponseDto> createAnswer(@PathVariable("qna_id") Long qna_id, @RequestBody QnaRequestDto qnaRequestDto, HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
System.out.println(token);
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
User findUser = userRepository.findById(userId).orElse(null);
|
||||||
|
|
||||||
|
if (findUser.getRole() != UserRole.ADMIN) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QnaResponseDto responseDto = qnaService.createAnswer(qna_id, qnaRequestDto);
|
||||||
|
return new ResponseEntity<>(responseDto, HttpStatus.ACCEPTED);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping({"/answer/update/{qna_id}"})
|
||||||
|
public ResponseEntity<QnaResponseDto> updateAnswer(@PathVariable("qna_id") Long qna_id, @RequestBody QnaRequestDto qnaRequestDto, HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
User findUser = userRepository.findById(userId).orElse(null);
|
||||||
|
|
||||||
|
if (findUser.getRole() != UserRole.ADMIN) {
|
||||||
|
System.out.println("role 안맞음");
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
QnaResponseDto responseDto = qnaService.updateAnswer(qna_id, qnaRequestDto);
|
||||||
|
return new ResponseEntity<>(responseDto, HttpStatus.ACCEPTED);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/answer/delete/{qna_id}")
|
||||||
|
public ResponseEntity<QnaResponseDto> deleteAnswer(@PathVariable("qna_id") Long qna_id, HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
User findUser = userRepository.findById(userId).orElse(null);
|
||||||
|
|
||||||
|
System.out.println("delete answer");
|
||||||
|
if (findUser.getRole() != UserRole.ADMIN) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE);
|
||||||
|
}
|
||||||
|
qnaService.deleteAnswer(qna_id);
|
||||||
|
return new ResponseEntity<>(HttpStatus.ACCEPTED);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PutMapping("/{id}")
|
||||||
|
public ResponseEntity<QnaResponseDto> updateQna(@PathVariable Long id, @RequestBody QnaRequestDto qnaRequestDto, HttpServletRequest request) {
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
try {
|
||||||
|
QnaResponseDto qnaResponseDto = qnaService.updateQna(id, qnaRequestDto, userId);
|
||||||
|
return new ResponseEntity<>(qnaResponseDto, HttpStatus.ACCEPTED);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public ResponseEntity<Qna> deleteQna(@PathVariable Long id, HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
qnaService.deleteQna(id, userId);
|
||||||
|
return new ResponseEntity<>(HttpStatus.ACCEPTED);
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public ResponseEntity<QnaResponseDto> getQna(@PathVariable Long id, HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
QnaResponseDto findQna = qnaService.getQna(id, userId);
|
||||||
|
return new ResponseEntity<>(findQna, HttpStatus.ACCEPTED);
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/all/{id}")
|
||||||
|
public ResponseEntity<List<QnaResponseDto>> getAllQna(
|
||||||
|
@PathVariable Long id,
|
||||||
|
@RequestParam(defaultValue = "0") int pageNo) {
|
||||||
|
try {
|
||||||
|
List<QnaResponseDto> qnaList = qnaService.getAllQnasByLecture(id, pageNo, PAGE_SIZE);
|
||||||
|
return new ResponseEntity<>(qnaList, HttpStatus.ACCEPTED);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package com.edufocus.edufocus.qna.entity;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.lecture.entity.Lecture;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.User;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
import org.hibernate.annotations.OnDelete;
|
||||||
|
import org.hibernate.annotations.OnDeleteAction;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
|
||||||
|
|
||||||
|
public class Qna {
|
||||||
|
|
||||||
|
// 연관관계 주인
|
||||||
|
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "qna_id")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@Column(columnDefinition = "TEXT")
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
|
||||||
|
@Column(name = "created_at")
|
||||||
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
|
private Date createdAt;
|
||||||
|
|
||||||
|
@Column(name = "modified_at")
|
||||||
|
@Temporal(TemporalType.DATE)
|
||||||
|
private Date modifiedAt;
|
||||||
|
|
||||||
|
@Column(columnDefinition = "TEXT")
|
||||||
|
private String answer;
|
||||||
|
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "id")
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "lecture_id")
|
||||||
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
|
private Lecture lecture;
|
||||||
|
|
||||||
|
private boolean isMine;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.edufocus.edufocus.qna.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class QnaRequestDto {
|
||||||
|
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
private String content;
|
||||||
|
private String answer;
|
||||||
|
|
||||||
|
public static Qna toEntity(QnaRequestDto qnaRequestDto) {
|
||||||
|
{
|
||||||
|
|
||||||
|
return Qna.builder()
|
||||||
|
.content(qnaRequestDto.getContent())
|
||||||
|
.title(qnaRequestDto.getTitle())
|
||||||
|
.answer(qnaRequestDto.getAnswer())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package com.edufocus.edufocus.qna.entity;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
public class QnaResponseDto {
|
||||||
|
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String title;
|
||||||
|
private String username;
|
||||||
|
private String content;
|
||||||
|
private Date createtAt;
|
||||||
|
private String answer;
|
||||||
|
private boolean isMine;
|
||||||
|
|
||||||
|
public static QnaResponseDto toEntity(Qna qna) {
|
||||||
|
return new QnaResponseDto(
|
||||||
|
qna.getId(),
|
||||||
|
qna.getTitle(),
|
||||||
|
qna.getUser().getName(),
|
||||||
|
qna.getContent(),
|
||||||
|
qna.getCreatedAt(),
|
||||||
|
qna.getAnswer(),
|
||||||
|
qna.isMine()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.edufocus.edufocus.qna.repository;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.qna.entity.Qna;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface QnaRepository extends JpaRepository<Qna, Long> {
|
||||||
|
|
||||||
|
//List<Qna> findByLectureId(Long lecturerId);
|
||||||
|
|
||||||
|
@Query("SELECT q FROM Qna q WHERE q.lecture.id = :lectureId ORDER BY q.createdAt DESC")
|
||||||
|
Page<Qna> findByLectureId(Long lectureId, Pageable pageable);
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.edufocus.edufocus.qna.service;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.lecture.entity.Lecture;
|
||||||
|
import com.edufocus.edufocus.qna.entity.Qna;
|
||||||
|
import com.edufocus.edufocus.qna.entity.QnaRequestDto;
|
||||||
|
import com.edufocus.edufocus.qna.entity.QnaResponseDto;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public interface QnaService {
|
||||||
|
|
||||||
|
QnaResponseDto createQna(Long id, QnaRequestDto qnaRequestDto, Long lecture_id) throws SQLException;
|
||||||
|
|
||||||
|
QnaResponseDto updateQna(Long id, QnaRequestDto qnaRequestDto, Long userId) throws SQLException;
|
||||||
|
|
||||||
|
void deleteQna(Long id, Long userId) throws SQLException;
|
||||||
|
|
||||||
|
QnaResponseDto getQna(Long id, Long userId) throws SQLException;
|
||||||
|
|
||||||
|
List<QnaResponseDto> getAllQnasByLecture(Long lectureId, int pageNo, int pageNumber) throws SQLException;
|
||||||
|
|
||||||
|
QnaResponseDto createAnswer(Long id, QnaRequestDto qnaRequestDto) throws SQLException;
|
||||||
|
|
||||||
|
QnaResponseDto updateAnswer(Long id, QnaRequestDto qnaRequestDto) throws SQLException;
|
||||||
|
|
||||||
|
void deleteAnswer(Long id) throws SQLException;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,169 @@
|
|||||||
|
package com.edufocus.edufocus.qna.service;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.lecture.entity.Lecture;
|
||||||
|
import com.edufocus.edufocus.lecture.repository.LectureRepository;
|
||||||
|
import com.edufocus.edufocus.qna.entity.Qna;
|
||||||
|
import com.edufocus.edufocus.qna.entity.QnaRequestDto;
|
||||||
|
import com.edufocus.edufocus.qna.entity.QnaResponseDto;
|
||||||
|
import com.edufocus.edufocus.qna.repository.QnaRepository;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.User;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.UserRole;
|
||||||
|
import com.edufocus.edufocus.user.model.repository.UserRepository;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class QnaServiceImpl implements QnaService {
|
||||||
|
|
||||||
|
private final QnaRepository qnaRepository;
|
||||||
|
private final LectureRepository lectureRepository;
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QnaResponseDto createQna(Long id, QnaRequestDto qnaRequestDto, Long lecture_id) {
|
||||||
|
|
||||||
|
|
||||||
|
Lecture lecture = lectureRepository.findById(lecture_id).orElse(null);
|
||||||
|
|
||||||
|
User user = userRepository.findById(id).orElse(null);
|
||||||
|
|
||||||
|
|
||||||
|
Qna qna = QnaRequestDto.toEntity(qnaRequestDto);
|
||||||
|
|
||||||
|
qna.setLecture(lecture);
|
||||||
|
qna.setUser(user);
|
||||||
|
|
||||||
|
qna.setCreatedAt(new Date());
|
||||||
|
|
||||||
|
qnaRepository.save(qna);
|
||||||
|
return QnaResponseDto.toEntity(qna);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QnaResponseDto updateQna(Long id, QnaRequestDto qnaRequestDto, Long userId) {
|
||||||
|
|
||||||
|
System.out.println("userId:" + userId);
|
||||||
|
|
||||||
|
Qna findQna = qnaRepository.findById(id).orElse(null);
|
||||||
|
System.out.println("quesiton에 있는거: " + findQna.getUser().getId());
|
||||||
|
User user = userRepository.findById(userId).orElse(null);
|
||||||
|
|
||||||
|
if (findQna.getUser().getId() != userId || user.getRole() != UserRole.STUDENT) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
findQna.setModifiedAt(new Date());
|
||||||
|
findQna.setTitle(qnaRequestDto.getTitle());
|
||||||
|
findQna.setContent(qnaRequestDto.getContent());
|
||||||
|
|
||||||
|
qnaRepository.save(findQna);
|
||||||
|
|
||||||
|
return QnaResponseDto.toEntity(findQna);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteQna(Long id, Long userId) {
|
||||||
|
|
||||||
|
Qna qna = qnaRepository.findById(id).orElse(null);
|
||||||
|
User user = userRepository.findById(userId).orElse(null);
|
||||||
|
if (qna.getUser().getId() == userId || user.getRole() == UserRole.ADMIN) {
|
||||||
|
qnaRepository.delete(qna);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QnaResponseDto getQna(Long id, Long userId) {
|
||||||
|
|
||||||
|
Qna qna;
|
||||||
|
try {
|
||||||
|
|
||||||
|
qna = qnaRepository.findById(id).orElse(null);
|
||||||
|
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
throw new RuntimeException("Qna 없음 " + id, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
QnaResponseDto dto = QnaResponseDto.builder()
|
||||||
|
.id(qna.getId())
|
||||||
|
.title(qna.getTitle())
|
||||||
|
.username(qna.getUser().getName())
|
||||||
|
.content(qna.getContent())
|
||||||
|
.createtAt(qna.getCreatedAt())
|
||||||
|
.answer(qna.getAnswer())
|
||||||
|
.isMine(userId == qna.getUser().getId())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
return dto;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<QnaResponseDto> getAllQnasByLecture(Long lectureId, int pageNo, int pageSize) {
|
||||||
|
Pageable pageable = PageRequest.of(pageNo, pageSize);
|
||||||
|
Page<Qna> qnaPage = qnaRepository.findByLectureId(lectureId, pageable);
|
||||||
|
|
||||||
|
return qnaPage.getContent().stream()
|
||||||
|
.map(QnaResponseDto::toEntity)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QnaResponseDto createAnswer(Long id, QnaRequestDto qnaRequestDto) throws SQLException {
|
||||||
|
|
||||||
|
Qna findQna = qnaRepository.findById(id).orElse(null);
|
||||||
|
if (findQna.getAnswer() != null) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
findQna.setAnswer(qnaRequestDto.getAnswer());
|
||||||
|
|
||||||
|
|
||||||
|
qnaRepository.save(findQna);
|
||||||
|
|
||||||
|
return QnaResponseDto.toEntity(findQna);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QnaResponseDto updateAnswer(Long id, QnaRequestDto qnaRequestDto) throws SQLException {
|
||||||
|
|
||||||
|
Qna findQna = qnaRepository.findById(id).orElse(null);
|
||||||
|
findQna.setAnswer(qnaRequestDto.getAnswer());
|
||||||
|
|
||||||
|
|
||||||
|
qnaRepository.save(findQna);
|
||||||
|
|
||||||
|
return QnaResponseDto.toEntity(findQna);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteAnswer(Long id) throws SQLException {
|
||||||
|
|
||||||
|
Qna findQna = qnaRepository.findById(id).orElse(null);
|
||||||
|
findQna.setAnswer(null);
|
||||||
|
qnaRepository.save(findQna);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,145 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.controller;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.quiz.entity.*;
|
||||||
|
import com.edufocus.edufocus.quiz.service.QuizService;
|
||||||
|
import com.edufocus.edufocus.quiz.service.QuizSetService;
|
||||||
|
import com.edufocus.edufocus.user.util.JWTUtil;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/quiz")
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class QuizController {
|
||||||
|
|
||||||
|
private final QuizService quizService;
|
||||||
|
|
||||||
|
private final QuizSetService quizSetService;
|
||||||
|
|
||||||
|
private final JWTUtil jwtUtil;
|
||||||
|
|
||||||
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
|
public ResponseEntity<?> createQuizSet(@RequestHeader("Authorization") String accessToken, @RequestPart QuizSetCreateRequest quizSetCreateRequest
|
||||||
|
, @RequestPart(value = "images", required = false) List<MultipartFile> images) throws IOException {
|
||||||
|
long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
|
||||||
|
|
||||||
|
if (quizSetCreateRequest.getQuizzes().isEmpty()) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (MultipartFile image : images) {
|
||||||
|
if (image != null && !image.getContentType().startsWith("image")) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QuizSet quizSet = quizSetService.createQuizSet(userId, quizSetCreateRequest.getTitle());
|
||||||
|
|
||||||
|
int imageIdx = 0;
|
||||||
|
for (QuizCreateRequest quizCreateRequest : quizSetCreateRequest.getQuizzes()) {
|
||||||
|
quizService.createQuiz(quizSet, quizCreateRequest, images.get(imageIdx++));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.CREATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/student/{quizsetId}")
|
||||||
|
public ResponseEntity<?> getQuizzes(@PathVariable Long quizsetId) {
|
||||||
|
QuizSetResponse quizSet = quizSetService.findQuizSetResponse(quizsetId);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(quizSet, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/teacher/{quizsetId}")
|
||||||
|
public ResponseEntity<?> getQuizzesIncludeAnswer(@RequestHeader("Authorization") String accessToken, @PathVariable Long quizsetId) {
|
||||||
|
long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
|
||||||
|
|
||||||
|
QuizSet quizSet = quizSetService.findQuizSet(quizsetId);
|
||||||
|
if (quizSet.getUser().getId() != userId) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ResponseEntity<>(quizSet, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
|
public ResponseEntity<?> updateQuizSet(@RequestHeader("Authorization") String accessToken, @RequestPart QuizSetUpdateRequest quizSetUpdateRequest
|
||||||
|
, @RequestPart(value = "images", required = false) List<MultipartFile> images) throws IOException {
|
||||||
|
long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
|
||||||
|
|
||||||
|
QuizSet quizset = quizSetService.findQuizSet(quizSetUpdateRequest.getId());
|
||||||
|
if (userId != quizset.getUser().getId()) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quizset.isTested()) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.CONFLICT);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (MultipartFile image : images) {
|
||||||
|
if (image != null && !image.getContentType().startsWith("image")) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quizSetService.updateQuizSet(quizSetUpdateRequest.getId(), quizSetUpdateRequest.getTitle());
|
||||||
|
|
||||||
|
Map<Long, Boolean> quizUpdatedCheckMap = new HashMap<>();
|
||||||
|
for (Quiz quiz : quizset.getQuizzes()) {
|
||||||
|
quizUpdatedCheckMap.put(quiz.getId(), false);
|
||||||
|
}
|
||||||
|
int imageIdx = 0;
|
||||||
|
for (QuizUpdateRequest quizUpdateRequest : quizSetUpdateRequest.getQuizzes()) {
|
||||||
|
if (quizUpdateRequest.getId() == null) {
|
||||||
|
QuizCreateRequest quizCreateRequest = QuizCreateRequest.builder()
|
||||||
|
.question(quizUpdateRequest.getQuestion())
|
||||||
|
.answer(quizUpdateRequest.getAnswer())
|
||||||
|
.choices(quizUpdateRequest.getChoices())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
quizService.createQuiz(quizset, quizCreateRequest, images.get(imageIdx++));
|
||||||
|
} else {
|
||||||
|
quizService.updateQuiz(quizUpdateRequest, images.get(imageIdx++));
|
||||||
|
|
||||||
|
quizUpdatedCheckMap.put(quizUpdateRequest.getId(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Long quizId : quizUpdatedCheckMap.keySet()) {
|
||||||
|
if (!quizUpdatedCheckMap.get(quizId)) {
|
||||||
|
quizService.removeQuiz(quizId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{quizsetId}")
|
||||||
|
public ResponseEntity<?> deleteQuizSet(@RequestHeader("Authorization") String accessToken, @PathVariable long quizsetId) {
|
||||||
|
long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
|
||||||
|
|
||||||
|
if (!quizSetService.deleteQuizSet(userId, quizsetId)) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public ResponseEntity<?> getQuizSets(@RequestHeader("Authorization") String accessToken) {
|
||||||
|
long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
|
||||||
|
|
||||||
|
return new ResponseEntity<>(quizSetService.findMyQuizSetResponses(userId), HttpStatus.OK);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.entity;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.report.entity.dto.ChoiceDto;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonBackReference;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Choice {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "QuizId")
|
||||||
|
@JsonBackReference
|
||||||
|
private Quiz quiz;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private int num;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
public ChoiceDto makeChoiceDto(){
|
||||||
|
return ChoiceDto.builder()
|
||||||
|
.num(num)
|
||||||
|
.content(content)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.entity;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ChoiceCreateRequest {
|
||||||
|
|
||||||
|
private int num;
|
||||||
|
|
||||||
|
private String content;
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.entity;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class MyQuizSetResponse {
|
||||||
|
|
||||||
|
private long quizSetId;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.entity;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonBackReference;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Quiz {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "quizset_id")
|
||||||
|
@JsonBackReference
|
||||||
|
private QuizSet quizSet;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String question;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String image;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String answer;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "quiz", orphanRemoval = true, cascade = CascadeType.ALL)
|
||||||
|
@JsonManagedReference
|
||||||
|
private List<Choice> choices;
|
||||||
|
|
||||||
|
public void setQuizSet(QuizSet quizSet) {
|
||||||
|
this.quizSet = quizSet;
|
||||||
|
|
||||||
|
if (!quizSet.getQuizzes().contains(this)) {
|
||||||
|
quizSet.getQuizzes().remove(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addChoice(Choice choice) {
|
||||||
|
this.choices.add(choice);
|
||||||
|
|
||||||
|
if (choice.getQuiz() != this) {
|
||||||
|
choice.setQuiz(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.entity;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class QuizCreateRequest {
|
||||||
|
|
||||||
|
private String question;
|
||||||
|
|
||||||
|
private String answer;
|
||||||
|
|
||||||
|
private List<ChoiceCreateRequest> choices;
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.entity;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class QuizResponse {
|
||||||
|
|
||||||
|
private String question;
|
||||||
|
|
||||||
|
private String image;
|
||||||
|
|
||||||
|
private List<Choice> choices;
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.entity;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.User;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonBackReference;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class QuizSet {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "user_id")
|
||||||
|
@JsonBackReference
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private boolean tested;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "quizSet", orphanRemoval = true)
|
||||||
|
@JsonManagedReference
|
||||||
|
private List<Quiz> quizzes;
|
||||||
|
|
||||||
|
public void addQuiz(Quiz quiz) {
|
||||||
|
this.quizzes.add(quiz);
|
||||||
|
|
||||||
|
if (quiz.getQuizSet() != this) {
|
||||||
|
quiz.setQuizSet(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.entity;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class QuizSetCreateRequest {
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private List<QuizCreateRequest> quizzes;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.entity;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class QuizSetResponse {
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private List<QuizResponse> quizzes;
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.entity;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class QuizSetUpdateRequest {
|
||||||
|
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private List<QuizUpdateRequest> quizzes;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.entity;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class QuizUpdateRequest {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String question;
|
||||||
|
|
||||||
|
private String answer;
|
||||||
|
|
||||||
|
private List<ChoiceCreateRequest> choices;
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.repository;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.quiz.entity.Choice;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface ChoiceRepository extends JpaRepository<Choice, Long> {
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.repository;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.quiz.entity.Quiz;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface QuizRepository extends JpaRepository<Quiz, Long> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.repository;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.quiz.entity.QuizSet;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface QuizSetRepository extends JpaRepository<QuizSet, Long> {
|
||||||
|
|
||||||
|
List<QuizSet> findQuizSetsByUserId(long userId);
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.service;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.quiz.entity.Quiz;
|
||||||
|
import com.edufocus.edufocus.quiz.entity.QuizCreateRequest;
|
||||||
|
import com.edufocus.edufocus.quiz.entity.QuizSet;
|
||||||
|
import com.edufocus.edufocus.quiz.entity.QuizUpdateRequest;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public interface QuizService {
|
||||||
|
|
||||||
|
void createQuiz(QuizSet quizSet, QuizCreateRequest quizCreateRequest, MultipartFile quizImage) throws IOException;
|
||||||
|
|
||||||
|
void updateQuiz(QuizUpdateRequest quizUpdateRequest, MultipartFile quizImage) throws IOException;
|
||||||
|
|
||||||
|
Quiz findQuiz(long quizId);
|
||||||
|
|
||||||
|
void removeQuiz(long quizId);
|
||||||
|
}
|
@ -0,0 +1,136 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.service;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.global.properties.ImagePathProperties;
|
||||||
|
import com.edufocus.edufocus.quiz.entity.*;
|
||||||
|
import com.edufocus.edufocus.quiz.repository.ChoiceRepository;
|
||||||
|
import com.edufocus.edufocus.quiz.repository.QuizRepository;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class QuizServiceImpl implements QuizService {
|
||||||
|
|
||||||
|
private final ImagePathProperties imagePathProperties;
|
||||||
|
|
||||||
|
private final QuizRepository quizRepository;
|
||||||
|
|
||||||
|
private final ChoiceRepository choiceRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createQuiz(QuizSet quizSet, QuizCreateRequest quizCreateRequest, MultipartFile quizImage) throws IOException {
|
||||||
|
Quiz quiz = Quiz.builder()
|
||||||
|
.quizSet(quizSet)
|
||||||
|
.question(quizCreateRequest.getQuestion())
|
||||||
|
.answer(quizCreateRequest.getAnswer())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
List<Choice> choices = new ArrayList<>();
|
||||||
|
|
||||||
|
for (ChoiceCreateRequest choiceCreateRequest : quizCreateRequest.getChoices()) {
|
||||||
|
Choice choice = Choice.builder()
|
||||||
|
.quiz(quiz)
|
||||||
|
.num(choiceCreateRequest.getNum())
|
||||||
|
.content(choiceCreateRequest.getContent())
|
||||||
|
.build();
|
||||||
|
choices.add(choice);
|
||||||
|
}
|
||||||
|
|
||||||
|
quiz.setChoices(choices);
|
||||||
|
|
||||||
|
if (quizImage != null && !quizImage.isEmpty()) {
|
||||||
|
String uid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
String imagePath = imagePathProperties.getPath();
|
||||||
|
|
||||||
|
File checkPathFile = new File(imagePath);
|
||||||
|
if (!checkPathFile.exists()) {
|
||||||
|
checkPathFile.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
File savingImage = new File(imagePath + "/" + uid + "_" + quizImage.getOriginalFilename());
|
||||||
|
quizImage.transferTo(savingImage.toPath());
|
||||||
|
String savePath = savingImage.toPath().toString();
|
||||||
|
|
||||||
|
quiz.setImage(savePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
quizRepository.save(quiz);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateQuiz(QuizUpdateRequest quizUpdateRequest, MultipartFile quizImage) throws IOException {
|
||||||
|
Quiz quiz = quizRepository.findById(quizUpdateRequest.getId()).orElseThrow(NoSuchElementException::new);
|
||||||
|
|
||||||
|
quiz.setQuestion(quizUpdateRequest.getQuestion());
|
||||||
|
quiz.setAnswer(quizUpdateRequest.getAnswer());
|
||||||
|
|
||||||
|
quiz.getChoices().clear();
|
||||||
|
quizRepository.save(quiz);
|
||||||
|
|
||||||
|
for (ChoiceCreateRequest choiceCreateRequest : quizUpdateRequest.getChoices()) {
|
||||||
|
Choice choice = Choice.builder()
|
||||||
|
.quiz(quiz)
|
||||||
|
.num(choiceCreateRequest.getNum())
|
||||||
|
.content(choiceCreateRequest.getContent())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
quiz.addChoice(choice);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quizImage != null && !quizImage.isEmpty()) {
|
||||||
|
if (quiz.getImage() != null) {
|
||||||
|
File file = new File(quiz.getImage());
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
String uid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
String imagePath = imagePathProperties.getPath();
|
||||||
|
|
||||||
|
File checkPathFile = new File(imagePath);
|
||||||
|
if (!checkPathFile.exists()) {
|
||||||
|
checkPathFile.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
File savingImage = new File(imagePath + "/" + uid + "_" + quizImage.getOriginalFilename());
|
||||||
|
quizImage.transferTo(savingImage.toPath());
|
||||||
|
String savePath = savingImage.toPath().toString();
|
||||||
|
|
||||||
|
quiz.setImage(savePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
quizRepository.save(quiz);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Quiz findQuiz(long quizId) {
|
||||||
|
return quizRepository.findById(quizId).orElseThrow(NoSuchElementException::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeQuiz(long quizId) {
|
||||||
|
Quiz quiz = quizRepository.findById(quizId).orElseThrow(NoSuchElementException::new);
|
||||||
|
|
||||||
|
String image = quiz.getImage();
|
||||||
|
if (image != null) {
|
||||||
|
File file = new File(quiz.getImage());
|
||||||
|
file.delete();
|
||||||
|
quiz.setImage(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
quizRepository.delete(quiz);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.service;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.quiz.entity.MyQuizSetResponse;
|
||||||
|
import com.edufocus.edufocus.quiz.entity.QuizSet;
|
||||||
|
import com.edufocus.edufocus.quiz.entity.QuizSetResponse;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public interface QuizSetService {
|
||||||
|
|
||||||
|
QuizSet createQuizSet(long userId, String title);
|
||||||
|
|
||||||
|
void updateQuizSet(long quizSetId, String title);
|
||||||
|
|
||||||
|
boolean deleteQuizSet(long userId, long quizSetId);
|
||||||
|
|
||||||
|
QuizSet findQuizSet(long quizSetId);
|
||||||
|
|
||||||
|
QuizSetResponse findQuizSetResponse(long quizSetId);
|
||||||
|
|
||||||
|
List<MyQuizSetResponse> findMyQuizSetResponses(long userId);
|
||||||
|
|
||||||
|
void updateQuizSetTested(long quizSetId);
|
||||||
|
}
|
@ -0,0 +1,109 @@
|
|||||||
|
package com.edufocus.edufocus.quiz.service;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.quiz.entity.*;
|
||||||
|
import com.edufocus.edufocus.quiz.repository.QuizSetRepository;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.User;
|
||||||
|
import com.edufocus.edufocus.user.model.exception.UnAuthorizedException;
|
||||||
|
import com.edufocus.edufocus.user.model.repository.UserRepository;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class QuizSetServiceImpl implements QuizSetService {
|
||||||
|
|
||||||
|
private final QuizSetRepository quizSetRepository;
|
||||||
|
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QuizSet createQuizSet(long userId, String title) {
|
||||||
|
User user = userRepository.findById(userId).orElseThrow(NoSuchElementException::new);
|
||||||
|
|
||||||
|
QuizSet quizSet = QuizSet.builder()
|
||||||
|
.user(user)
|
||||||
|
.title(title)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return quizSetRepository.save(quizSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateQuizSet(long quizSetId, String title) {
|
||||||
|
QuizSet quizSet = quizSetRepository.findById(quizSetId).orElseThrow(NoSuchElementException::new);
|
||||||
|
|
||||||
|
quizSet.setTitle(title);
|
||||||
|
quizSetRepository.save(quizSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteQuizSet(long userId, long quizSetId) {
|
||||||
|
QuizSet quizSet = quizSetRepository.findById(quizSetId).orElseThrow(NoSuchElementException::new);
|
||||||
|
|
||||||
|
if (userId != quizSet.getUser().getId()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
quizSetRepository.deleteById(quizSetId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QuizSet findQuizSet(long quizSetId) {
|
||||||
|
return quizSetRepository.findById(quizSetId).orElseThrow(NoSuchElementException::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QuizSetResponse findQuizSetResponse(long quizSetId) {
|
||||||
|
QuizSet quizSet = quizSetRepository.findById(quizSetId).orElseThrow(NoSuchElementException::new);
|
||||||
|
|
||||||
|
List<QuizResponse> quizResponses = new ArrayList<>();
|
||||||
|
for (Quiz quiz : quizSet.getQuizzes()) {
|
||||||
|
QuizResponse quizResponse = QuizResponse.builder()
|
||||||
|
.question(quiz.getQuestion())
|
||||||
|
.image(quiz.getImage())
|
||||||
|
.choices(quiz.getChoices())
|
||||||
|
.build();
|
||||||
|
quizResponses.add(quizResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
return QuizSetResponse.builder()
|
||||||
|
.title(quizSet.getTitle())
|
||||||
|
.quizzes(quizResponses)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MyQuizSetResponse> findMyQuizSetResponses(long userId) {
|
||||||
|
List<QuizSet> quizSetList = quizSetRepository.findQuizSetsByUserId(userId);
|
||||||
|
|
||||||
|
List<MyQuizSetResponse> myQuizSetResponses = new ArrayList<>();
|
||||||
|
for (QuizSet quizSet : quizSetList) {
|
||||||
|
MyQuizSetResponse myQuizSetResponse = MyQuizSetResponse.builder()
|
||||||
|
.quizSetId(quizSet.getId())
|
||||||
|
.title(quizSet.getTitle())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
myQuizSetResponses.add(myQuizSetResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
return myQuizSetResponses;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateQuizSetTested(long quizSetId) {
|
||||||
|
QuizSet quizSet = quizSetRepository.findById(quizSetId).orElseThrow(NoSuchElementException::new);
|
||||||
|
|
||||||
|
quizSet.setTested(true);
|
||||||
|
quizSetRepository.save(quizSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.edufocus.edufocus.redis.util;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
|
import org.springframework.data.redis.core.ValueOperations;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RedisUtil {
|
||||||
|
|
||||||
|
private final StringRedisTemplate stringRedisTemplate;
|
||||||
|
|
||||||
|
public String getData(String key) {
|
||||||
|
ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();
|
||||||
|
return valueOperations.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(String key, String value) {
|
||||||
|
ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();
|
||||||
|
valueOperations.set(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDataExpire(String key, String value, long duration) {
|
||||||
|
ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();
|
||||||
|
Duration expireDuration = Duration.ofSeconds(duration);
|
||||||
|
valueOperations.set(key, value, expireDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteData(String key) {
|
||||||
|
stringRedisTemplate.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean exists(String key) {
|
||||||
|
return stringRedisTemplate.hasKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package com.edufocus.edufocus.registration.controller;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.lecture.service.LectureService;
|
||||||
|
import com.edufocus.edufocus.registration.service.RegistrationService;
|
||||||
|
import com.edufocus.edufocus.user.util.JWTUtil;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/registration")
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RegistrationController {
|
||||||
|
|
||||||
|
private final RegistrationService registrationService;
|
||||||
|
|
||||||
|
private final LectureService lectureService;
|
||||||
|
|
||||||
|
private final JWTUtil jwtUtil;
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public ResponseEntity<?> register(@RequestHeader("Authorization") String accessToken, @RequestBody Map<String, Long> map) {
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
|
||||||
|
Long lectureId = map.get("lectureId");
|
||||||
|
|
||||||
|
if (!registrationService.createRegistration(userId, lectureId)) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.CREATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{registrationId}")
|
||||||
|
public ResponseEntity<?> acceptRegistration(@RequestHeader("Authorization") String accessToken, @PathVariable long registrationId) {
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
|
||||||
|
|
||||||
|
if (!registrationService.acceptRegistration(userId, registrationId)) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{registrationId}")
|
||||||
|
public ResponseEntity<?> deleteRegistration(@RequestHeader("Authorization") String accessToken, @PathVariable long registrationId) {
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
|
||||||
|
|
||||||
|
if (!registrationService.deleteRegistration(userId, registrationId)) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{lectureId}")
|
||||||
|
public ResponseEntity<?> getRegistrations(@RequestHeader("Authorization") String accessToken, @PathVariable long lectureId) {
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
|
||||||
|
|
||||||
|
if (!lectureService.checkTeacher(userId, lectureId)) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ResponseEntity<>(registrationService.searchRegistrations(lectureId), HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
package com.edufocus.edufocus.registration.entity;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.lecture.entity.Lecture;
|
||||||
|
import com.edufocus.edufocus.quiz.entity.QuizSet;
|
||||||
|
import com.edufocus.edufocus.report.entity.vo.Report;
|
||||||
|
import com.edufocus.edufocus.report.entity.vo.ReportSet;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.User;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
import org.hibernate.annotations.OnDelete;
|
||||||
|
import org.hibernate.annotations.OnDeleteAction;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Registration {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "user_id")
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
|
@JoinColumn(name = "lecture_id")
|
||||||
|
private Lecture lecture;
|
||||||
|
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private RegistrationStatus status;
|
||||||
|
|
||||||
|
public boolean isAccepted() {
|
||||||
|
return status == RegistrationStatus.ACCEPTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Report makeReport(ReportSet reportSet, QuizSet quizSet, long lectureId) {
|
||||||
|
return Report.builder()
|
||||||
|
.allCount(0)
|
||||||
|
.correctCount(-1)
|
||||||
|
.reportSet(reportSet)
|
||||||
|
.quizSet(quizSet)
|
||||||
|
.lectureId(lectureId)
|
||||||
|
.user(user)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.edufocus.edufocus.registration.entity;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.lecture.entity.Lecture;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RegistrationSearchResponse {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String userName;
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.edufocus.edufocus.registration.entity;
|
||||||
|
|
||||||
|
public enum RegistrationStatus {
|
||||||
|
WAITING, ACCEPTED
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.edufocus.edufocus.registration.repository;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.registration.entity.Registration;
|
||||||
|
import com.edufocus.edufocus.registration.entity.RegistrationStatus;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface RegistrationRepository extends JpaRepository<Registration, Long> {
|
||||||
|
List<Registration> findAllByUserId(@Param("userId") Long userId);
|
||||||
|
|
||||||
|
List<Registration> findAllByLectureId(Long lectureId);
|
||||||
|
|
||||||
|
Registration findByUserIdAndLectureId(Long userId, Long lectureId);
|
||||||
|
|
||||||
|
List<Registration> findByLectureIdAndStatus(Long lectureId, RegistrationStatus status);
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.edufocus.edufocus.registration.service;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.registration.entity.Registration;
|
||||||
|
import com.edufocus.edufocus.registration.entity.RegistrationSearchResponse;
|
||||||
|
import com.edufocus.edufocus.registration.entity.RegistrationStatus;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public interface RegistrationService {
|
||||||
|
|
||||||
|
boolean createRegistration(Long userId, Long registrationId);
|
||||||
|
|
||||||
|
boolean acceptRegistration(Long userId, Long RegistrationId);
|
||||||
|
|
||||||
|
boolean deleteRegistration(Long userId, Long registrationId);
|
||||||
|
|
||||||
|
List<RegistrationSearchResponse>[] searchRegistrations(Long LectureId);
|
||||||
|
|
||||||
|
RegistrationStatus getStatus(Long userId, Long lectureId);
|
||||||
|
}
|
@ -0,0 +1,107 @@
|
|||||||
|
package com.edufocus.edufocus.registration.service;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.lecture.repository.LectureRepository;
|
||||||
|
import com.edufocus.edufocus.registration.entity.Registration;
|
||||||
|
import com.edufocus.edufocus.registration.entity.RegistrationSearchResponse;
|
||||||
|
import com.edufocus.edufocus.registration.entity.RegistrationStatus;
|
||||||
|
import com.edufocus.edufocus.registration.repository.RegistrationRepository;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.User;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.UserRole;
|
||||||
|
import com.edufocus.edufocus.user.model.repository.UserRepository;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RegistrationServiceImpl implements RegistrationService {
|
||||||
|
|
||||||
|
private final RegistrationRepository registrationRepository;
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
private final LectureRepository lectureRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean createRegistration(Long userId, Long lectureId) {
|
||||||
|
Optional<User> user = userRepository.findById(userId);
|
||||||
|
|
||||||
|
if (user.isEmpty() || user.get().getRole().equals(UserRole.ADMIN)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registrationRepository.findByUserIdAndLectureId(userId, lectureId) != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Registration registration = Registration.builder()
|
||||||
|
.user(userRepository.findById(userId).get())
|
||||||
|
.lecture(lectureRepository.findById(lectureId).get())
|
||||||
|
.status(RegistrationStatus.WAITING)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
registrationRepository.save(registration);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean acceptRegistration(Long userId, Long registrationId) {
|
||||||
|
Optional<Registration> registration = registrationRepository.findById(registrationId);
|
||||||
|
|
||||||
|
if (registration.isEmpty() || registration.get().getLecture().getUser().getId() != userId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
registration.get().setStatus(RegistrationStatus.valueOf("ACCEPTED"));
|
||||||
|
registrationRepository.save(registration.get());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteRegistration(Long userId, Long registrationId) {
|
||||||
|
Optional<Registration> registration = registrationRepository.findById(registrationId);
|
||||||
|
|
||||||
|
if (registration.isEmpty() || registration.get().getLecture().getUser().getId() != userId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
registrationRepository.deleteById(registrationId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<RegistrationSearchResponse>[] searchRegistrations(Long lectureId) {
|
||||||
|
List<Registration> registrations = registrationRepository.findAllByLectureId(lectureId);
|
||||||
|
|
||||||
|
List<RegistrationSearchResponse>[] responses = new ArrayList[2];
|
||||||
|
responses[0] = new ArrayList<>();
|
||||||
|
responses[1] = new ArrayList<>();
|
||||||
|
for (Registration registration : registrations) {
|
||||||
|
RegistrationSearchResponse response = RegistrationSearchResponse.builder()
|
||||||
|
.id(registration.getId())
|
||||||
|
.userName(registration.getUser().getName())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if (registration.getStatus() == RegistrationStatus.ACCEPTED) {
|
||||||
|
responses[0].add(response);
|
||||||
|
} else {
|
||||||
|
responses[1].add(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return responses;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RegistrationStatus getStatus(Long userId, Long lectureId) {
|
||||||
|
|
||||||
|
Registration registration = registrationRepository.findByUserIdAndLectureId(userId, lectureId);
|
||||||
|
return registration.getStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
package com.edufocus.edufocus.report.controller;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.report.entity.dto.*;
|
||||||
|
import com.edufocus.edufocus.report.service.ReportService;
|
||||||
|
import com.edufocus.edufocus.user.model.service.UserService;
|
||||||
|
import com.edufocus.edufocus.user.util.JWTUtil;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/report")
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ReportController {
|
||||||
|
|
||||||
|
|
||||||
|
private final ReportService reportService;
|
||||||
|
private final JWTUtil jwtUtil;
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
|
@PostMapping("/submit/quizSet/{reportSetId}")
|
||||||
|
public ResponseEntity<?> submit(@PathVariable("reportSetId") UUID reportSetId, @RequestBody ReportRequest reportRequest, HttpServletRequest request) {
|
||||||
|
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
|
||||||
|
if (userService.isTeacher(userId))
|
||||||
|
return new ResponseEntity<>("강사는 퀴즈제출을 할수 없습니다", HttpStatus.FORBIDDEN);
|
||||||
|
|
||||||
|
reportService.grade(userId, reportSetId, reportRequest);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/student/{lectureId}")
|
||||||
|
public ResponseEntity<List<ReportResponse>> searchMyReport(@PathVariable long lectureId, HttpServletRequest request) {
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
|
||||||
|
List<ReportResponse> reportResponses = reportService.findReports(lectureId, userId);
|
||||||
|
|
||||||
|
if (reportResponses.isEmpty())
|
||||||
|
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(reportResponses, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/reportDetail/{reportId}")
|
||||||
|
public ResponseEntity<ReportDetailResponseDto> searchDetailReport(@PathVariable("reportId") long reportId) {
|
||||||
|
ReportDetailResponseDto detailReport = reportService.reportDetail(reportId);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(detailReport, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/teacher/reportSet/{lectureId}")
|
||||||
|
public ResponseEntity<List<ReportSetResponse>> searchReportSets(@PathVariable("lectureId") long lectureId) {
|
||||||
|
List<ReportSetResponse> reportSetResponses = reportService.findReportSets(lectureId);
|
||||||
|
|
||||||
|
if (reportSetResponses.isEmpty())
|
||||||
|
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(reportSetResponses, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/teacher/report/{reportSetId}")
|
||||||
|
public ResponseEntity<?> searchReports(@PathVariable("reportSetId") UUID reportSetId) {
|
||||||
|
List<ReportResponse> reportResponses = reportService.findReports(reportSetId);
|
||||||
|
|
||||||
|
if (reportResponses.isEmpty())
|
||||||
|
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(reportResponses, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/teacher/report/{reportSetId}")
|
||||||
|
public ResponseEntity<?> deleteReportSet(@PathVariable("reportSetId") UUID reportSetId, HttpServletRequest request) {
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
|
||||||
|
reportService.deleteReportSet(reportSetId, userId);
|
||||||
|
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.edufocus.edufocus.report.entity.dto;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class ChoiceDto {
|
||||||
|
int num;
|
||||||
|
String content;
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.edufocus.edufocus.report.entity.dto;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.quiz.entity.Choice;
|
||||||
|
import com.edufocus.edufocus.quiz.entity.QuizSet;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonBackReference;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class QuizDto {
|
||||||
|
private long id;
|
||||||
|
private String question;
|
||||||
|
private String image;
|
||||||
|
private String answer;
|
||||||
|
private String userAnswer;
|
||||||
|
private boolean isCorrect;
|
||||||
|
private List<ChoiceDto> choices;
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.edufocus.edufocus.report.entity.dto;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.quiz.entity.Quiz;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class ReportDetailResponseDto {
|
||||||
|
private int allCount;
|
||||||
|
private String title;
|
||||||
|
private int correctCount;
|
||||||
|
private Date testAt;
|
||||||
|
private List<QuizDto> quizzes;
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.edufocus.edufocus.report.entity.dto;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ReportRequest {
|
||||||
|
|
||||||
|
|
||||||
|
List<String> answer;
|
||||||
|
|
||||||
|
// [1,2,,3]
|
||||||
|
// List<answerDto> a
|
||||||
|
// userID :
|
||||||
|
// quizSetId :
|
||||||
|
// answerList : [
|
||||||
|
// { ans1 : 1},
|
||||||
|
// {ans2 : 2}
|
||||||
|
// ]
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.edufocus.edufocus.report.entity.dto;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
public class ReportResponse {
|
||||||
|
private long reportId;
|
||||||
|
private String name;
|
||||||
|
private String title;
|
||||||
|
private int allCount;
|
||||||
|
private int correctCount;
|
||||||
|
private Date date;
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.edufocus.edufocus.report.entity.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ReportSetResponse {
|
||||||
|
private UUID reportSetId;
|
||||||
|
private String quizSetTitle;
|
||||||
|
private Date testAt;
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.edufocus.edufocus.report.entity.vo;
|
||||||
|
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.quiz.entity.Quiz;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
import org.hibernate.annotations.OnDelete;
|
||||||
|
import org.hibernate.annotations.OnDeleteAction;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
public class Answer {
|
||||||
|
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private String userAnswer;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
private boolean isCorrect;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "report_id")
|
||||||
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
|
private Report report;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "quiz_id")
|
||||||
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
|
private Quiz quiz;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package com.edufocus.edufocus.report.entity.vo;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.quiz.entity.QuizSet;
|
||||||
|
import com.edufocus.edufocus.report.entity.dto.ReportResponse;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.User;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
|
import org.hibernate.annotations.OnDelete;
|
||||||
|
import org.hibernate.annotations.OnDeleteAction;
|
||||||
|
import org.springframework.data.annotation.CreatedDate;
|
||||||
|
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
@EntityListeners(AuditingEntityListener.class)
|
||||||
|
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
|
||||||
|
public class Report {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private int allCount;
|
||||||
|
|
||||||
|
private int correctCount;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@CreationTimestamp
|
||||||
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
|
private Date testAt;
|
||||||
|
|
||||||
|
private Long lectureId;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "user_id")
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "quizset_id")
|
||||||
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
|
private QuizSet quizSet;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "reportset_id")
|
||||||
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
|
private ReportSet reportSet;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "report")
|
||||||
|
private List<Answer> answers;
|
||||||
|
|
||||||
|
public ReportResponse makeReportResponse() {
|
||||||
|
return ReportResponse.builder()
|
||||||
|
.reportId(id)
|
||||||
|
.name(user.getName())
|
||||||
|
.title(quizSet.getTitle())
|
||||||
|
.allCount(allCount)
|
||||||
|
.correctCount(correctCount)
|
||||||
|
.date(testAt)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package com.edufocus.edufocus.report.entity.vo;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.lecture.entity.Lecture;
|
||||||
|
import com.edufocus.edufocus.quiz.entity.QuizSet;
|
||||||
|
import com.edufocus.edufocus.report.entity.dto.ReportSetResponse;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import jakarta.persistence.CascadeType;
|
||||||
|
import lombok.*;
|
||||||
|
import org.hibernate.annotations.*;
|
||||||
|
import org.springframework.data.annotation.CreatedDate;
|
||||||
|
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||||
|
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@EntityListeners(AuditingEntityListener.class)
|
||||||
|
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
|
||||||
|
public class ReportSet {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(generator = "UUID")
|
||||||
|
@GenericGenerator(
|
||||||
|
name = "UUID",
|
||||||
|
strategy = "org.hibernate.id.UUIDGenerator"
|
||||||
|
)
|
||||||
|
private UUID id;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@CreationTimestamp
|
||||||
|
@Temporal(TemporalType.TIMESTAMP)
|
||||||
|
private Date createAt;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "reportSet")
|
||||||
|
private List<Report> reports;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "lecture_id")
|
||||||
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
|
private Lecture lecture;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "quizSet_id")
|
||||||
|
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||||
|
private QuizSet quizSet;
|
||||||
|
|
||||||
|
public ReportSetResponse makeReportSetResponse() {
|
||||||
|
return ReportSetResponse.builder()
|
||||||
|
.reportSetId(id)
|
||||||
|
.quizSetTitle(quizSet.getTitle())
|
||||||
|
.testAt(createAt)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long findUserId() {
|
||||||
|
return lecture.getUser().getId();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.edufocus.edufocus.report.repository;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.report.entity.vo.Answer;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface AnswerRepository extends JpaRepository<Answer, Long> {
|
||||||
|
List<Answer> findByReportId(Long reportId);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.edufocus.edufocus.report.repository;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.report.entity.vo.Report;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface ReportRepository extends JpaRepository<Report, Long> {
|
||||||
|
Report findByReportSetIdAndUserId(UUID reportSetId, long userId);
|
||||||
|
|
||||||
|
List<Report> findByReportSetIdOrderById(UUID reportSetId);
|
||||||
|
|
||||||
|
List<Report> findByLectureIdAndUserIdOrderById(long lectureId, long userId);
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.edufocus.edufocus.report.repository;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.report.entity.vo.ReportSet;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface ReportSetRepository extends JpaRepository<ReportSet, UUID> {
|
||||||
|
List<ReportSet> findByLectureIdOrderById(long userId);
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.edufocus.edufocus.report.service;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.report.entity.vo.Answer;
|
||||||
|
|
||||||
|
public interface AnswerService {
|
||||||
|
|
||||||
|
void save(Answer answer);
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.edufocus.edufocus.report.service;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.report.entity.vo.Answer;
|
||||||
|
import com.edufocus.edufocus.report.repository.AnswerRepository;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AnswerServiceImpl implements AnswerService{
|
||||||
|
|
||||||
|
private final AnswerRepository answerRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(Answer answer) {
|
||||||
|
|
||||||
|
answerRepository.save(answer);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.edufocus.edufocus.report.service;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.report.entity.dto.*;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public interface ReportService {
|
||||||
|
void grade(long userId, UUID reportSetId, ReportRequest reportRequest);
|
||||||
|
|
||||||
|
ReportDetailResponseDto reportDetail(long userId);
|
||||||
|
|
||||||
|
List<ReportSetResponse> findReportSets(long lectureId);
|
||||||
|
|
||||||
|
List<ReportResponse> findReports(UUID reportSetId);
|
||||||
|
|
||||||
|
List<ReportResponse> findReports(long lectureId, long userid);
|
||||||
|
|
||||||
|
UUID initReportSet(long lectureId, long quizSetId);
|
||||||
|
|
||||||
|
void deleteReportSet(UUID reportSetId, long userId);
|
||||||
|
}
|
@ -0,0 +1,182 @@
|
|||||||
|
package com.edufocus.edufocus.report.service;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.lecture.repository.LectureRepository;
|
||||||
|
import com.edufocus.edufocus.quiz.entity.Choice;
|
||||||
|
import com.edufocus.edufocus.quiz.entity.Quiz;
|
||||||
|
import com.edufocus.edufocus.quiz.entity.QuizSet;
|
||||||
|
import com.edufocus.edufocus.quiz.repository.QuizRepository;
|
||||||
|
import com.edufocus.edufocus.quiz.repository.QuizSetRepository;
|
||||||
|
import com.edufocus.edufocus.registration.entity.Registration;
|
||||||
|
import com.edufocus.edufocus.registration.entity.RegistrationStatus;
|
||||||
|
import com.edufocus.edufocus.registration.repository.RegistrationRepository;
|
||||||
|
import com.edufocus.edufocus.report.entity.dto.*;
|
||||||
|
import com.edufocus.edufocus.report.entity.vo.Answer;
|
||||||
|
import com.edufocus.edufocus.report.entity.vo.Report;
|
||||||
|
import com.edufocus.edufocus.report.entity.vo.ReportSet;
|
||||||
|
import com.edufocus.edufocus.report.repository.AnswerRepository;
|
||||||
|
import com.edufocus.edufocus.report.repository.ReportRepository;
|
||||||
|
import com.edufocus.edufocus.report.repository.ReportSetRepository;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ReportServiceImpl implements ReportService {
|
||||||
|
|
||||||
|
private final ReportRepository reportRepository;
|
||||||
|
private final QuizRepository quizRepository;
|
||||||
|
private final RegistrationRepository registrationRepository;
|
||||||
|
private final AnswerRepository answerRepository;
|
||||||
|
private final ReportSetRepository reportSetRepository;
|
||||||
|
private final LectureRepository lectureRepository;
|
||||||
|
private final QuizSetRepository quizSetRepository;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void grade(long userId, UUID reportSetId, ReportRequest reportRequest){
|
||||||
|
|
||||||
|
ReportSet reportSet = reportSetRepository.findById(reportSetId).orElseThrow(NoSuchElementException::new);
|
||||||
|
|
||||||
|
Report report = reportRepository.findByReportSetIdAndUserId(reportSetId, userId);
|
||||||
|
|
||||||
|
List<Quiz> quizList = report.getQuizSet().getQuizzes();
|
||||||
|
|
||||||
|
List<String> answerInputList = reportRequest.getAnswer();
|
||||||
|
|
||||||
|
List<Answer> answerList = new ArrayList<>();
|
||||||
|
|
||||||
|
int correctCount = 0;
|
||||||
|
|
||||||
|
for (int idx = 0; idx < answerInputList.size(); idx++) {
|
||||||
|
Quiz quiz = quizList.get(idx);
|
||||||
|
String inputAnswer = answerInputList.get(idx);
|
||||||
|
boolean isCorrect;
|
||||||
|
Answer answer;
|
||||||
|
if (quiz.getAnswer().equalsIgnoreCase(inputAnswer)) {
|
||||||
|
correctCount++;
|
||||||
|
isCorrect = true;
|
||||||
|
} else {
|
||||||
|
isCorrect = false;
|
||||||
|
}
|
||||||
|
answer = Answer.builder()
|
||||||
|
.userAnswer(inputAnswer)
|
||||||
|
.isCorrect(isCorrect)
|
||||||
|
.report(report)
|
||||||
|
.quiz(quiz)
|
||||||
|
.build();
|
||||||
|
answerList.add(answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
report.setAllCount(quizList.size());
|
||||||
|
report.setCorrectCount(correctCount);
|
||||||
|
|
||||||
|
reportRepository.save(report);
|
||||||
|
|
||||||
|
answerRepository.saveAll(answerList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReportDetailResponseDto reportDetail(long reportId) {
|
||||||
|
|
||||||
|
Report report = reportRepository.findById(reportId).orElseThrow(NoSuchElementException::new);
|
||||||
|
|
||||||
|
QuizSet quizSet = quizSetRepository.findById(report.getQuizSet().getId()).orElseThrow(NoSuchElementException::new);
|
||||||
|
|
||||||
|
List<QuizDto> quizDtos = new ArrayList<>();
|
||||||
|
|
||||||
|
List<Answer> myAnswer = answerRepository.findByReportId(report.getId());
|
||||||
|
|
||||||
|
for (Answer answer : myAnswer) {
|
||||||
|
Quiz quiz = quizRepository.findById(answer.getQuiz().getId()).orElse(null);
|
||||||
|
|
||||||
|
List<ChoiceDto> choiceDtos = quiz.getChoices()
|
||||||
|
.stream()
|
||||||
|
.map(Choice::makeChoiceDto)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
QuizDto quizDto = QuizDto.builder()
|
||||||
|
.id(quiz.getId())
|
||||||
|
.question(quiz.getQuestion())
|
||||||
|
.image(quiz.getImage())
|
||||||
|
.question(quiz.getQuestion())
|
||||||
|
.answer(quiz.getAnswer())
|
||||||
|
.userAnswer(answer.getUserAnswer())
|
||||||
|
.isCorrect(answer.isCorrect())
|
||||||
|
.choices(choiceDtos)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
quizDtos.add(quizDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return ReportDetailResponseDto.builder()
|
||||||
|
.title(quizSet.getTitle())
|
||||||
|
.testAt(report.getTestAt())
|
||||||
|
.allCount(report.getAllCount())
|
||||||
|
.correctCount(report.getCorrectCount())
|
||||||
|
.quizzes(quizDtos)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ReportSetResponse> findReportSets(long lectureId) {
|
||||||
|
List<ReportSet> reportSets = reportSetRepository.findByLectureIdOrderById(lectureId);
|
||||||
|
|
||||||
|
return reportSets.stream()
|
||||||
|
.map(ReportSet::makeReportSetResponse)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ReportResponse> findReports(UUID reportSetId) {
|
||||||
|
List<Report> reports = reportRepository.findByReportSetIdOrderById(reportSetId);
|
||||||
|
|
||||||
|
return reports.stream()
|
||||||
|
.map(Report::makeReportResponse)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ReportResponse> findReports(long lectureId, long userId) {
|
||||||
|
List<Report> reports = reportRepository.findByLectureIdAndUserIdOrderById(lectureId, userId);
|
||||||
|
|
||||||
|
return reports.stream()
|
||||||
|
.map(Report::makeReportResponse)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID initReportSet(long lectureId, long quizSetId) {
|
||||||
|
ReportSet reportSet = ReportSet.builder()
|
||||||
|
.lecture(lectureRepository.getReferenceById(lectureId))
|
||||||
|
.quizSet(quizSetRepository.getReferenceById(quizSetId))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
reportSetRepository.save(reportSet);
|
||||||
|
|
||||||
|
QuizSet quizSet = quizSetRepository.getReferenceById(quizSetId);
|
||||||
|
|
||||||
|
List<Registration> registrations = registrationRepository.findByLectureIdAndStatus(lectureId, RegistrationStatus.ACCEPTED);
|
||||||
|
|
||||||
|
List<Report> reports = registrations.stream()
|
||||||
|
.map((Registration registration)-> registration.makeReport(reportSet, quizSet, lectureId))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
reportRepository.saveAll(reports);
|
||||||
|
|
||||||
|
return reportSet.getId();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteReportSet(UUID reportSetId, long userId) {
|
||||||
|
ReportSet reportSet = reportSetRepository.findById(reportSetId).orElseThrow(NoSuchElementException::new);
|
||||||
|
if(reportSet.findUserId() == userId)
|
||||||
|
reportSetRepository.delete(reportSet);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.edufocus.edufocus.swagger;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.models.Components;
|
||||||
|
import io.swagger.v3.oas.models.OpenAPI;
|
||||||
|
import io.swagger.v3.oas.models.info.Info;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class SwaggerConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public OpenAPI openAPI() {
|
||||||
|
return new OpenAPI()
|
||||||
|
.info(new Info()
|
||||||
|
.title("에듀포커스 API")
|
||||||
|
.description("")
|
||||||
|
|
||||||
|
.version("1.0.0"));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package com.edufocus.edufocus.user.config;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.user.intercepter.JWTInterceptor;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebMvc
|
||||||
|
public class WebConfiguration implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
private JWTInterceptor jwtInterceptor;
|
||||||
|
|
||||||
|
public WebConfiguration(JWTInterceptor jwtInterceptor) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.jwtInterceptor = jwtInterceptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
@Override
|
||||||
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
|
registry
|
||||||
|
.addMapping("/**")
|
||||||
|
.allowedOriginPatterns("https://i11a701.p.ssafy.io/", "https://localhost:5173", "http://localhost:5173", "http://localhost:4173", "http://localhost:5080", "http://192.168.*.*:5173")
|
||||||
|
.allowedMethods("GET", "POST", HttpMethod.GET.name(), HttpMethod.POST.name(), HttpMethod.PUT.name(),
|
||||||
|
HttpMethod.DELETE.name(), HttpMethod.HEAD.name(), HttpMethod.OPTIONS.name(),
|
||||||
|
HttpMethod.PATCH.name())
|
||||||
|
.allowCredentials(true)
|
||||||
|
.allowedHeaders("*")
|
||||||
|
.maxAge(1800); // Pre-flight Caching
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||||
|
registry.addResourceHandler("/img/**").addResourceLocations("classpath:/static/assets/img/");
|
||||||
|
registry.addResourceHandler("/*.html**").addResourceLocations("classpath:/static/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
registry.addInterceptor(jwtInterceptor)
|
||||||
|
.addPathPatterns("/**") // 모든 경로에 대해 인터셉터 적용
|
||||||
|
.excludePathPatterns("/v3/api-docs/**", "/swagger-resources/**", "/webjars/**", "/swagger-ui/**", "/auth/**", "/board/**", "/user/**", "/lecture/**", "/qna/**", "/quiz/**", "/video/**", "/registration/**", "/report/**", "/mail/**"); // 인증 없이 접근 가능한 경로 설정
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,203 @@
|
|||||||
|
package com.edufocus.edufocus.user.controller;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.user.model.entity.dto.InfoDto;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.dto.PasswordDto;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.dto.RequestJoinDto;
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.User;
|
||||||
|
import com.edufocus.edufocus.user.model.exception.InvalidTokenException;
|
||||||
|
import com.edufocus.edufocus.user.model.service.UserService;
|
||||||
|
import com.edufocus.edufocus.user.util.JWTUtil;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import jakarta.servlet.http.Cookie;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/user")
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@CrossOrigin(origins = "http://localhost:5173", allowedHeaders = "*", allowCredentials = "true")
|
||||||
|
public class UserController {
|
||||||
|
|
||||||
|
private final UserService userService;
|
||||||
|
private final JWTUtil jwtUtil;
|
||||||
|
|
||||||
|
@PostMapping("/join")
|
||||||
|
public ResponseEntity<String> join(@RequestBody RequestJoinDto requestJoinDto) {
|
||||||
|
|
||||||
|
if (userService.isUserIdExist(requestJoinDto.getUserId()))
|
||||||
|
return new ResponseEntity<>("아이디가 중복 됐습니다.", HttpStatus.CONFLICT);
|
||||||
|
|
||||||
|
if (userService.isEmailExist(requestJoinDto.getEmail()))
|
||||||
|
return new ResponseEntity<>("이메일이 중복 됐습니다.", HttpStatus.CONFLICT);
|
||||||
|
|
||||||
|
userService.join(requestJoinDto);
|
||||||
|
|
||||||
|
return ResponseEntity.ok("User registered successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/updateinfo")
|
||||||
|
public ResponseEntity<String> updateUserInfo(@RequestBody InfoDto infoDto, HttpServletRequest request) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
|
||||||
|
userService.changeUserInfo(infoDto, userId);
|
||||||
|
return ResponseEntity.ok("Password changed successfully");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).body(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 비밀번호 변경
|
||||||
|
@PutMapping("/updatepassword")
|
||||||
|
public ResponseEntity<String> updatePassword(@RequestBody PasswordDto passwordDto, HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
|
||||||
|
userService.changePassword(passwordDto, userId);
|
||||||
|
return ResponseEntity.ok("Password changed successfully");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).body(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 비밀번호 찾기를 통한 변경
|
||||||
|
@PutMapping("/updateforgottenpassword")
|
||||||
|
public ResponseEntity<String> updatePassword(@RequestParam String email,
|
||||||
|
@RequestParam String newPassword) {
|
||||||
|
userService.changeForgottenPassword(email, newPassword);
|
||||||
|
return new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "로그인", description = "아이디와 비밀번호를 이용하여 로그인 처리.")
|
||||||
|
@PostMapping("/login")
|
||||||
|
public ResponseEntity<Map<String, Object>> login(
|
||||||
|
@RequestBody @Parameter(description = "로그인 시 필요한 회원정보(아이디, 비밀번호).", required = true) User user, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
|
||||||
|
Map<String, Object> resultMap = new HashMap<>();
|
||||||
|
HttpStatus status = HttpStatus.ACCEPTED;
|
||||||
|
|
||||||
|
User loginUser = userService.login(user);
|
||||||
|
if (loginUser == null)
|
||||||
|
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
|
||||||
|
|
||||||
|
String accessToken = jwtUtil.createAccessToken(String.valueOf(loginUser.getId()));
|
||||||
|
String refreshToken = jwtUtil.createRefreshToken(String.valueOf(loginUser.getId()));
|
||||||
|
|
||||||
|
userService.saveRefreshToken(loginUser.getId(), refreshToken);
|
||||||
|
|
||||||
|
resultMap.put("name", loginUser.getName());
|
||||||
|
resultMap.put("role", loginUser.getRole());
|
||||||
|
resultMap.put("access-token", accessToken);
|
||||||
|
|
||||||
|
setCookies(response, refreshToken);
|
||||||
|
|
||||||
|
status = HttpStatus.CREATED;
|
||||||
|
|
||||||
|
|
||||||
|
return new ResponseEntity<>(resultMap, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/logout")
|
||||||
|
public ResponseEntity<?> removeToken(HttpServletRequest request) {
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
|
||||||
|
userService.deleteRefreshToken(userId);
|
||||||
|
|
||||||
|
return new ResponseEntity<Map<String, Object>>(HttpStatus.ACCEPTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Access Token 재발급", description = "만료된 access token 을 재발급 받는다.")
|
||||||
|
@PostMapping("/refresh")
|
||||||
|
public ResponseEntity<?> refreshToken(HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
Cookie[] cookies = request.getCookies();
|
||||||
|
String token = null;
|
||||||
|
if (cookies != null) {
|
||||||
|
for (Cookie cookie : cookies) {
|
||||||
|
if (cookie.getName().equals("refresh-token")) {
|
||||||
|
token = cookie.getValue();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
jwtUtil.checkToken(token);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidTokenException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Long userId = Long.parseLong(jwtUtil.getUserId(token));
|
||||||
|
|
||||||
|
if (!token.equals(userService.getRefreshToken(userId))) {
|
||||||
|
throw new InvalidTokenException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String accessToken = jwtUtil.createAccessToken(String.valueOf(userId));
|
||||||
|
String refreshToken = jwtUtil.createRefreshToken(String.valueOf(userId));
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, Object> resultMap = new HashMap<>();
|
||||||
|
resultMap.put("access-token", accessToken);
|
||||||
|
|
||||||
|
userService.saveRefreshToken(userId, refreshToken);
|
||||||
|
|
||||||
|
setCookies(response, refreshToken);
|
||||||
|
|
||||||
|
return new ResponseEntity<Map<String, Object>>(resultMap, HttpStatus.CREATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "회원 정보 조회", description = "토큰을 이용하여 회원 정보를 조회한다.")
|
||||||
|
@GetMapping("/userinfo")
|
||||||
|
public ResponseEntity<Map<String, Object>> getMember(HttpServletRequest request) {
|
||||||
|
Map<String, Object> resultMap = new HashMap<>();
|
||||||
|
HttpStatus status = HttpStatus.ACCEPTED;
|
||||||
|
String token = request.getHeader("Authorization");
|
||||||
|
|
||||||
|
if (jwtUtil.checkToken(token)) {
|
||||||
|
String userId = jwtUtil.getUserId(token);
|
||||||
|
log.info("사용 가능한 토큰!!! userId: {}", userId);
|
||||||
|
try {
|
||||||
|
User user = userService.userInfo(Long.parseLong(userId));
|
||||||
|
resultMap.put("userInfo", user);
|
||||||
|
status = HttpStatus.OK;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("정보조회 실패 : {}", e);
|
||||||
|
resultMap.put("message", e.getMessage());
|
||||||
|
status = HttpStatus.INTERNAL_SERVER_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.error("사용 불가능 토큰!!!");
|
||||||
|
status = HttpStatus.UNAUTHORIZED;
|
||||||
|
}
|
||||||
|
return new ResponseEntity<Map<String, Object>>(resultMap, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void setCookies(HttpServletResponse response, String refreshToken) {
|
||||||
|
Cookie refreshCookie = new Cookie("refresh-token", refreshToken);
|
||||||
|
refreshCookie.setPath("/");
|
||||||
|
refreshCookie.setHttpOnly(true);
|
||||||
|
refreshCookie.setSecure(true);
|
||||||
|
response.addCookie(refreshCookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.edufocus.edufocus.user.intercepter;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.user.model.exception.UnAuthorizedException;
|
||||||
|
import com.edufocus.edufocus.user.util.JWTUtil;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class JWTInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
|
private final String HEADER_AUTH = "Authorization";
|
||||||
|
|
||||||
|
private JWTUtil jwtUtil;
|
||||||
|
|
||||||
|
public JWTInterceptor(JWTUtil jwtUtil) {
|
||||||
|
super();
|
||||||
|
this.jwtUtil = jwtUtil;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
|
||||||
|
final String token = request.getHeader(HEADER_AUTH);
|
||||||
|
jwtUtil.checkToken(token);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.edufocus.edufocus.user.model.entity.dto;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
|
||||||
|
public class InfoDto {
|
||||||
|
|
||||||
|
String name;
|
||||||
|
String email;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.edufocus.edufocus.user.model.entity.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@ToString
|
||||||
|
@Data
|
||||||
|
public class MemberChangeDto {
|
||||||
|
Long id;
|
||||||
|
String password;
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.edufocus.edufocus.user.model.entity.dto;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
public class PasswordDto {
|
||||||
|
String currentPassword;
|
||||||
|
String newPassword;
|
||||||
|
String newPasswordCheck;
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.edufocus.edufocus.user.model.entity.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RefreshTokenDto {
|
||||||
|
private String Token;
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.edufocus.edufocus.user.model.entity.dto;
|
||||||
|
|
||||||
|
import com.edufocus.edufocus.user.model.entity.vo.UserRole;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class RequestJoinDto {
|
||||||
|
private String userId;
|
||||||
|
private String email;
|
||||||
|
private String password;
|
||||||
|
private UserRole role;
|
||||||
|
private String name;
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.edufocus.edufocus.user.model.entity.vo;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.Pattern;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY) // 자동 증가 설정
|
||||||
|
@Column(name = "id")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
|
||||||
|
@Column(name = "user_id", unique = true, nullable = false)
|
||||||
|
@Pattern(regexp = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,16}", message = "비밀번호는 8~16자 영문 대 소문자, 숫자, 특수문자를 사용하세요.")
|
||||||
|
@NotBlank(message = "아이디는 필수 입력 값입니다.")
|
||||||
|
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
@Pattern(regexp = "^(?:\\w+\\.?)*\\w+@(?:\\w+\\.)+\\w+$", message = "이메일 형식이 올바르지 않습니다.")
|
||||||
|
private String email;
|
||||||
|
private String password;
|
||||||
|
@Enumerated(EnumType.STRING) // 혹은 EnumType.ORDINAL
|
||||||
|
private UserRole role;
|
||||||
|
private String refreshToken;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.edufocus.edufocus.user.model.entity.vo;
|
||||||
|
|
||||||
|
public enum UserRole {
|
||||||
|
STUDENT,ADMIN
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.edufocus.edufocus.user.model.exception;
|
||||||
|
|
||||||
|
public class ExpriedTokenException extends RuntimeException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public ExpriedTokenException() {
|
||||||
|
super("계정 권한이 유효하지 않습니다.\n다시 로그인을 하세요.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.edufocus.edufocus.user.model.exception;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
|
||||||
|
@ControllerAdvice
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
@ExceptionHandler(InvalidTokenException.class)
|
||||||
|
public ResponseEntity<String> handleInvalidTokenException(InvalidTokenException e) {
|
||||||
|
return new ResponseEntity<>(e.getMessage(), HttpStatus.FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
@ExceptionHandler(ExpriedTokenException.class)
|
||||||
|
public ResponseEntity<String> handleExpiredTokenException(ExpriedTokenException e) {
|
||||||
|
return new ResponseEntity<>(e.getMessage(), HttpStatus.UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(UserException.class)
|
||||||
|
public ResponseEntity<String> handleUserException(UserException e) {
|
||||||
|
return new ResponseEntity<>(e.getMessage(), HttpStatus.FORBIDDEN);//수정해야함
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.edufocus.edufocus.user.model.exception;
|
||||||
|
|
||||||
|
public class InvalidTokenException extends RuntimeException {
|
||||||
|
public InvalidTokenException() {
|
||||||
|
super("Token is invalid");
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user