Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
91d1346
feat: 모의지원 최대 지망 수를 동적으로 관리하도록 (#746)
whqtker Jun 15, 2026
2fb7476
feat: 컬럼 매핑 alias enum class 작성
whqtker Jun 15, 2026
8c11ed2
feat: 마크다운 표 파서 클래스 추가
whqtker Jun 15, 2026
f4a9c94
feat: DTO 작성
whqtker Jun 15, 2026
fb515bd
refactor: deprecated 컬럼 제거
whqtker Jun 15, 2026
5c4e888
feat: 서비스 계층 로직 작성
whqtker Jun 15, 2026
c03954a
feat: 지원 대학 정보 삽입 관련 로직 추가
whqtker Jun 15, 2026
0411646
feat: 컨트롤러 작성
whqtker Jun 15, 2026
19d5e4a
fix: 중간 빈 셀이 있는 경우 정상적으로 저장이 되지 않던 문제 수정
whqtker Jun 15, 2026
06038b4
chore: 어드민 관련 계정 추가 외
whqtker Jun 15, 2026
c86d452
feat: 학기 추가, 조회, 현재 학기 설정 관련 어드민 API 추가
whqtker Jun 15, 2026
8eabacf
refactor: 현재 학기 설정 관련 무결성 제약조건 위반하지 않도록 Modifying 쿼리 사용
whqtker Jun 15, 2026
275be81
refactor: 누락 필드 임시 추가
whqtker Jun 16, 2026
0ab661f
feat: host_university 테이블 컬럼 또한 입력으로 받도록
whqtker Jun 16, 2026
1e19e86
fix: 컬럼명 오타 수정
whqtker Jun 16, 2026
22dec8c
feat: 세부 레코드 삽입 실패 이유까지 전달하도록
whqtker Jun 17, 2026
6c34fbf
feat: 셀 단위 타입·열거형·길이 제약 검증 추가
whqtker Jun 17, 2026
b1608b4
test: enum 변환 실패 시 행 실패 동작으로 테스트 수정
whqtker Jun 17, 2026
531bb26
test: 셀 단위 타입·길이 검증 테스트 추가
whqtker Jun 17, 2026
a2ceae4
fix: 마크다운 파서에서 이스케이프된 파이프 문자 처리
whqtker Jun 17, 2026
c504325
refactor: 지원 대학 삽입 응답에서 각 셀 검증 제거
whqtker Jun 17, 2026
6046b3f
test: 각 셀 검증 제거에 따른 테스트 수정
whqtker Jun 17, 2026
1da7f46
refactor: 학기 이름 관련 변수명 수정
whqtker Jun 17, 2026
d375d26
refactor: 불명확한 변수명 수정
whqtker Jun 17, 2026
cc679f7
refactor: 부분 실패 대신 전체 실패
whqtker Jun 17, 2026
a52ec48
chore: 국가 코드 추가
whqtker Jun 17, 2026
01f98c2
refactor: 비어있는 키-값에 대한 검증 추가
whqtker Jun 17, 2026
4fe41a7
refactor: 컬럼 길이 제한 수정
whqtker Jun 17, 2026
c8cc141
refactor: 코드래빗 리뷰 반영
whqtker Jun 17, 2026
98e4d60
refactor: 컨벤션 위반 항목 전면 수정
whqtker Jun 17, 2026
1cea41d
chore: 두 스크립트 하나로 병합
whqtker Jun 17, 2026
036e17e
feat: 지원 대학 추가 시 캐시 무효화
whqtker Jun 17, 2026
9b3795e
chore: 목데이터 수정
whqtker Jun 18, 2026
fce3034
Merge remote-tracking branch 'origin/develop' into feat/745-univ-appl…
whqtker Jun 18, 2026
78def58
chore: 어드민 기능 테스트 관련 목데이터 추가
whqtker Jun 18, 2026
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.example.solidconnection.admin.term.controller;

import com.example.solidconnection.admin.term.dto.AdminTermCreateRequest;
import com.example.solidconnection.admin.term.dto.AdminTermResponse;
import com.example.solidconnection.admin.term.service.AdminTermService;
import jakarta.validation.Valid;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RequestMapping("/admin/terms")
@RestController
public class AdminTermController {

private final AdminTermService adminTermService;

@GetMapping
public ResponseEntity<List<AdminTermResponse>> getAllTerms() {
List<AdminTermResponse> responses = adminTermService.getAllTerms();
return ResponseEntity.ok(responses);
}

@PostMapping
public ResponseEntity<AdminTermResponse> createTerm(
@Valid @RequestBody AdminTermCreateRequest request
) {
AdminTermResponse response = adminTermService.createTerm(request);
return ResponseEntity.status(HttpStatus.CREATED).body(response);
}

@PatchMapping("/{id}/activate")
public ResponseEntity<AdminTermResponse> activateTerm(
@PathVariable long id
) {
AdminTermResponse response = adminTermService.activateTerm(id);
return ResponseEntity.ok(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.example.solidconnection.admin.term.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;

public record AdminTermCreateRequest(
@NotBlank
@Pattern(regexp = "^\\d{4}-\\d$", message = "학기 이름은 'YYYY-N' 형태여야 합니다. (예: 2026-1)")
String name
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.solidconnection.admin.term.dto;

import com.example.solidconnection.term.domain.Term;

public record AdminTermResponse(
Long id,
String name,
boolean isCurrent
) {

public static AdminTermResponse from(Term term) {
return new AdminTermResponse(
term.getId(),
term.getName(),
Boolean.TRUE.equals(term.getIsCurrent())
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.example.solidconnection.admin.term.service;

import static com.example.solidconnection.common.exception.ErrorCode.TERM_ALREADY_EXISTS;
import static com.example.solidconnection.common.exception.ErrorCode.TERM_NOT_FOUND;

import com.example.solidconnection.admin.term.dto.AdminTermCreateRequest;
import com.example.solidconnection.admin.term.dto.AdminTermResponse;
import com.example.solidconnection.common.exception.CustomException;
import com.example.solidconnection.term.domain.Term;
import com.example.solidconnection.term.repository.TermRepository;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
public class AdminTermService {

private final TermRepository termRepository;

@Transactional(readOnly = true)
public List<AdminTermResponse> getAllTerms() {
return termRepository.findAll()
.stream()
.map(AdminTermResponse::from)
.toList();
}

@Transactional
public AdminTermResponse createTerm(AdminTermCreateRequest request) {
termRepository.findByName(request.name())
.ifPresent(t -> {
throw new CustomException(TERM_ALREADY_EXISTS);
});
Term saved = termRepository.save(new Term(request.name(), false));
return AdminTermResponse.from(saved);
Comment thread
whqtker marked this conversation as resolved.
}

@Transactional
public AdminTermResponse activateTerm(long id) {
Term termToActivate = termRepository.findById(id)
.orElseThrow(() -> new CustomException(TERM_NOT_FOUND));
if (!Boolean.TRUE.equals(termToActivate.getIsCurrent())) {
termRepository.deactivateCurrentTerm();
}
termToActivate.activate();
return AdminTermResponse.from(termToActivate);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.example.solidconnection.admin.university.controller;

import com.example.solidconnection.admin.university.dto.UnivApplyInfoFieldResponse;
import com.example.solidconnection.admin.university.dto.UnivApplyInfoImportRequest;
import com.example.solidconnection.admin.university.dto.UnivApplyInfoImportResponse;
import com.example.solidconnection.admin.university.service.AdminUnivApplyInfoService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RequestMapping("/admin/univ-apply-infos")
@RestController
public class AdminUnivApplyInfoController {

private final AdminUnivApplyInfoService adminUnivApplyInfoService;

@GetMapping("/fields")
public ResponseEntity<UnivApplyInfoFieldResponse> getFields() {
return ResponseEntity.ok(adminUnivApplyInfoService.getFields());
}

@PostMapping
public ResponseEntity<UnivApplyInfoImportResponse> importUnivApplyInfos(
@Valid @RequestBody UnivApplyInfoImportRequest request
) {
return ResponseEntity.ok(adminUnivApplyInfoService.importUnivApplyInfos(request));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ public record AdminHomeUniversityUpdateRequest(
message = "올바른 이메일 도메인 형식이 아닙니다 (예: inha.edu, inu.ac.kr)"
)
String emailDomain

) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public record AdminHostUniversityCreateRequest(
String koreanName,

@NotBlank(message = "영문 대학명은 필수입니다")
@Size(max = 100, message = "영문 대학명은 100자 이하여야 합니다")
@Size(max = 200, message = "영문 대학명은 200자 이하여야 합니다")
String englishName,

@NotBlank(message = "표시 대학명은 필수입니다")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public record AdminHostUniversityUpdateRequest(
String koreanName,

@NotBlank(message = "영문 대학명은 필수입니다")
@Size(max = 100, message = "영문 대학명은 100자 이하여야 합니다")
@Size(max = 200, message = "영문 대학명은 200자 이하여야 합니다")
String englishName,

@NotBlank(message = "표시 대학명은 필수입니다")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.example.solidconnection.admin.university.dto;

import com.example.solidconnection.university.domain.LanguageTestType;
import com.example.solidconnection.university.domain.UnivApplyInfoColumn;
import java.util.Arrays;
import java.util.List;

public record UnivApplyInfoFieldResponse(
List<String> fields,
List<String> languageTestTypes
) {

public static UnivApplyInfoFieldResponse of() {
List<String> fields = Arrays.stream(UnivApplyInfoColumn.values())
.map(UnivApplyInfoColumn::getFieldName)
.toList();
List<String> testTypes = Arrays.stream(LanguageTestType.values())
.map(Enum::name)
.toList();
return new UnivApplyInfoFieldResponse(fields, testTypes);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.example.solidconnection.admin.university.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import java.util.Map;

public record UnivApplyInfoImportRequest(
@NotNull(message = "학기는 필수입니다")
Long termId,

@NotNull(message = "대학은 필수입니다")
Long homeUniversityId,

@NotBlank(message = "마크다운 텍스트는 필수입니다")
String markdown,

@NotEmpty(message = "컬럼은 필수입니다")
Map<String, String> columnMappings
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.example.solidconnection.admin.university.dto;

import java.util.List;

public record UnivApplyInfoImportResponse(
int successCount,
List<String> createdUniversities
) {
}
Loading
Loading