Merge pull request #133 from TeamBNBN/BE/video

feat: 강의 시작, 강의 참여 기능
This commit is contained in:
Jungmin 2024-07-29 14:10:02 +09:00 committed by GitHub
commit 6e3a7349c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 179 additions and 44 deletions

View File

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

View File

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

View File

@ -222,4 +222,28 @@ 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);
}
}

View File

@ -1,6 +1,7 @@
package com.edufocus.edufocus.registration.service;
import com.edufocus.edufocus.registration.entity.Registration;
import com.edufocus.edufocus.registration.entity.RegistrationStatus;
import org.springframework.stereotype.Service;
@Service
@ -12,4 +13,5 @@ public interface RegistrationService {
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;
}
@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) {
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())
@ -45,7 +45,7 @@ public class WebConfiguration implements WebMvcConfigurer {
registry.addInterceptor(jwtInterceptor)
.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/**"); // 인증 없이 접근 가능한 경로 설정
///v3/api-docs/**, /swagger-resources/**, /webjars/**
}

View File

@ -1,20 +1,37 @@
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.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;
//@CrossOrigin(origins = "*")
@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}")
private String LIVEKIT_API_KEY;
@ -25,47 +42,98 @@ 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<Map<String, String>> startLecture(@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);
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);
token.setName(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()));
}
@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 = "/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) {
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}