Merge branch 'backend' into be/ws

This commit is contained in:
yulmam 2024-07-31 12:57:29 +09:00 committed by GitHub
commit cfb999e7e7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
56 changed files with 1115 additions and 340 deletions

View File

@ -2,7 +2,9 @@ package com.edufocus.edufocus;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@EnableJpaAuditing
@SpringBootApplication
public class EdufocusApplication {

View File

@ -19,7 +19,6 @@ import java.util.List;
*/
@RestController
@RequestMapping("/board")
@CrossOrigin("*")
public class BoardController {
private final JWTUtil jwtUtil;

View File

@ -5,7 +5,7 @@ import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalTime;
import java.time.LocalDateTime;
@Builder
@Getter
@ -17,6 +17,6 @@ public class ResponseBoardDetailDto {
private String title;
private String content;
private int viewCount;
private LocalTime createdAt;
private LocalTime modifiedAt;
private LocalDateTime createdAt;
private LocalDateTime modifiedAt;
}

View File

@ -5,6 +5,8 @@ import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
@Builder
@Getter
@Setter
@ -12,4 +14,5 @@ public class ResponseBoardSummaryDto {
private long id;
private String name;
private String title;
private LocalDateTime createdAt;
}

View File

@ -4,6 +4,7 @@ import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
import java.time.LocalTime;
@Builder
@ -13,6 +14,6 @@ public class ResponseCommentDto {
private long id;
private String name;
private String content;
private LocalTime createAt;
private LocalTime modifiedAt;
private LocalDateTime createAt;
private LocalDateTime modifiedAt;
}

View File

@ -8,8 +8,11 @@ import com.edufocus.edufocus.user.model.entity.User;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.CreationTimestamp;
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.time.LocalTime;
import java.util.List;
@ -18,6 +21,7 @@ import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
@Setter
@EntityListeners(AuditingEntityListener.class)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class Board {
@ -37,11 +41,11 @@ public class Board {
@Column(nullable = true)
private int viewCount;
@CreationTimestamp
LocalTime createdAt;
@CreatedDate
LocalDateTime createdAt;
@CreationTimestamp
LocalTime modifiedAt;
@LastModifiedDate
LocalDateTime modifiedAt;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
@ -60,6 +64,7 @@ public class Board {
.id(id)
.title(title)
.name(user.getUserId())
.createdAt(createdAt)
.build();
}

View File

@ -10,7 +10,7 @@ import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.time.LocalTime;
import java.time.LocalDateTime;
@Entity
@Builder
@ -26,10 +26,10 @@ public class Comment {
private String content;
@Column
private LocalTime createdAt;
private LocalDateTime createdAt;
@Column
private LocalTime modifiedAt;
private LocalDateTime modifiedAt;
@ManyToOne
@JoinColumn(name = "user_id")

View File

@ -5,15 +5,14 @@ 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.model.entity.User;
import com.edufocus.edufocus.user.model.service.UserService;
import com.edufocus.edufocus.user.model.service.UserServiceImpl;
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.List;
@ -26,19 +25,19 @@ public class LectureController {
private final LectureService lectureService;
private final JWTUtil jwtUtil;
@PostMapping
public ResponseEntity<?> createLecture(@RequestHeader("Authorization") String accessToken, @RequestBody LectureCreateRequest lectureCreateRequest) {
@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) {
String msg = new String("Duplicated Lecture");
return new ResponseEntity<>(msg, HttpStatus.CONFLICT);
return new ResponseEntity<>(HttpStatus.CONFLICT);
}
lectureService.createLecture(userId, lectureCreateRequest);
String msg = new String("Lecture registered successfully");
return new ResponseEntity<>(msg, HttpStatus.CREATED);
lectureService.createLecture(userId, lectureCreateRequest, image);
return new ResponseEntity<>(HttpStatus.CREATED);
}
@PutMapping("/{lectureId}")
@ -46,11 +45,9 @@ public class LectureController {
Long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
if (!lectureService.updateLecture(userId, lectureId, lectureCreateRequest)) {
String msg = new String("Can't update Lecture");
return new ResponseEntity<>(msg, HttpStatus.UNAUTHORIZED);
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
String msg = new String("Lecture updated successfully");
return new ResponseEntity<>(msg, HttpStatus.OK);
return new ResponseEntity<>(HttpStatus.OK);
}
@ -59,8 +56,7 @@ public class LectureController {
Long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
if (!lectureService.deleteLecture(userId, lectureId)) {
String msg = new String("Can't delete Lecture");
return new ResponseEntity<>(msg, HttpStatus.UNAUTHORIZED);
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
@ -70,11 +66,6 @@ public class LectureController {
public ResponseEntity<?> findAllLecture() {
List<LectureSearchResponse> lectures = lectureService.findAllLecture();
if (lectures.isEmpty()) {
String msg = new String("No lectures found");
return new ResponseEntity<>(msg, HttpStatus.OK);
}
return new ResponseEntity<>(lectures, HttpStatus.OK);
}
@ -85,34 +76,21 @@ public class LectureController {
if (accessToken != null) {
userId = Long.parseLong(jwtUtil.getUserId(accessToken));
}
LectureDetailResponse lectureDetailResponse = lectureService.findLectureById(userId, lectureId);
if (lectureDetailResponse == null) {
String msg = new String("Can't find Lecture");
return new ResponseEntity<>(msg, HttpStatus.OK);
}
return new ResponseEntity<>(lectureDetailResponse, HttpStatus.OK);
}
@GetMapping("/mylecture")
public ResponseEntity<?> findMyLecture(@RequestHeader(value = "Authorization", required = false) String accessToken) {
if (accessToken == null) {
String msg = new String("Not logged in");
return new ResponseEntity<>(msg, HttpStatus.OK);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
Long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
List<LectureSearchResponse> myLectures = lectureService.findMyLecture(userId);
if (myLectures.isEmpty()) {
String msg = new String("No lectures found");
return new ResponseEntity<>(msg, HttpStatus.OK);
}
return new ResponseEntity<>(myLectures, HttpStatus.OK);
}
}

View File

@ -15,7 +15,8 @@ import java.util.Date;
@AllArgsConstructor
public class Lecture {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private Long id;
@ -29,6 +30,9 @@ public class Lecture {
@Lob
private String description;
@Lob
private String plan;
@Column
private String image;
@ -40,10 +44,10 @@ public class Lecture {
@Temporal(TemporalType.DATE)
private Date endDate;
@Lob
private String plan;
@Column
private String time;
@Column(columnDefinition = "boolean default false")
private boolean online;
}

View File

@ -15,12 +15,12 @@ public class LectureCreateRequest {
private String description;
private String image;
private String plan;
private Date startDate;
private Date endDate;
private String plan;
private String time;
}

View File

@ -21,13 +21,15 @@ public class LectureDetailResponse {
private String description;
private String plan;
private String image;
private Date startDate;
private Date endDate;
private String plan;
private String time;
private boolean online;

View File

@ -5,6 +5,7 @@ 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;
@ -12,7 +13,7 @@ import java.util.List;
@Service
public interface LectureService {
void createLecture(long userId, LectureCreateRequest lectureCreateRequest);
void createLecture(long userId, LectureCreateRequest lectureCreateRequest, MultipartFile image) throws Exception;
boolean updateLecture(long userId, long lectureId, LectureCreateRequest lectureCreateRequest);
@ -25,4 +26,10 @@ public interface LectureService {
List<LectureSearchResponse> findMyLecture(long userId);
Lecture findLectureByTitle(String title);
void changeState(Long lectureId);
boolean getState(Long lectureId);
boolean checkTeacher(Long userId, Long lectureId);
}

View File

@ -11,11 +11,14 @@ import com.edufocus.edufocus.user.model.repository.UserRepository;
import jakarta.transaction.Transactional;
import lombok.Builder;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.io.File;
import java.io.IOException;
import java.util.*;
@Builder
@Service
@ -30,19 +33,35 @@ public class LectureServiceImpl implements LectureService {
private final RegistrationRepository registrationRepository;
@Override
public void createLecture(long userId, LectureCreateRequest lectureCreateRequest) {
public void createLecture(long userId, LectureCreateRequest lectureCreateRequest, MultipartFile image) throws IOException {
User user = userRepository.findById(userId).get();
Lecture lecture = new Lecture().builder()
.user(user)
.title(lectureCreateRequest.getTitle())
.description(lectureCreateRequest.getDescription())
.image(lectureCreateRequest.getImage())
.plan(lectureCreateRequest.getPlan())
.startDate(lectureCreateRequest.getStartDate())
.endDate(lectureCreateRequest.getEndDate())
.plan(lectureCreateRequest.getPlan())
.time(lectureCreateRequest.getTime())
.build();
if (image != null && !image.isEmpty()) {
String uid = UUID.randomUUID().toString();
String currentPath = "backend/src/main/resources/images/";
File checkPathFile = new File(currentPath);
if (!checkPathFile.exists()) {
checkPathFile.mkdirs();
}
File savingImage = new File(currentPath + uid + "_" + image.getOriginalFilename());
image.transferTo(savingImage.toPath());
String savePath = savingImage.toPath().toString();
lecture.setImage(savePath);
}
lectureRepository.save(lecture);
}
@ -60,8 +79,8 @@ public class LectureServiceImpl implements LectureService {
if (lectureCreateRequest.getDescription() != null) {
lecture.setDescription(lectureCreateRequest.getDescription());
}
if (lectureCreateRequest.getImage() != null) {
lecture.setImage(lectureCreateRequest.getImage());
if (lectureCreateRequest.getPlan() != null) {
lecture.setPlan(lectureCreateRequest.getPlan());
}
if (lectureCreateRequest.getStartDate() != null) {
lecture.setStartDate(lectureCreateRequest.getStartDate());
@ -69,8 +88,8 @@ public class LectureServiceImpl implements LectureService {
if (lectureCreateRequest.getEndDate() != null) {
lecture.setEndDate(lectureCreateRequest.getEndDate());
}
if (lectureCreateRequest.getPlan() != null) {
lecture.setPlan(lectureCreateRequest.getPlan());
if (lectureCreateRequest.getTime() != null) {
lecture.setTime(lectureCreateRequest.getTime());
}
lectureRepository.save(lecture);
@ -114,11 +133,9 @@ public class LectureServiceImpl implements LectureService {
@Override
public LectureDetailResponse findLectureById(Long userId, long lectureId) {
Optional<Lecture> lecture = lectureRepository.findById(lectureId);
if (lecture.isEmpty()) {
return null;
}
lecture = Optional.of(lecture.get());
String userStatus;
if (userId == null) {
@ -149,10 +166,11 @@ public class LectureServiceImpl implements LectureService {
.id(lecture.get().getId())
.title(lecture.get().getTitle())
.description(lecture.get().getDescription())
.plan(lecture.get().getPlan())
.image(lecture.get().getImage())
.startDate(lecture.get().getStartDate())
.endDate(lecture.get().getEndDate())
.plan(lecture.get().getPlan())
.time(lecture.get().getTime())
.online(lecture.get().isOnline())
.teacherName(lecture.get().getUser().getName())
.status(userStatus)
@ -198,4 +216,41 @@ public class LectureServiceImpl implements LectureService {
public Lecture findLectureByTitle(String title) {
return lectureRepository.findByTitle(title);
}
@Override
public void changeState(Long id) {
Optional<Lecture> lecture = lectureRepository.findById(id);
Lecture l;
if (lecture.isPresent()) {
l = lecture.get();
System.out.println(l.isOnline());
l.setOnline(true);
System.out.println(l.isOnline());
} else {
throw new RuntimeException("Lecture not found with id: " + id);
}
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;
}
}

View File

@ -106,9 +106,9 @@ public class QnaController {
}
@GetMapping("/{id}")
public ResponseEntity<Qna> getQna(@PathVariable Long id) {
public ResponseEntity<QnaResponseDto> getQna(@PathVariable Long id) {
try{
Qna findQna= qnaService.getQna(id);
QnaResponseDto findQna= qnaService.getQna(id);
return new ResponseEntity<>(findQna, HttpStatus.ACCEPTED);
} catch (SQLException e) {

View File

@ -14,6 +14,7 @@ import java.util.Date;
public class QnaResponseDto {
private Long id;
private String title;
private String username;
private String content;
@ -22,7 +23,7 @@ public class QnaResponseDto {
public static QnaResponseDto toEntity(Qna qna)
{
return new QnaResponseDto(
qna.getId(),
qna.getTitle(),
qna.getUser().getName(),
qna.getContent(),

View File

@ -13,7 +13,6 @@ import java.util.List;
@Repository
public interface QnaRepository extends JpaRepository<Qna, Long> {
List<Qna> findByLectureId(Long lecturerId);
Page<Qna> findByLectureId(Long lectureId, Pageable pageable);
}

View File

@ -16,7 +16,7 @@ public interface QnaService {
QnaResponseDto createQna(Long id, QnaRequestDto qnaRequestDto, Long lecture_id) throws SQLException;
QnaResponseDto updateQna(Long id,QnaRequestDto qnaRequestDto) throws SQLException;
void deleteQna(Long id) throws SQLException;
Qna getQna(Long id) throws SQLException;
QnaResponseDto getQna(Long id) throws SQLException;
List<QnaResponseDto> getAllQnasByLecture(Long lectureId,int pageNumber) throws SQLException;
QnaResponseDto createAnswer(Long id,QnaRequestDto qnaRequestDto) throws SQLException;

View File

@ -80,8 +80,22 @@ qnaRepository.deleteById(id);
}
@Override
public Qna getQna(Long id) {
return null;
public QnaResponseDto getQna(Long id) {
Optional<Qna> qna;
try {
qna= qnaRepository.findById(id);
} catch (Exception e) {
throw new RuntimeException("Qna 없음 " + id, e);
}
return QnaResponseDto.toEntity(qna.get());
}
@Override

View File

@ -1,18 +1,18 @@
package com.edufocus.edufocus.quiz.controller;
import com.edufocus.edufocus.quiz.entity.*;
import com.edufocus.edufocus.quiz.repository.QuizRepository;
import com.edufocus.edufocus.quiz.service.QuizService;
import com.edufocus.edufocus.quiz.service.QuizSetService;
import com.edufocus.edufocus.user.model.service.UserService;
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.io.IOException;
import java.util.List;
@RestController
@ -25,24 +25,18 @@ public class QuizController {
private final QuizSetService quizSetService;
private final UserService userService;
private final JWTUtil jwtUtil;
private final QuizRepository quizRepository;
@PostMapping
public ResponseEntity<?> createQuizSet(@RequestHeader("Authorization") String accessToken, @RequestBody QuizSetCreateRequest quizSetCreateRequest) {
@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));
String title = quizSetCreateRequest.getTitle();
String image = quizSetCreateRequest.getImage();
SetCreateRequest setCreateRequest = new SetCreateRequest(userId, title, image);
QuizSet quizSet = quizSetService.createQuizSet(setCreateRequest);
QuizSet quizSet = quizSetService.createQuizSet(userId, quizSetCreateRequest.getTitle());
int imageIdx = 0;
for (QuizCreateRequest quizCreateRequest : quizSetCreateRequest.getQuizzes()) {
quizService.createQuiz(quizSet.getId(), quizCreateRequest);
quizService.createQuiz(quizSet, quizCreateRequest, images.get(imageIdx++));
}
return new ResponseEntity<>(HttpStatus.CREATED);
@ -50,8 +44,30 @@ public class QuizController {
@GetMapping("/{quizsetId}")
public ResponseEntity<?> getQuizzes(@PathVariable Long quizsetId) {
QuizSet quizSet = quizSetService.findQuizSet(quizsetId);
QuizSetResponse quizSet = quizSetService.findQuizSetResponse(quizsetId);
if (quizSet == null) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(quizSet, 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);
}
}

View File

@ -0,0 +1,29 @@
package com.edufocus.edufocus.quiz.entity;
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;
}

View File

@ -7,12 +7,9 @@ import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class SetCreateRequest {
public class ChoiceCreateRequest {
private Long UserId;
private String title;
private String image;
private int num;
private String content;
}

View File

@ -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;
}

View File

@ -5,6 +5,8 @@ import com.fasterxml.jackson.annotation.JsonManagedReference;
import jakarta.persistence.*;
import lombok.*;
import java.util.List;
@Entity
@Getter
@Setter
@ -23,31 +25,17 @@ public class Quiz {
private QuizSet quizSet;
@Column
private String title;
@Column
private String description;
@Column
private String answer;
@Column (name = "is_single")
private boolean isSingle;
private String question;
@Column
private String image;
@Column
private String choice1;
private String answer;
@Column
private String choice2;
@Column
private String choice3;
@Column
private String choice4;
@OneToMany(mappedBy = "quiz", orphanRemoval = true, cascade = CascadeType.ALL)
@JsonManagedReference
private List<Choice> choices;
public void setQuizSet(QuizSet quizSet) {
this.quizSet = quizSet;
@ -56,4 +44,12 @@ public class Quiz {
quizSet.getQuizzes().remove(this);
}
}
public void addChoice(Choice choice) {
this.choices.add(choice);
if (choice.getQuiz() != this) {
choice.setQuiz(this);
}
}
}

View File

@ -4,26 +4,16 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.List;
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class QuizCreateRequest {
private String title;
private String description;
private String question;
private String answer;
private boolean isSingle;
private String image;
private String choice1;
private String choice2;
private String choice3;
private String choice4;
private List<ChoiceCreateRequest> choices;
}

View File

@ -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;
}

View File

@ -27,12 +27,9 @@ public class QuizSet {
@Column
private String title;
@Column
private String image;
@OneToMany(mappedBy = "quizSet")
@OneToMany(mappedBy = "quizSet", orphanRemoval = true)
@JsonManagedReference
private List<Quiz> quizzes = new ArrayList<Quiz>();
private List<Quiz> quizzes = new ArrayList<Quiz>();
public void addQuiz(Quiz quiz) {
this.quizzes.add(quiz);

View File

@ -11,12 +11,8 @@ import java.util.List;
@AllArgsConstructor
public class QuizSetCreateRequest {
private Long UserId;
private String title;
private String image;
private List<QuizCreateRequest> quizzes;
}

View File

@ -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;
}

View File

@ -3,7 +3,6 @@ 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> {
}

View File

@ -3,6 +3,9 @@ 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);
}

View File

@ -1,15 +1,16 @@
package com.edufocus.edufocus.quiz.service;
import com.edufocus.edufocus.quiz.entity.QuizCreateRequest;
import com.edufocus.edufocus.quiz.entity.QuizSet;
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(long quizSetId, QuizCreateRequest
QuizCreateRequest);
void createQuiz(QuizSet quizSet, QuizCreateRequest quizCreateRequest, MultipartFile quizImage) throws IOException;
boolean deleteQuiz(long quizId);
}

View File

@ -1,15 +1,18 @@
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.*;
import com.edufocus.edufocus.quiz.repository.QuizRepository;
import com.edufocus.edufocus.quiz.repository.QuizSetRepository;
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.UUID;
@Service
@Transactional
@ -18,39 +21,45 @@ public class QuizServiceImpl implements QuizService {
private final QuizRepository quizRepository;
private final QuizSetRepository quizSetRepository;
@Override
public void createQuiz(long quizSetId, QuizCreateRequest quizCreateRequest) {
QuizSet quizSet = quizSetRepository.findById(quizSetId).get();
public void createQuiz(QuizSet quizSet, QuizCreateRequest quizCreateRequest, MultipartFile quizImage) throws IOException {
Quiz quiz = new Quiz().builder()
.title(quizCreateRequest.getTitle())
.description(quizCreateRequest.getDescription())
.answer(quizCreateRequest.getAnswer())
.image(quizCreateRequest.getImage())
.quizSet(quizSet)
.question(quizCreateRequest.getQuestion())
.answer(quizCreateRequest.getAnswer())
.build();
if (!quiz.isSingle()) {
quiz.setChoice1(quizCreateRequest.getChoice1());
quiz.setChoice2(quizCreateRequest.getChoice2());
quiz.setChoice3(quizCreateRequest.getChoice3());
quiz.setChoice4(quizCreateRequest.getChoice4());
List<Choice> choices = new ArrayList<>();
for (ChoiceCreateRequest choiceCreateRequest : quizCreateRequest.getChoices()) {
Choice choice = new 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 currentPath = "backend/src/main/resources/images/quizzes/";
File checkPathFile = new File(currentPath);
if (!checkPathFile.exists()) {
checkPathFile.mkdirs();
}
File savingImage = new File(currentPath + uid + "_" + quizImage.getOriginalFilename());
quizImage.transferTo(savingImage.toPath());
String savePath = savingImage.toPath().toString();
quiz.setImage(savePath);
}
quizRepository.save(quiz);
}
@Override
public boolean deleteQuiz(long quizId) {
// 유저 아이디 정보 조회 검증 로직 추가 예정
// jwt -> 로그인 유저 정보 조회
// quizId -> 퀴즈 정보 조회 -> 퀴즈셋 정보 조회
// 퀴즈셋 생성자와 로그인 유저의 id값이 일치하는지 확인 -> 불일치시 삭제 실패
quizRepository.deleteById(quizId);
return true;
}
}

View File

@ -1,17 +1,24 @@
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.SetCreateRequest;
import com.edufocus.edufocus.quiz.entity.QuizSetResponse;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public interface QuizSetService {
QuizSet createQuizSet(SetCreateRequest setCreateRequest);
QuizSet createQuizSet(Long userId, String title);
void updateQuizSet(QuizSet quizSet);
void deleteQuizSet(long quizSetId);
boolean deleteQuizSet(Long userId, Long quizSetId);
QuizSet findQuizSet(long quizSetId);
QuizSet findQuizSet(Long quizSetId);
QuizSetResponse findQuizSetResponse(Long quizSetId);
List<MyQuizSetResponse> findMyQuizSetResponses(Long userId);
}

View File

@ -1,7 +1,6 @@
package com.edufocus.edufocus.quiz.service;
import com.edufocus.edufocus.quiz.entity.*;
import com.edufocus.edufocus.quiz.repository.QuizRepository;
import com.edufocus.edufocus.quiz.repository.QuizSetRepository;
import com.edufocus.edufocus.user.model.entity.User;
import com.edufocus.edufocus.user.model.repository.UserRepository;
@ -9,6 +8,10 @@ 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
@ -17,19 +20,14 @@ public class QuizSetServiceImpl implements QuizSetService {
private final QuizSetRepository quizSetRepository;
private final UserRepository userRepository;
private final QuizRepository quizRepository;
@Override
public QuizSet createQuizSet(SetCreateRequest setCreateRequest) {
public QuizSet createQuizSet(Long userId, String title) {
QuizSet quizSet = new QuizSet();
User user = userRepository.findById(setCreateRequest.getUserId()).get();
User user = userRepository.findById(userId).get();
quizSet.setUser(user);
quizSet.setTitle(setCreateRequest.getTitle());
quizSet.setImage(setCreateRequest.getImage());
quizSet.setTitle(title);
return quizSetRepository.save(quizSet);
}
@ -40,12 +38,65 @@ public class QuizSetServiceImpl implements QuizSetService {
}
@Override
public void deleteQuizSet(long quizSetId) {
public boolean deleteQuizSet(Long userId, Long quizSetId) {
Optional<QuizSet> quizSet = quizSetRepository.findById(quizSetId);
if (quizSet.isEmpty() || userId != quizSet.get().getUser().getId()) {
return false;
}
quizSetRepository.deleteById(quizSetId);
return true;
}
@Override
public QuizSet findQuizSet(long quizSetId) {
public QuizSet findQuizSet(Long quizSetId) {
return quizSetRepository.findById(quizSetId).get();
}
@Override
public QuizSetResponse findQuizSetResponse(Long quizSetId) {
Optional<QuizSet> quizSet = quizSetRepository.findById(quizSetId);
if (quizSet.isEmpty()) {
return null;
}
List<QuizResponse> quizResponses = new ArrayList<>();
for (Quiz quiz : quizSet.get().getQuizzes()) {
QuizResponse quizResponse = new QuizResponse().builder()
.question(quiz.getQuestion())
.image(quiz.getImage())
.choices(quiz.getChoices())
.build();
quizResponses.add(quizResponse);
}
QuizSetResponse quizSetResponse = new QuizSetResponse().builder()
.title(quizSet.get().getTitle())
.quizzes(quizResponses)
.build();
return quizSetResponse;
}
@Override
public List<MyQuizSetResponse> findMyQuizSetResponses(Long userId) {
List<QuizSet> quizSetList = quizSetRepository.findQuizSetsByUserId(userId);
List<MyQuizSetResponse> myQuizSetResponses = new ArrayList<>();
for (QuizSet quizSet : quizSetList) {
MyQuizSetResponse myQuizSetResponse = new MyQuizSetResponse().builder()
.quizSetId(quizSet.getId())
.title(quizSet.getTitle())
.build();
myQuizSetResponses.add(myQuizSetResponse);
}
return myQuizSetResponses;
}
}

View File

@ -1,5 +1,6 @@
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;
@ -16,7 +17,9 @@ import java.util.Map;
@RequiredArgsConstructor
public class RegistrationController {
private final RegistrationService registrationServiceImpl;
private final RegistrationService registrationService;
private final LectureService lectureService;
private final JWTUtil jwtUtil;
@ -25,12 +28,10 @@ public class RegistrationController {
Long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
Long lectureId = map.get("lectureId");
if (!registrationServiceImpl.createRegistration(userId, lectureId)) {
String msg = new String("Duplicated Registration");
return new ResponseEntity<>(msg, HttpStatus.CONFLICT);
if (!registrationService.createRegistration(userId, lectureId)) {
return new ResponseEntity<>(HttpStatus.CONFLICT);
}
String msg = new String("registration successful");
return new ResponseEntity<>(HttpStatus.CREATED);
}
@ -38,12 +39,10 @@ public class RegistrationController {
public ResponseEntity<?> acceptRigistration(@RequestHeader("Authorization") String accessToken, @PathVariable long registrationId) {
Long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
if (!registrationServiceImpl.acceptRegistration(userId, registrationId)) {
String msg = new String("Not Acceptable");
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
if (!registrationService.acceptRegistration(userId, registrationId)) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
String msg = new String("registration accepted");
return new ResponseEntity<>(HttpStatus.OK);
}
@ -51,12 +50,22 @@ public class RegistrationController {
public ResponseEntity<?> deleteRigistration(@RequestHeader("Authorization") String accessToken, @PathVariable long registrationId) {
Long userId = Long.parseLong(jwtUtil.getUserId(accessToken));
if (!registrationServiceImpl.deleteRegistration(userId, registrationId)) {
String msg = new String("Not Acceptable");
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
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);
}
}

View File

@ -26,5 +26,5 @@ public class Registration {
private Lecture lecture;
@Enumerated(EnumType.STRING)
private RegistrationStatus status ;
private RegistrationStatus status;
}

View File

@ -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;
}

View File

@ -2,6 +2,7 @@ package com.edufocus.edufocus.registration.repository;
import com.edufocus.edufocus.registration.entity.Registration;
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;
@ -11,5 +12,7 @@ import java.util.List;
public interface RegistrationRepository extends JpaRepository<Registration, Long> {
List<Registration> findAllByUserId(@Param("userId") Long userId);
List<Registration> findAllNotAcceptedByLectureId(@Param("lectureId") Long lectureId);
Registration findByUserIdAndLectureId(Long userId, Long lectureId);
}

View File

@ -1,15 +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 createRegistration(Long userId, Long registrationId);
boolean acceptRegistration(long userId, long RegistrationId);
boolean acceptRegistration(Long userId, Long RegistrationId);
boolean deleteRegistration(long userId, long registrationId);
boolean deleteRegistration(Long userId, Long registrationId);
List<RegistrationSearchResponse> searchRegistrations(Long LectureId);
RegistrationStatus isOnline(Long userId, Long lectureId);
}

View File

@ -1,14 +1,20 @@
package com.edufocus.edufocus.registration.service;
import com.edufocus.edufocus.lecture.entity.Lecture;
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.User;
import com.edufocus.edufocus.user.model.entity.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
@ -21,14 +27,16 @@ public class RegistrationServiceImpl implements RegistrationService {
private final LectureRepository lectureRepository;
@Override
public boolean createRegistration(long userId, long lectureId) {
if (registrationRepository.findByUserIdAndLectureId(userId, lectureId) != null) {
public boolean createRegistration(Long userId, Long lectureId) {
Optional<User> user = userRepository.findById(userId);
if (user.isEmpty() || user.get().getRole().equals(UserRole.ADMIN)) {
return false;
}
Registration registration = new Registration().builder()
.user(userRepository.getReferenceById(userId))
.lecture(lectureRepository.getReferenceById(lectureId))
.user(userRepository.findById(userId).get())
.lecture(lectureRepository.findById(lectureId).get())
.status(RegistrationStatus.WAITING)
.build();
@ -37,24 +45,24 @@ public class RegistrationServiceImpl implements RegistrationService {
}
@Override
public boolean acceptRegistration(long userId, long registrationId) {
Registration registration = registrationRepository.findById(registrationId).get();
public boolean acceptRegistration(Long userId, Long registrationId) {
Optional<Registration> registration = registrationRepository.findById(registrationId);
if (registration.getLecture().getUser().getId() != userId) {
if (registration.isEmpty() || registration.get().getLecture().getUser().getId() != userId) {
return false;
}
registration.setStatus(RegistrationStatus.valueOf("ACCEPTED"));
registrationRepository.save(registration);
registration.get().setStatus(RegistrationStatus.valueOf("ACCEPTED"));
registrationRepository.save(registration.get());
return true;
}
@Override
public boolean deleteRegistration(long userId, long registrationId) {
Registration registration = registrationRepository.findById(registrationId).get();
public boolean deleteRegistration(Long userId, Long registrationId) {
Optional<Registration> registration = registrationRepository.findById(registrationId);
if (registration.getLecture().getUser().getId() != userId) {
if (registration.isEmpty() || registration.get().getLecture().getUser().getId() != userId) {
return false;
}
@ -62,4 +70,28 @@ public class RegistrationServiceImpl implements RegistrationService {
return true;
}
@Override
public List<RegistrationSearchResponse> searchRegistrations(Long lectureId) {
List<Registration> registrations = registrationRepository.findAllNotAcceptedByLectureId(lectureId);
List<RegistrationSearchResponse> responses = new ArrayList<>();
for (Registration registration : registrations) {
RegistrationSearchResponse response = new RegistrationSearchResponse().builder()
.id(registration.getId())
.userName(registration.getUser().getName())
.build();
responses.add(response);
}
return responses;
}
@Override
public RegistrationStatus isOnline(Long userId, Long lectureId) {
Registration registration = registrationRepository.findByUserIdAndLectureId(userId, lectureId);
return registration.getStatus();
}
}

View File

@ -15,6 +15,7 @@ public class SwaggerConfig {
.info(new Info()
.title("에듀포커스 API")
.description("")
.version("1.0.0"));
}
}

View File

@ -26,7 +26,7 @@ public class WebConfiguration implements WebMvcConfigurer {
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedOrigins("http://i11a701.p.ssafy.io/", "http://localhost:5173", "http://localhost:4173")
.allowedOrigins("http://i11a701.p.ssafy.io/", "http://localhost:5173", "http://localhost:4173","http://localhost:5080")
.allowedMethods(HttpMethod.GET.name(), HttpMethod.POST.name(), HttpMethod.PUT.name(),
HttpMethod.DELETE.name(), HttpMethod.HEAD.name(), HttpMethod.OPTIONS.name(),
HttpMethod.PATCH.name())
@ -44,8 +44,6 @@ public class WebConfiguration implements WebMvcConfigurer {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor)
.addPathPatterns("/**") // 모든 경로에 대해 인터셉터 적용
.excludePathPatterns("/v3/api-docs/**","/swagger-resources/**","/webjars/**","/swagger-ui/**","/auth/**", "/board/**", "/user/**","/lecture/**","/qna/**", "/quiz/**"); // 인증 없이 접근 가능한 경로 설정
///v3/api-docs/**, /swagger-resources/**, /webjars/**
.excludePathPatterns("/v3/api-docs/**","/swagger-resources/**","/webjars/**","/swagger-ui/**","/auth/**", "/board/**", "/user/**","/lecture/**","/qna/**", "/quiz/**","/video/**","/registration/**"); // 인증 없이 접근 가능한 경로 설정
}
}

View File

@ -1,6 +1,10 @@
package com.edufocus.edufocus.user.controller;
import com.edufocus.edufocus.user.model.entity.InfoDto;
import com.edufocus.edufocus.user.model.entity.PasswordDto;
import com.edufocus.edufocus.user.model.entity.User;
import com.edufocus.edufocus.user.model.exception.ExpriedTokenException;
import com.edufocus.edufocus.user.model.exception.UnAuthorizedException;
import com.edufocus.edufocus.user.model.service.UserService;
import com.edufocus.edufocus.user.util.JWTUtil;
import io.swagger.v3.oas.annotations.Operation;
@ -41,48 +45,68 @@ public class UserController {
return ResponseEntity.ok("임시 비밀번호가 이메일로 전송되었습니다.");
}
//
// @PostMapping("/login")
// public ResponseEntity<User> login(@RequestBody User user) {
// try {
// User loggedInUser = userService.login(user);
// return ResponseEntity.ok(loggedInUser);
//
// } catch (Exception e) {
// throw new RuntimeException(e);
// }
// }
@PutMapping("/updateinfo/{id}")
public ResponseEntity<String> updateUserInfo(
@PathVariable("id") Long id,
@RequestBody InfoDto infoDto) {
try {
userService.changeuInfo(infoDto, id);
return ResponseEntity.ok("User info updated successfully");
} catch (Exception e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}
// 비밀번호 변경
@PutMapping("/updatepassword/{id}")
public ResponseEntity<String> updatePassword(
@PathVariable("id") Long id,
@RequestBody PasswordDto passwordDto) {
try {
userService.changePassword(passwordDto, id);
return ResponseEntity.ok("Password changed successfully");
} catch (Exception e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}
@Operation(summary = "로그인", description = "아이디와 비밀번호를 이용하여 로그인 처리.")
@PostMapping("/login")
public ResponseEntity<Map<String, Object>> login(
@RequestBody @Parameter(description = "로그인 시 필요한 회원정보(아이디, 비밀번호).", required = true) User user, HttpServletResponse response) {
Map<String, Object> resultMap = new HashMap<>();
HttpStatus status = HttpStatus.ACCEPTED;
try {
User loginUser = userService.login(user);
if (loginUser != null) {
String name = loginUser.getName();
resultMap.put("name",name);
String accessToken = jwtUtil.createAccessToken(String.valueOf(loginUser.getId()));
String refreshToken = jwtUtil.createRefreshToken(String.valueOf(loginUser.getId()));
// 발급받은 refresh token DB에 저장.
userService.saveRefreshToken(loginUser.getId(), refreshToken);
// JSON 으로 token 전달.
System.out.println(accessToken);
resultMap.put("access-token", accessToken);
// resultMap.put("refresh-token", refreshToken);
// 쿠키 저장
resultMap.put("role",loginUser.getRole());
resultMap.put("access-token", accessToken);
Cookie refreshCookie = new Cookie("refresh-token", refreshToken);
refreshCookie.setPath("/");
refreshCookie.setHttpOnly(true);
refreshCookie.setSecure(true); // HTTPS에서만 전송되도록 설정
// refreshCookie.setSecure(true); // HTTPS에서만 전송되도록 설정
// refreshCookie.setSameSite(Cookie.SameSite.NONE); // Cross-Origin 요청에 대해 모두 전송
response.addCookie(refreshCookie);
// 쿠키저장
status = HttpStatus.CREATED;
} else {
resultMap.put("message", "아이디 또는 패스워드를 확인해 주세요.");
@ -100,12 +124,9 @@ public class UserController {
public ResponseEntity<Map<String, Object>> getInfo(
@PathVariable("userId") @Parameter(description = "인증할 회원의 아이디.", required = true) Long userId,
HttpServletRequest request) {
//logger.debug("userId : {} ", userId);
String id = String.valueOf(userId);
System.out.println("!>>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println(id);
System.out.println(id.getClass().getName());
Map<String, Object> resultMap = new HashMap<>();
HttpStatus status = HttpStatus.ACCEPTED;
if (jwtUtil.checkToken(request.getHeader("Authorization"))) {
@ -239,7 +260,15 @@ public class UserController {
}
@ExceptionHandler(ExpriedTokenException.class)
public ResponseEntity<?> handleExpiredTokenException(){
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
@ExceptionHandler(UnAuthorizedException.class)
public ResponseEntity<?> handleUnauthorizedException(){
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}

View File

@ -0,0 +1,15 @@
package com.edufocus.edufocus.user.model.entity;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class InfoDto {
String name;
String email;
}

View File

@ -0,0 +1,14 @@
package com.edufocus.edufocus.user.model.entity;
import lombok.Generated;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class PasswordDto {
String currentPassword;
String newPassword;
String newPasswordCheck;
}

View File

@ -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다시 로그인을 하세요.");
}
}

View File

@ -0,0 +1,25 @@
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> handleUnAuthorizedException(InvalidTokenException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(ExpriedTokenException.class)
public ResponseEntity<String> handleInvalidTokenException(ExpriedTokenException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.UNAUTHORIZED);
}
}

View File

@ -0,0 +1,7 @@
package com.edufocus.edufocus.user.model.exception;
public class InvalidTokenException extends RuntimeException {
public InvalidTokenException() {
super("Token is invalid");
}
}

View File

@ -1,5 +1,7 @@
package com.edufocus.edufocus.user.model.service;
import com.edufocus.edufocus.user.model.entity.InfoDto;
import com.edufocus.edufocus.user.model.entity.PasswordDto;
import com.edufocus.edufocus.user.model.entity.User;
public interface UserService {
@ -11,5 +13,8 @@ public interface UserService {
User userInfo(Long id) throws Exception;
void sendEamail(User user) throws Exception;
void userCheck(Long id) throws Exception;
String getUserName(Long id) throws Exception;
void changeuInfo(InfoDto infoDto,Long id) throws Exception;
void changePassword(PasswordDto passwordDto,Long id) throws Exception;
}

View File

@ -1,9 +1,7 @@
package com.edufocus.edufocus.user.model.service;
import com.edufocus.edufocus.user.model.entity.MailDto;
import com.edufocus.edufocus.user.model.entity.MemberChangeDto;
import com.edufocus.edufocus.user.model.entity.User;
import com.edufocus.edufocus.user.model.entity.*;
import com.edufocus.edufocus.user.model.exception.UserException;
import com.edufocus.edufocus.user.model.repository.UserRepository;
import jakarta.transaction.Transactional;
@ -21,46 +19,41 @@ import java.util.Optional;
@Service
@Transactional
@RequiredArgsConstructor
public class UserServiceImpl implements UserService{
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final JavaMailSender mailSender;
public void join(User user)
{
System.out.println(user.getRole().getClass());
userRepository.save(user);
}
public User login(User user) throws SQLException
{
public User login(User user) throws SQLException {
Optional<User> findUser = userRepository.findByUserId(user.getUserId());
if(findUser.isEmpty())
{
if (findUser.isEmpty()) {
throw new UserException("없는 유저");
}
if(findUser.isPresent())
{
if (findUser.isPresent()) {
User find = findUser.get();
if(find.getPassword().equals(user.getPassword()))
{
if (find.getPassword().equals(user.getPassword())) {
return find;
}
else{
} else {
throw new UserException("비밀번호 틀림");
}
}
else{
} else {
throw new UserException("없는 유저");
@ -69,13 +62,10 @@ public class UserServiceImpl implements UserService{
}
@Override
public User userInfo(Long id)
{
try{
public User userInfo(Long id) {
try {
return userRepository.findById(id).get();
}
catch (Exception e)
{
} catch (Exception e) {
throw new UserException(e.getMessage());
}
@ -85,16 +75,15 @@ public class UserServiceImpl implements UserService{
public void sendEamail(User user) throws Exception {
MailDto mailDto = createMailAndChargePassword(user);
System.out.println("이메일 전송 완료");
SimpleMailMessage message = new SimpleMailMessage();
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(mailDto.getAddress());
message.setFrom("passfinder111@gmail.com");
message.setSubject(mailDto.getTitle());
message.setText(mailDto.getMessage());
System.out.println("!!!!!!!!!!!!!!!!!!"+ message);
mailSender.send(message);
@ -105,16 +94,14 @@ public class UserServiceImpl implements UserService{
String str = getTempPassword();
MailDto dto = new MailDto();
dto.setAddress(user.getEmail());
dto.setTitle(user.getUserId()+"님의 임시비밀번호 안내 이메일 입니다.");
dto.setMessage("안녕하세요. EduFoucs 입니다. "+ "\n"+ "임시비밀번호 안내 관련 메일 입니다." + "\n[" + user.getName() + "]" + "님의 임시 비밀번호는 "
dto.setTitle(user.getUserId() + "님의 임시비밀번호 안내 이메일 입니다.");
dto.setMessage("안녕하세요. EduFoucs 입니다. " + "\n" + "임시비밀번호 안내 관련 메일 입니다." + "\n[" + user.getName() + "]" + "님의 임시 비밀번호는 "
+ str + " 입니다.");
System.out.println(dto);
MemberChangeDto memberChangeDto = new MemberChangeDto(user.getId(),str);
System.out.println(memberChangeDto);
userRepository.updatePassword(memberChangeDto.getId(),memberChangeDto.getPassword());
System.out.println();
MemberChangeDto memberChangeDto = new MemberChangeDto(user.getId(), str);
userRepository.updatePassword(memberChangeDto.getId(), memberChangeDto.getPassword());
return dto;
}
@ -125,17 +112,63 @@ public class UserServiceImpl implements UserService{
User user = userRepository.findById(id).orElse(null);
if(user == null)
{
System.out.println("불가");
throw new RuntimeException("유효하지 않은 아이디입니다. 다시 입력하세요");
if (user == null) {
throw new UserException("유효하지 않은 아이디입니다. 다시 입력하세요");
}
else {
} else {
sendEamail(user);
}
}
@Override
public String getUserName(Long id) throws Exception {
return userRepository.findById(id).get().getName();
}
@Override
public void changeuInfo(InfoDto infoDto, Long id) throws Exception {
User user = userRepository.findById(id).orElse(null);
if (user == null) {
throw new Exception("User not found");
}
if (infoDto.getName() != null)
{
user.setName(infoDto.getName());
}
if(infoDto.getEmail()!=null)
{
user.setEmail(infoDto.getEmail());
}
userRepository.save(user);
}
@Override
public void changePassword(PasswordDto passwordDto, Long id) throws Exception {
User user = userRepository.findById(id).orElse(null);
if (user == null) {
throw new Exception("User not found");
}
if (!user.getPassword().equals(passwordDto.getCurrentPassword())) {
throw new Exception("Current password is incorrect");
} else {
if (!passwordDto.getNewPassword().equals(passwordDto.getNewPasswordCheck())) {
throw new Exception("New password confirmation does not match");
}
}
user.setPassword(passwordDto.getNewPassword());
userRepository.save(user);
}
public String getTempPassword() {
char[] charSet = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};

View File

@ -4,6 +4,8 @@ import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
import com.edufocus.edufocus.user.model.exception.ExpriedTokenException;
import com.edufocus.edufocus.user.model.exception.InvalidTokenException;
import com.edufocus.edufocus.user.model.exception.UnAuthorizedException;
import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Value;
@ -52,19 +54,27 @@ public class JWTUtil {
public boolean checkToken(String token) {
try {
Jws<Claims> claims = Jwts.parserBuilder()
.setSigningKey(generateKey())
.build()
.parseClaimsJws(token);
log.debug("claims: {}", claims);
return true;
} catch (MalformedJwtException | UnsupportedJwtException | IllegalArgumentException | SignatureException | ExpiredJwtException e) {
log.error("Token validation error: {}", e.getMessage());
return false;
} catch (Exception e) {
System.out.println(token);
log.error("Unexpected error while validating token: {}", e.getMessage());
return false;
Jws<Claims> claims = Jwts.parserBuilder()
.setSigningKey(generateKey())
.build()
.parseClaimsJws(token);
log.debug("claims: {}", claims);
return true;
} catch (MalformedJwtException | UnsupportedJwtException | IllegalArgumentException | SignatureException e) {
log.error("Token validation error: {}", e.getMessage());
return false;
}
catch ( ExpiredJwtException e)
{
throw new ExpriedTokenException();
}
catch (Exception e) {
System.out.println(token);
System.out.println(e.getMessage());
log.error("Unexpected error while validating token: {}", e.getMessage());
return false;
}
}
@ -77,9 +87,15 @@ public class JWTUtil {
Map<String, Object> value = claims.getBody();
log.info("value : {}", value);
return (String) value.get("id");
} catch (Exception e) {
}catch ( ExpiredJwtException e)
{
System.out.println("expired token");
throw new ExpriedTokenException();
}
catch (Exception e) {
log.error("Failed to get user ID from token: {}", e.getMessage());
throw new UnAuthorizedException();
throw new InvalidTokenException();
}
}
}

View File

@ -1,20 +1,44 @@
package com.edufocus.edufocus.video.controller;
import io.livekit.server.AccessToken;
import io.livekit.server.RoomJoin;
import io.livekit.server.RoomName;
import io.livekit.server.WebhookReceiver;
import livekit.LivekitWebhook.WebhookEvent;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@CrossOrigin(origins = "*")
@RestController
public class Controller {
import com.edufocus.edufocus.lecture.entity.Lecture;
import com.edufocus.edufocus.lecture.entity.LectureDetailResponse;
import com.edufocus.edufocus.lecture.repository.LectureRepository;
import com.edufocus.edufocus.lecture.service.LectureService;
import com.edufocus.edufocus.registration.entity.RegistrationStatus;
import com.edufocus.edufocus.registration.service.RegistrationService;
import com.edufocus.edufocus.user.model.entity.User;
import com.edufocus.edufocus.user.model.entity.UserRole;
import com.edufocus.edufocus.user.model.repository.UserRepository;
import com.edufocus.edufocus.user.model.service.UserService;
import com.edufocus.edufocus.user.util.JWTUtil;
import com.edufocus.edufocus.video.service.VideoSertvice;
import io.livekit.server.*;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import livekit.LivekitWebhook.WebhookEvent;
@RestController
@RequestMapping("/video")
@Slf4j
@RequiredArgsConstructor
public class Controller {
private final JWTUtil jwtUtil;
private final UserService userService;
private final LectureService lectureService;
private final VideoSertvice videoSertvice;
private final RegistrationService registrationService;
private final UserRepository userRepository;
private final LectureRepository lectureRepository;
@Value("${livekit.api.key}")
private String LIVEKIT_API_KEY;
@ -25,47 +49,143 @@ public class Controller {
* @param params JSON object with roomName and participantName
* @return JSON object with the JWT token
*/
@PostMapping(value = "/token")
public ResponseEntity<Map<String, String>> createToken(@RequestBody Map<String, String> params) {
String roomName = params.get("roomName");
String participantName = params.get("participantName");
// @PostMapping(value = "/token")
// public ResponseEntity<Map<String, String>> createToken(@RequestBody Map<String, String> params) {
// String roomName = params.get("roomName");
// String participantName = params.get("participantName");
//
// if (roomName == null || participantName == null) {
// return ResponseEntity.badRequest().body(Map.of("errorMessage", "roomName and participantName are required"));
// }
//
// AccessToken token = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
// token.setName(participantName);
// token.setIdentity(participantName);
// token.addGrants(new RoomJoin(true), new RoomName(roomName));
//
//
//
// return ResponseEntity.ok(Map.of("token", token.toJwt()));
// }
//
//
//
//
//
//
@PostMapping(value = "/makeroom/{lecture_id}")
public ResponseEntity<String> startLecture(@PathVariable("lecture_id") Long id, HttpServletRequest request) throws Exception {
if (roomName == null || participantName == null) {
return ResponseEntity.badRequest().body(Map.of("errorMessage", "roomName and participantName are required"));
String userToken = request.getHeader("Authorization");
Long userId = Long.parseLong(jwtUtil.getUserId(userToken));
videoSertvice.startOnline(userId, id);
return new ResponseEntity<>("방만들기 성공",HttpStatus.OK);
}
@PostMapping(value = "/joinroom/{lecture_id}")
public ResponseEntity<Map<String, String>> joinRoom(@PathVariable("lecture_id") Long id, HttpServletRequest request) throws Exception
{
String userToken = request.getHeader("Authorization");
Long userId = Long.parseLong(jwtUtil.getUserId(userToken));
User findUser= userRepository.findById(userId).orElse(null);
Lecture lecture= lectureRepository.findById(id).orElse(null);
if(findUser.getRole()==UserRole.ADMIN ){//&& lecture.isOnline() ) {
String roomName = lecture.getTitle();
String participantName = userService.getUserName(userId);
AccessToken token = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
token.setName(participantName);
token.setIdentity(participantName);
token.addGrants(new RoomJoin(true), new RoomName(roomName), new RoomCreate(true));
videoSertvice.startOnline(userId, id);
return ResponseEntity.ok(Map.of("token", token.toJwt()));
}
else if(findUser.getRole()==UserRole.STUDENT )// && lecture.isOnline() )
{
String roomName = lecture.getTitle();
String participantName = userService.getUserName(userId);
AccessToken token = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
token.setName(participantName);
token.setIdentity(participantName);
token.addGrants(new RoomJoin(true), new RoomName(roomName));
videoSertvice.startOnline(userId, id);
return ResponseEntity.ok(Map.of("token", token.toJwt()));
}
AccessToken token = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
return ResponseEntity.ok(Map.of("token", null));
// String userToken = request.getHeader("Authorization");
//
// Long userId = Long.parseLong(jwtUtil.getUserId(userToken));
// LectureDetailResponse lecture= lectureService.findLectureById(userId,id);
//
//
// //RegistrationStatus registrationStatus = registrationService.isOnline(userId,id);
//
// if(registrationStatus==RegistrationStatus.ACCEPTED)
// {
// String roomName = lecture.getTitle();
// String participantName = userService.getUserName(userId);
//
//
// AccessToken token = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
// token.setName(participantName);
// token.setIdentity(participantName);
// token.addGrants(new RoomJoin(true), new RoomName(roomName));
//
// //videoSertvice.startOnline(userId,id);
//
//
//
// return ResponseEntity.ok(Map.of("token", token.toJwt()));
// }
// else{
// return ResponseEntity.status(HttpStatus.FORBIDDEN).body(Map.of("errorMessage", "Not accepted"));
//
// }
token.setName(participantName);
token.setIdentity(participantName);
token.addGrants(new RoomJoin(true), new RoomName(roomName));
// 방이름으로 입장하는건데
// 만약 수강생에 DB에 신청한 강의명이 없다면 들어갈수 없음
// 검증 로직만 추가하면 될듯?
return ResponseEntity.ok(Map.of("token", token.toJwt()));
}
@PostMapping(value = "/webhook", consumes = "application/webhook+json")
public ResponseEntity<String> receiveWebhook(@RequestHeader("Authorization") String authHeader, @RequestBody String body) {
WebhookReceiver webhookReceiver = new WebhookReceiver(LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
try {
WebhookEvent event = webhookReceiver.receive(body, authHeader);
System.out.println("LiveKit Webhook: " + event.toString());
} catch (Exception e) {
System.err.println("Error validating webhook event: " + e.getMessage());
}
return ResponseEntity.ok("ok");
@PostMapping(value = "/livekit/webhook", consumes = "application/webhook+json")
public ResponseEntity<String> receiveWebhook(@RequestHeader("Authorization") String authHeader, @RequestBody String body) {
WebhookReceiver webhookReceiver = new WebhookReceiver(LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
try {
WebhookEvent event = webhookReceiver.receive(body, authHeader);
System.out.println("LiveKit Webhook: " + event.toString());
} catch (Exception e) {
System.err.println("Error validating webhook event: " + e.getMessage());
}
return ResponseEntity.ok("ok");
}
}

View File

@ -0,0 +1,8 @@
package com.edufocus.edufocus.video.service;
import java.sql.SQLException;
public interface VideoSertvice {
void startOnline(Long userId,Long lectureId) throws SQLException;
}

View File

@ -0,0 +1,21 @@
package com.edufocus.edufocus.video.service;
import com.edufocus.edufocus.lecture.entity.Lecture;
import com.edufocus.edufocus.lecture.service.LectureService;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.sql.SQLException;
@Service
@Transactional
@RequiredArgsConstructor
public class VideoServiceImpl implements VideoSertvice{
private final LectureService lectureService;
@Override
public void startOnline(Long userId,Long lectureId) throws SQLException {
lectureService.changeState(lectureId);
}
}

View File

@ -4,6 +4,9 @@ server.port=8080
server.ssl.enabled=false
server.servlet.context-path=${CONTEXT_PATH}
# openvidu
#server.port=${SERVER_PORT:6080}
# LiveKit configuration
livekit.api.key=${LIVEKIT_API_KEY:devkey}
@ -28,6 +31,8 @@ spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.mail.host=smtp.gmail.com
spring.mail.port=587
#spring.mail.username=ssafytestpjt

View File

@ -0,0 +1,185 @@
package com.edufocus.edufocus.user.model.service;
import com.edufocus.edufocus.user.model.entity.PasswordDto;
import com.edufocus.edufocus.user.model.entity.User;
import com.edufocus.edufocus.user.model.entity.UserRole;
import com.edufocus.edufocus.user.model.exception.UserException;
import com.edufocus.edufocus.user.model.repository.UserRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.mail.javamail.JavaMailSender;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
public class UserServiceImplTest {
@InjectMocks
private UserServiceImpl userService;
@Mock
private UserRepository userRepository;
@BeforeEach
public void setup() {
MockitoAnnotations.openMocks(this);
}
@Test
public void testJoin() {
User user = new User();
user.setUserId("testUser");
user.setPassword("password");
user.setEmail("test@example.com");
user.setRole(UserRole.STUDENT);
user.setId(1L);
userService.join(user);
verify(userRepository, times(1)).save(user);
}
@Test
public void testLogin_Success() throws Exception {
User user = new User();
user.setUserId("testUser");
user.setPassword("password");
when(userRepository.findByUserId("testUser")).thenReturn(Optional.of(user));
User loggedInUser = userService.login(user);
assertNotNull(loggedInUser);
assertEquals("testUser", loggedInUser.getUserId());
}
@Test
public void testLogin_UserNotFound() {
User user = new User();
user.setUserId("testUser");
user.setPassword("password");
when(userRepository.findByUserId("testUser")).thenReturn(Optional.empty());
assertThrows(UserException.class, () -> {
userService.login(user);
});
}
@Test
public void testLogin_InvalidPassword() {
User user = new User();
user.setUserId("testUser");
user.setPassword("password");
User storedUser = new User();
storedUser.setUserId("testUser");
storedUser.setPassword("wrongPassword");
when(userRepository.findByUserId("testUser")).thenReturn(Optional.of(storedUser));
assertThrows(UserException.class, () -> {
userService.login(user);
});
}
// @Test
// public void testUserInfo_Success() {
// User user = new User();
// user.setId(1L);
// user.setName("testUser");
//
// when(userRepository.findById(1L)).thenReturn(Optional.of(user));
//
// User userInfo = userService.userInfo(1L);
//
// assertNotNull(userInfo);
// assertEquals("testUser", userInfo.getName());
// }
//
// @Test
// public void testUserInfo_UserNotFound() {
// when(userRepository.findById(1L)).thenReturn(Optional.empty());
//
// assertThrows(UserException.class, () -> {
// userService.userInfo(1L);
// });
// }
//
// @Test
// public void testChangePassword_Success() throws Exception {
// User user = new User();
// user.setId(1L);
// user.setPassword("currentPassword");
//
// when(userRepository.findById(1L)).thenReturn(Optional.of(user));
//
// PasswordDto passwordDto = new PasswordDto();
// passwordDto.setCurrentPassword("currentPassword");
// passwordDto.setNewPassword("newPassword");
// passwordDto.setNewPasswordCheck("newPassword");
//
// userService.changePassword(passwordDto, 1L);
//
// verify(userRepository, times(1)).save(user);
// assertEquals("newPassword", user.getPassword());
// }
//
// @Test
// public void testChangePassword_UserNotFound() {
// when(userRepository.findById(1L)).thenReturn(Optional.empty());
//
// PasswordDto passwordDto = new PasswordDto();
// passwordDto.setCurrentPassword("currentPassword");
// passwordDto.setNewPassword("newPassword");
// passwordDto.setNewPasswordCheck("newPassword");
//
// assertThrows(Exception.class, () -> {
// userService.changePassword(passwordDto, 1L);
// });
// }
//
// @Test
// public void testChangePassword_InvalidCurrentPassword() {
// User user = new User();
// user.setId(1L);
// user.setPassword("currentPassword");
//
// when(userRepository.findById(1L)).thenReturn(Optional.of(user));
//
// PasswordDto passwordDto = new PasswordDto();
// passwordDto.setCurrentPassword("wrongPassword");
// passwordDto.setNewPassword("newPassword");
// passwordDto.setNewPasswordCheck("newPassword");
//
// assertThrows(Exception.class, () -> {
// userService.changePassword(passwordDto, 1L);
// });
// }
//
// @Test
// public void testChangePassword_NewPasswordMismatch() {
// User user = new User();
// user.setId(1L);
// user.setPassword("currentPassword");
//
// when(userRepository.findById(1L)).thenReturn(Optional.of(user));
//
// PasswordDto passwordDto = new PasswordDto();
// passwordDto.setCurrentPassword("currentPassword");
// passwordDto.setNewPassword("newPassword");
// passwordDto.setNewPasswordCheck("mismatchNewPassword");
//
// assertThrows(Exception.class, () -> {
// userService.changePassword(passwordDto, 1L);
// });
// }
}