Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Academ Back-end repository 입니다.
---

### 프로젝트 구조
( 최신화 : v1.1.2 )
( 최신화 : v1.1.3 )
```
├── .github
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -25,11 +26,12 @@
import java.util.Map;

@RestController
@RequiredArgsConstructor
@Tag(name = "ADMIN", description = "ADMIN 권한의 계정만 요청 가능한 api입니다.")
public class AdminController
{
@Autowired AdminService adminService;
@Autowired VersionProvider versionProvider;
private final AdminService adminService;
private final VersionProvider versionProvider;

/* 강의 정보 동기화 컨트톨러 */
@PostMapping("/api/admin/course-synchronization")
Expand Down Expand Up @@ -182,4 +184,27 @@ public ResponseEntity<ResponseDto.Success> trafficYearly(@RequestParam("year") S
);
}

/* 테스트 계정 생성 컨트롤러 */
@PostMapping("/api/admin/create-test-account")
@Operation(summary = "테스트 계정 생성")
@Parameters(value = {
@Parameter(in = ParameterIn.HEADER, name = "Authorization", description = "Bearer {access token}"),
})
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "이메일을 반환합니다.", content = @Content(schema = @Schema(implementation = String.class))),
@ApiResponse(responseCode = "실패: 400 (EMAIL_DUPLICATED)", description = "해당 이메일로 생성된 계정이 이미 존재하는 경우 (입력받은 이메일을 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
})
public ResponseEntity<ResponseDto.Success> createTestAccount(@Valid @RequestBody ProfileDto.CreateTestAccount dto) {
adminService.createTestAccount(dto);

return ResponseEntity.status(HttpStatus.CREATED)
.body(
ResponseDto.Success.builder()
.message("테스트 계정 생성을 성공하였습니다.")
.data(dto.getEmail())
.version(versionProvider.getVersion())
.build()
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
Expand All @@ -24,11 +25,12 @@
import java.util.Map;

@RestController
@RequiredArgsConstructor
@Tag(name = "강의", description = "강의, 강의평 관련 api입니다.")
public class CourseController
{
@Autowired CourseService courseService;
@Autowired VersionProvider versionProvider;
private final CourseService courseService;
private final VersionProvider versionProvider;

/* 강의 검색 컨트롤러 */
@GetMapping("/api/course/search")
Expand Down Expand Up @@ -188,6 +190,7 @@ public ResponseEntity<ResponseDto.Success> startInsertComment(Principal principa
@ApiResponse(responseCode = "실패: 401 (UNAUTHORIZED)", description = "로그인하지 않은 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 400 (ALREADY_EXIST)", description = "해당 사용자가 해당 강의에 이미 강의평을 등록한 경우 (입력받은 course_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 400 (SHORT_COMMENT_REVIEW)", description = "강의평 세부 내용 길이가 50자 미만인 경우 (입력받은 세부 내용의 길이를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 400 (LONG_COMMENT_REVIEW)", description = "강의평 세부 내용 길이가 3000자 초과인 경우 (입력받은 세부 내용의 길이를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 404 (COURSE_NOT_FOUND)", description = "요청으로 보낸 course_id에 해당하는 강의가 존재하지 않는 경우 (입력받은 course_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 404 (COURSE_RATING_NOT_FOUND)", description = "특정 강의에 대한 평점 데이터가 존재하지 않는 경우 (courseRating_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 404 (EMAIL_NOT_FOUND)", description = "요청을 보낸 사용자의 계정이 존재하지 않는 경우 (이메일을 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
Expand Down Expand Up @@ -247,6 +250,7 @@ public ResponseEntity<ResponseDto.Success> startUpdateComment(Principal principa
@ApiResponse(responseCode = "실패: 401 (UNAUTHORIZED)", description = "로그인하지 않은 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 400 (NOT_COMMENT_BY_USER)", description = "해당 강의평이 해당 사용자가 작성한 강의평이 아닌 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 400 (SHORT_COMMENT_REVIEW)", description = "강의평 세부 내용 길이가 50자 미만인 경우 (입력받은 세부 내용의 길이를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 400 (LONG_COMMENT_REVIEW)", description = "강의평 세부 내용 길이가 3000자 초과인 경우 (입력받은 세부 내용의 길이를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 404 (COURSE_NOT_FOUND)", description = "요청으로 보낸 강의평이 속한 강의가 존재하지 않는 경우 (course_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 404 (COMMENT_NOT_FOUND)", description = "요청으로 보낸 comment_id에 해당하는 강의평이 존재하지 않는 경우 (입력받은 comment_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 404 (EMAIL_NOT_FOUND)", description = "요청을 보낸 사용자의 계정이 존재하지 않는 경우 (이메일을 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
Expand All @@ -27,11 +28,12 @@
import java.security.Principal;

@RestController
@RequiredArgsConstructor
@Tag(name = "로그인", description = "회원가입/로그인/로그아웃, 권한 관련 api입니다.")
public class LoginController
{
@Autowired LoginService loginService;
@Autowired VersionProvider versionProvider;
private final LoginService loginService;
private final VersionProvider versionProvider;

/* 회원가입 컨트롤러 */
@PostMapping("/api/signup")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -23,11 +24,12 @@
import java.util.List;

@RestController
@RequiredArgsConstructor
@Tag(name = "마이페이지", description = "마이페이지 관련 api입니다.")
public class MyPageController {

@Autowired MyPageService myPageService;
@Autowired VersionProvider versionProvider;
private final MyPageService myPageService;
private final VersionProvider versionProvider;

/* 마이페이지 기본 정보 컨트롤러 */
@GetMapping("/api/mypage/info")
Expand Down Expand Up @@ -252,9 +254,8 @@ public ResponseEntity<ResponseDto.Success> updatePassword(@Valid @RequestBody Pr
@ApiResponse(responseCode = "실패: 401 (UNAUTHORIZED)", description = "로그인하지 않은 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 400 (WRONG_PASSWORD)", description = "기존 비밀번호가 틀렸을 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 400 (NOT_COMMENT_BY_USER)", description = "특정 강의평이 해당 사용자가 작성한 강의평이 아닌 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 404 (COURSE_NOT_FOUND)", description = "특정 강의평이 속한 강의가 존재하지 않는 경우 (course_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 404 (COMMENT_NOT_FOUND)", description = "특정 comment_id에 해당하는 강의평이 존재하지 않는 경우 (comment_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 404 (EMAIL_NOT_FOUND)", description = "요청을 보낸 비밀번호가 숫자 또는 영문을 포함하지 않았거나, 8~24자리가 아닌 경우 (요청으로 보낸 새로운 비밀번호를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
@ApiResponse(responseCode = "실패: 404 (UNKNOWN_NOT_FOUND)", description = "알 수 없음 계정이 존재하지 않는 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))),
})
public ResponseEntity<ResponseDto.Success> deleteProfile(@Valid @RequestBody ProfileDto.Delete dto,
Principal principal)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
package com.example.Devkor_project.controller;

import com.example.Devkor_project.configuration.VersionProvider;
import com.example.Devkor_project.dto.CommentDto;
import com.example.Devkor_project.dto.ResponseDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@Tag(name = "버전", description = "버전 관련 api입니다.")
public class VersionController
{
@Autowired VersionProvider versionProvider;
private final VersionProvider versionProvider;

/* 버전 확인 컨트톨러 */
@GetMapping("/api/is-secure")
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/com/example/Devkor_project/dto/ProfileDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -262,4 +262,19 @@ public static class BuyAccessAuth
@Schema(description = "구매 상품")
private String item;
}

@AllArgsConstructor
@ToString
@Getter
public static class CreateTestAccount
{
@NotBlank(message = "[email] cannot be blank.")
@Email(message = "[email] should be email format.")
@Schema(description = "이메일")
private String email;

@NotBlank(message = "[password] cannot be blank.")
@Schema(description = "비밀번호")
private String password;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ public enum ErrorCode
ALREADY_EXIST(HttpStatus.BAD_REQUEST, "해당 강의에 해당 사용자는 이미 강의평을 달았습니다."),
NOT_COMMENT_BY_USER(HttpStatus.BAD_REQUEST, "해당 강의평은 해당 사용자가 작성한 강의평이 아닙니다."),
SHORT_COMMENT_REVIEW(HttpStatus.BAD_REQUEST, "강의평 상세 내용은 50자 이상이어야 합니다."),
LONG_COMMENT_REVIEW(HttpStatus.BAD_REQUEST, "강의평 상세 내용은 3000자 이하이어야 합니다."),
INVALID_REASON(HttpStatus.BAD_REQUEST, "해당 신고 사유는 유효하지 않습니다."),
TOO_MANY_REPORT(HttpStatus.BAD_REQUEST, "해당 강의평을 너무 많이 신고하였습니다."),
INVALID_ITEM(HttpStatus.BAD_REQUEST, "해당 아이템은 유효하지 않습니다."),
NOT_ENOUGH_POINT(HttpStatus.BAD_REQUEST, "포인트가 부족합니다."),
WRONG_PASSWORD(HttpStatus.BAD_REQUEST, "비밀번호가 틀렸습니다."),
TRAFFIC_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 기간 동안 요청이 들어오지 않았습니다.");
TRAFFIC_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 기간 동안 요청이 들어오지 않았습니다."),
UNKNOWN_NOT_FOUND(HttpStatus.NOT_FOUND, "알 수 없음 계정이 존재하지 않습니다.");

private final HttpStatus httpStatus;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package com.example.Devkor_project.repository;

import com.example.Devkor_project.entity.Profile;
import io.lettuce.core.dynamic.annotation.Param;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.Optional;

public interface ProfileRepository extends JpaRepository<Profile, Long>
{
Optional<Profile> findByEmail(String email);
Optional<Profile> findByUsername(String username);

@Query(value = "SELECT * FROM profile WHERE profile_id = 0 AND username = '알 수 없음'", nativeQuery = true)
Optional<Profile> getUnknownProfile();
}
53 changes: 43 additions & 10 deletions src/main/java/com/example/Devkor_project/service/AdminService.java
Original file line number Diff line number Diff line change
@@ -1,40 +1,44 @@
package com.example.Devkor_project.service;

import com.example.Devkor_project.dto.CommentDto;
import com.example.Devkor_project.dto.CourseDto;
import com.example.Devkor_project.dto.CrawlingDto;
import com.example.Devkor_project.dto.TrafficDto;
import com.example.Devkor_project.dto.*;
import com.example.Devkor_project.entity.*;
import com.example.Devkor_project.exception.AppException;
import com.example.Devkor_project.exception.ErrorCode;
import com.example.Devkor_project.repository.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.transaction.Transactional;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.MediaType;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;

import java.security.Principal;
import java.time.LocalDate;
import java.util.*;

@Service
@RequiredArgsConstructor
@Slf4j
public class AdminService
{
@Autowired CourseRepository courseRepository;
@Autowired CourseRatingRepository courseRatingRepository;
@Autowired CommentRepository commentRepository;
@Autowired CommentReportRepository commentReportRepository;
@Autowired TrafficRepository trafficRepository;
private final BCryptPasswordEncoder encoder;

@Autowired CourseService courseService;
private final CourseRepository courseRepository;
private final CourseRatingRepository courseRatingRepository;
private final CommentRepository commentRepository;
private final CommentReportRepository commentReportRepository;
private final ProfileRepository profileRepository;
private final TrafficRepository trafficRepository;

private final CourseService courseService;

/* 강의 정보 동기화 서비스 */
@Transactional
Expand Down Expand Up @@ -366,4 +370,33 @@ public List<TrafficDto.Year> trafficYearly(String year)

return data;
}

/* 테스트 계정 생성 서비스 */
@Transactional
public void createTestAccount(ProfileDto.CreateTestAccount dto)
{
// 이메일 중복 체크
profileRepository.findByEmail(dto.getEmail())
.ifPresent(user -> {
throw new AppException(ErrorCode.EMAIL_DUPLICATED, dto.getEmail());
});

// Profile 엔티티 생성
Profile profile = Profile.builder()
.email(dto.getEmail())
.password(encoder.encode(dto.getPassword()))
.username("테스트")
.student_id("0000000")
.degree("MASTER")
.semester(1)
.department("컴퓨터학과")
.role("ROLE_ADMIN")
.point(10000000)
.access_expiration_date(LocalDate.now().plusYears(100))
.created_at(LocalDate.now())
.build();

// 해당 엔티티를 데이터베이스에 저장
profileRepository.save(profile);
}
}
Loading
Loading