Merge branch 'backend' of https://github.com/TeamBNBN/edufocus into be/Quiz

This commit is contained in:
kgc9007 2024-07-30 10:17:15 +09:00
commit 10ef02eaf4
23 changed files with 248 additions and 63 deletions

View File

@ -2,7 +2,9 @@ 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;
@EnableJpaAuditing
@SpringBootApplication @SpringBootApplication
public class EdufocusApplication { public class EdufocusApplication {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -47,7 +47,7 @@ public class Lecture {
@Column @Column
private String time; private String time;
@Column @Column(columnDefinition = "boolean default false")
private boolean online; private boolean online;
} }

View File

@ -26,4 +26,6 @@ public interface LectureService {
List<LectureSearchResponse> findMyLecture(long userId); List<LectureSearchResponse> findMyLecture(long userId);
Lecture findLectureByTitle(String title); Lecture findLectureByTitle(String title);
void changeState(Long lectureId);
} }

View File

@ -216,4 +216,28 @@ public class LectureServiceImpl implements LectureService {
public Lecture findLectureByTitle(String title) { public Lecture findLectureByTitle(String title) {
return lectureRepository.findByTitle(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);
}
} }

View File

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

View File

@ -13,7 +13,6 @@ import java.util.List;
@Repository @Repository
public interface QnaRepository extends JpaRepository<Qna, Long> { public interface QnaRepository extends JpaRepository<Qna, Long> {
List<Qna> findByLectureId(Long lecturerId); List<Qna> findByLectureId(Long lecturerId);
Page<Qna> findByLectureId(Long lectureId, Pageable pageable); 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 createQna(Long id, QnaRequestDto qnaRequestDto, Long lecture_id) throws SQLException;
QnaResponseDto updateQna(Long id,QnaRequestDto qnaRequestDto) throws SQLException; QnaResponseDto updateQna(Long id,QnaRequestDto qnaRequestDto) throws SQLException;
void deleteQna(Long id) 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; List<QnaResponseDto> getAllQnasByLecture(Long lectureId,int pageNumber) throws SQLException;
QnaResponseDto createAnswer(Long id,QnaRequestDto qnaRequestDto) throws SQLException; QnaResponseDto createAnswer(Long id,QnaRequestDto qnaRequestDto) throws SQLException;

View File

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

View File

@ -1,6 +1,7 @@
package com.edufocus.edufocus.registration.service; package com.edufocus.edufocus.registration.service;
import com.edufocus.edufocus.registration.entity.Registration; import com.edufocus.edufocus.registration.entity.Registration;
import com.edufocus.edufocus.registration.entity.RegistrationStatus;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
@ -12,4 +13,5 @@ public interface RegistrationService {
boolean deleteRegistration(long userId, long registrationId); boolean deleteRegistration(long userId, long registrationId);
RegistrationStatus isOnline(Long userId , Long lectureId);
} }

View File

@ -62,4 +62,11 @@ public class RegistrationServiceImpl implements RegistrationService {
return true; return true;
} }
@Override
public RegistrationStatus isOnline(Long userId, Long lectureId) {
Registration registration = registrationRepository.findByUserIdAndLectureId(userId,lectureId);
return registration.getStatus();
}
} }

View File

@ -26,7 +26,7 @@ public class WebConfiguration implements WebMvcConfigurer {
public void addCorsMappings(CorsRegistry registry) { public void addCorsMappings(CorsRegistry registry) {
registry registry
.addMapping("/**") .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(), .allowedMethods(HttpMethod.GET.name(), HttpMethod.POST.name(), HttpMethod.PUT.name(),
HttpMethod.DELETE.name(), HttpMethod.HEAD.name(), HttpMethod.OPTIONS.name(), HttpMethod.DELETE.name(), HttpMethod.HEAD.name(), HttpMethod.OPTIONS.name(),
HttpMethod.PATCH.name()) HttpMethod.PATCH.name())
@ -45,7 +45,7 @@ public class WebConfiguration implements WebMvcConfigurer {
registry.addInterceptor(jwtInterceptor) registry.addInterceptor(jwtInterceptor)
.addPathPatterns("/**") // 모든 경로에 대해 인터셉터 적용 .addPathPatterns("/**") // 모든 경로에 대해 인터셉터 적용
.excludePathPatterns("/v3/api-docs/**","/swagger-resources/**","/webjars/**","/swagger-ui/**","/auth/**", "/board/**", "/user/**","/lecture/**","/qna/**", "/quiz/**"); // 인증 없이 접근 가능한 경로 설정 .excludePathPatterns("/v3/api-docs/**","/swagger-resources/**","/webjars/**","/swagger-ui/**","/auth/**", "/board/**", "/user/**","/lecture/**","/qna/**", "/quiz/**","/video/**","/registration/**"); // 인증 없이 접근 가능한 경로 설정
///v3/api-docs/**, /swagger-resources/**, /webjars/** ///v3/api-docs/**, /swagger-resources/**, /webjars/**
} }

View File

@ -0,0 +1,8 @@
package com.edufocus.edufocus.user.model.entity;
public class InfoDto {
String name;
String email;
}

View File

@ -12,4 +12,7 @@ public interface UserService {
void sendEamail(User user) throws Exception; void sendEamail(User user) throws Exception;
void userCheck(Long id) throws Exception; void userCheck(Long id) throws Exception;
String getUserName(Long id) throws Exception; String getUserName(Long id) throws Exception;
void changeuInfo(Long id) throws Exception;
void changePassword(Long id) throws Exception;
} }

View File

@ -143,6 +143,16 @@ public class UserServiceImpl implements UserService{
return userRepository.findById(id).get().getName(); return userRepository.findById(id).get().getName();
} }
@Override
public void changeuInfo(Long id) throws Exception {
}
@Override
public void changePassword(Long id) throws Exception {
}
public String getTempPassword() { public String getTempPassword() {
char[] charSet = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 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'}; 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};

View File

@ -1,20 +1,38 @@
package com.edufocus.edufocus.video.controller; 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; import java.util.Map;
@CrossOrigin(origins = "*") import com.edufocus.edufocus.lecture.entity.Lecture;
@RestController import com.edufocus.edufocus.lecture.entity.LectureDetailResponse;
public class Controller { 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.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;
@Value("${livekit.api.key}") @Value("${livekit.api.key}")
private String LIVEKIT_API_KEY; private String LIVEKIT_API_KEY;
@ -25,38 +43,91 @@ public class Controller {
* @param params JSON object with roomName and participantName * @param params JSON object with roomName and participantName
* @return JSON object with the JWT token * @return JSON object with the JWT token
*/ */
@PostMapping(value = "/token") // @PostMapping(value = "/token")
public ResponseEntity<Map<String, String>> createToken(@RequestBody Map<String, String> params) { // public ResponseEntity<Map<String, String>> createToken(@RequestBody Map<String, String> params) {
String roomName = params.get("roomName"); // String roomName = params.get("roomName");
String participantName = params.get("participantName"); // 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<Map<String, String>> startLecture(@PathVariable("lecture_id") Long id, HttpServletRequest request) throws Exception {
//
// String userToken = request.getHeader("Authorization");
// log.info("userToekn : ", userToken);
//
Long userId = Long.parseLong(jwtUtil.getUserId(userToken));
LectureDetailResponse lecture= lectureService.findLectureById(userId,id);
String roomName = lecture.getTitle();
String participantName = userService.getUserName(userId);
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); AccessToken token = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
token.setName(participantName); token.setName(participantName);
token.setIdentity(participantName); token.setIdentity(participantName);
token.addGrants(new RoomJoin(true), new RoomName(roomName)); token.addGrants(new RoomJoin(true), new RoomName(roomName),new RoomCreate(true));
videoSertvice.startOnline(userId,id);
// 방이름으로 입장하는건데
// 만약 수강생에 DB에 신청한 강의명이 없다면 들어갈수 없음
// 검증 로직만 추가하면 될듯?
return ResponseEntity.ok(Map.of("token", token.toJwt())); return ResponseEntity.ok(Map.of("token", token.toJwt()));
} }
@PostMapping(value = "/webhook", consumes = "application/webhook+json")
@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));
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"));
//
// }
}
@PostMapping(value = "/livekit/webhook", consumes = "application/webhook+json")
public ResponseEntity<String> receiveWebhook(@RequestHeader("Authorization") String authHeader, @RequestBody String body) { public ResponseEntity<String> receiveWebhook(@RequestHeader("Authorization") String authHeader, @RequestBody String body) {
WebhookReceiver webhookReceiver = new WebhookReceiver(LIVEKIT_API_KEY, LIVEKIT_API_SECRET); WebhookReceiver webhookReceiver = new WebhookReceiver(LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
try { try {
@ -68,4 +139,6 @@ public class Controller {
return ResponseEntity.ok("ok"); 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.ssl.enabled=false
server.servlet.context-path=${CONTEXT_PATH} server.servlet.context-path=${CONTEXT_PATH}
# openvidu
#server.port=${SERVER_PORT:6080}
# LiveKit configuration # LiveKit configuration
livekit.api.key=${LIVEKIT_API_KEY:devkey} livekit.api.key=${LIVEKIT_API_KEY:devkey}