diff --git a/module-user/src/main/java/org/example/domain/attendance/service/CreateAttendanceService.java b/module-user/src/main/java/org/example/domain/attendance/service/CreateAttendanceService.java index bc31182e..76af5f0c 100644 --- a/module-user/src/main/java/org/example/domain/attendance/service/CreateAttendanceService.java +++ b/module-user/src/main/java/org/example/domain/attendance/service/CreateAttendanceService.java @@ -103,7 +103,7 @@ public void createAttendance() { Attendance attendance = Attendance.builder() .studyMember(studyMember) .week(lastWeek) - .problemYN(getProblemYN(lastWeek, studyMember, requestCount - solvedWorkbookCount)) + .problemYN(getProblemYN(lastWeek, studyMember, requestCount - Math.min(WORKBOOK_MIN_REQUEST_COUNT, solvedWorkbookCount))) .blogYN(attendanceRequestYn && StringUtils.hasText(optionalAttendanceRequest.get().getBlogUrl())) .workbookYN(solvedWorkbookCount >= WORKBOOK_MIN_REQUEST_COUNT) .build(); diff --git a/module-user/src/main/java/org/example/domain/workbook/service/CreateWorkbookService.java b/module-user/src/main/java/org/example/domain/workbook/service/CreateWorkbookService.java index ad5439cc..19d180ea 100644 --- a/module-user/src/main/java/org/example/domain/workbook/service/CreateWorkbookService.java +++ b/module-user/src/main/java/org/example/domain/workbook/service/CreateWorkbookService.java @@ -1,8 +1,11 @@ package org.example.domain.workbook.service; +import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; -import java.util.stream.Stream; +import java.util.Set; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.example.api_response.exception.GeneralException; import org.example.api_response.status.ErrorStatus; @@ -111,36 +114,91 @@ private List createBasicWorkbook(Week week) { * 코딩테스트 심화반 */ private List createPrepareWorkbook(Week week, Long studyId) { + List studyMemberList = listStudyMemberRepository.getStudyMemberList(studyId); + final int MAX_MEMBER_PER_QUERY = 10; + int queryCount = (int) Math.ceil((double) studyMemberList.size() / MAX_MEMBER_PER_QUERY); + // 난이도 설정 쿼리 String silverQuery = "*s4..s1 "; String goldQuery = "*g "; // 주차별 알고리즘 유형 설정 쿼리 - StringBuilder query = new StringBuilder(); - switch (week.getValue()) { - case 1 -> query.append("(#bruteforcing | #backtracking) -#dfs -#bfs"); - case 2 -> query.append("#dp"); - case 3 -> query.append("(#simulation | #two_pointer)"); - case 4 -> query.append("(#binary_search | #prefix_sum)"); - case 5 -> query.append("#data_structures"); - case 6 -> query.append("(#bfs | #dfs)"); - case 7 -> query.append("#dijkstra"); - case 8 -> query.append("#greedy"); - } + String algorithmQuery = getAlgorithmQuery(week); // 스터디원이 푼 문제 제외 쿼리 - List studyMemberList = listStudyMemberRepository.getStudyMemberList(studyId); - studyMemberList.forEach(dto -> query.append(" -s@").append(dto.getHandle())); + List queryList = new ArrayList<>(); + for (int count = 0; count < queryCount; count++) { + queryList.add(new StringBuilder(algorithmQuery)); + for (int i = 0; i < MAX_MEMBER_PER_QUERY; i++) { + int idx = count * MAX_MEMBER_PER_QUERY + i; + if (idx >= studyMemberList.size()) break; + + queryList.get(count).append(" -s@").append(studyMemberList.get(idx)); + } + } // solved.ac 요청 - ProblemResponse silverProblemResponse = solvedAcClient.searchProblems(1, silverQuery + query, SORT, DIRECTION); - ProblemResponse goldProblemResponse = solvedAcClient.searchProblems(1, goldQuery + query, SORT, DIRECTION); - - List problemNumberList = Stream.concat( - silverProblemResponse.getProblemList().stream().limit(3), - goldProblemResponse.getProblemList().stream().limit(3) - ).map(ProblemDto::getNumber).toList(); - return problemRepository.findAllById(problemNumberList); + List> silverProblemSetList = new ArrayList<>(); + List> goldProblemSetList = new ArrayList<>(); + for (int count = 0; count < queryCount; count++) { + ProblemResponse silverProblemResponsePage1 = solvedAcClient.searchProblems(1, silverQuery + queryList.get(count), SORT, DIRECTION); + ProblemResponse silverProblemResponsePage2 = solvedAcClient.searchProblems(2, silverQuery + queryList.get(count), SORT, DIRECTION); + ProblemResponse goldProblemResponsePage1 = solvedAcClient.searchProblems(1, goldQuery + queryList.get(count), SORT, DIRECTION); + ProblemResponse goldProblemResponsePage2 = solvedAcClient.searchProblems(2, goldQuery + queryList.get(count), SORT, DIRECTION); + + Set silverPage1 = silverProblemResponsePage1.getProblemList().stream().map(ProblemDto::getNumber) + .collect(Collectors.toCollection(LinkedHashSet::new)); + Set silverPage2 = silverProblemResponsePage2.getProblemList().stream().map(ProblemDto::getNumber) + .collect(Collectors.toCollection(LinkedHashSet::new)); + Set goldPage1 = goldProblemResponsePage1.getProblemList().stream().map(ProblemDto::getNumber) + .collect(Collectors.toCollection(LinkedHashSet::new)); + Set goldPage2 = goldProblemResponsePage2.getProblemList().stream().map(ProblemDto::getNumber) + .collect(Collectors.toCollection(LinkedHashSet::new)); + + Set silverProblemSet = new LinkedHashSet<>(); + silverProblemSet.addAll(silverPage1); + silverProblemSet.addAll(silverPage2); + silverProblemSetList.add(silverProblemSet); + + Set goldProblemSet = new LinkedHashSet<>(); + goldProblemSet.addAll(goldPage1); + goldProblemSet.addAll(goldPage2); + goldProblemSetList.add(goldProblemSet); + } + + List result = new ArrayList<>(); + if (!silverProblemSetList.isEmpty()) { + Set silverResultSet = new LinkedHashSet<>(silverProblemSetList.get(0)); + for (int i = 1; i < silverProblemSetList.size(); i++) { + silverResultSet.retainAll(silverProblemSetList.get(i)); + } + result.addAll(silverResultSet.stream().limit(3).toList()); + } + + if (!goldProblemSetList.isEmpty()) { + Set goldResultSet = new LinkedHashSet<>(goldProblemSetList.get(0)); + for (int i = 1; i < goldProblemSetList.size(); i++) { + goldResultSet.retainAll(goldProblemSetList.get(i)); + } + result.addAll(goldResultSet.stream().limit(3).toList()); + } + + return problemRepository.findAllById(result); + } + + private String getAlgorithmQuery(Week week) { + String algorithmQuery = ""; + switch (week.getValue()) { + case 1 -> algorithmQuery = "(#bruteforcing | #backtracking) -#dfs -#bfs"; + case 2 -> algorithmQuery = "#dp"; + case 3 -> algorithmQuery = "(#simulation | #two_pointer)"; + case 4 -> algorithmQuery = "(#binary_search | #prefix_sum)"; + case 5 -> algorithmQuery = "#data_structures"; + case 6 -> algorithmQuery = "(#bfs | #dfs)"; + case 7 -> algorithmQuery = "#dijkstra"; + case 8 -> algorithmQuery = "#greedy"; + } + return algorithmQuery; } } diff --git a/module-user/src/test/java/org/example/domain/attendance/service/CreateAttendanceServiceTest.java b/module-user/src/test/java/org/example/domain/attendance/service/CreateAttendanceServiceTest.java new file mode 100644 index 00000000..1749a22a --- /dev/null +++ b/module-user/src/test/java/org/example/domain/attendance/service/CreateAttendanceServiceTest.java @@ -0,0 +1,93 @@ +package org.example.domain.attendance.service; + +import static org.junit.jupiter.api.Assertions.*; + +import java.time.Duration; +import java.time.LocalDate; +import java.time.temporal.ChronoField; +import java.util.List; +import org.example.util.http_request.Url; +import org.junit.jupiter.api.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest(properties = "spring.profiles.active=test") +class CreateAttendanceServiceTest { + + @Autowired + WebDriver webDriver; + @Autowired + Actions actions; + + @Test + void 저번주에_푼_문제수() { + + // 페이지 랜딩 대기 + webDriver.get(Url.BAEKJOON_USER.getBaekjoonUserUrl("engus525")); + new WebDriverWait(webDriver, Duration.ofSeconds(10)) + .until(ExpectedConditions.presenceOfElementLocated(By.tagName("rect"))); + List rectList = webDriver.findElements(By.tagName("rect")); + + // 지난주 범위 계산 + LocalDate today = LocalDate.now().minusDays(7); + LocalDate lastYear = today.minusYears(1); + int startRect = today.getDayOfYear() + - LocalDate.now().get(ChronoField.DAY_OF_WEEK) + 1; + if (rectList.size() >= 2 * 365) { + if (lastYear.isLeapYear()) startRect += 365 + 1; + else startRect += 365; + } + int lastRect = startRect + 6; + + int count = 0; + for (int i = startRect; i <= lastRect; i++) { + rectList = webDriver.findElements(By.tagName("rect")); + WebElement rect = rectList.get(i); + actions.moveToElement(rect).perform(); + + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + // tooltip에 기록된 해당 날짜에 푼 문제 수 추출 + WebElement tooltip = webDriver.findElement(By.className("google-visualization-tooltip")); + String text = tooltip.getText(); + System.out.println(text); + int colonIndex = text.indexOf(":"); + if (colonIndex != -1) { + count += Integer.parseInt(text.substring(colonIndex + 1).strip()); + } + } + + System.out.println("문제 풀이 수 : " + count); + + } + + + @Test + void 문제집에서_몇개_풀었는지() { + + webDriver.get(Url.BAEKJOON_USER.getBaekjoonUserUrl("engus525")); + + // 맞힌 문제 개수로 제한 + int limitCount = Integer.parseInt(webDriver.findElement(By.id("u-solved")).getText()); + List problemNumberList = webDriver.findElements(By.cssSelector(".problem-list a")) + .stream() + .map(problemNumber -> Integer.parseInt(problemNumber.getText())) + .limit(limitCount) + .toList(); + + int solvedCount; + List workbookProblemList = List.of(1446, 20168, 5972, 2151, 16118, 2307); + System.out.println(workbookProblemList.stream().filter(problemNumberList::contains).toList()); + solvedCount = (int) workbookProblemList.stream().filter(problemNumberList::contains).count(); + + System.out.println("solvedCount = " + solvedCount); + } +} \ No newline at end of file diff --git a/module-user/src/test/java/org/example/domain/workbook/service/CreateWorkbookServiceTest.java b/module-user/src/test/java/org/example/domain/workbook/service/CreateWorkbookServiceTest.java new file mode 100644 index 00000000..662b0c90 --- /dev/null +++ b/module-user/src/test/java/org/example/domain/workbook/service/CreateWorkbookServiceTest.java @@ -0,0 +1,130 @@ +package org.example.domain.workbook.service; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.example.schedule.solved_ac.SolvedAcClient; +import org.example.schedule.solved_ac.response.problem.ProblemDto; +import org.example.schedule.solved_ac.response.problem.ProblemResponse; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest(properties = "spring.profiles.active=test") +public class CreateWorkbookServiceTest { + + @Autowired + SolvedAcClient solvedAcClient; + private static final String SORT = "solved"; + private static final String DIRECTION = "desc"; + + + + @Test + void 정규스터디_문제집생성() { + + int week = 7; + + String[] handle = + {"engus525", "engus525", "engus525", "engus525", "engus525", "engus525", "engus525", "engus525", "engus525", "engus525", + "engus525", "engus525", "engus525", "engus525", "engus525", "engus525", "engus525", "engus525", "engus525", "engus525", + "engus525", "engus525", "engus525", "engus525", "engus525", "engus525", "engus525"}; + + final int MAX_MEMBER_PER_QUERY = 10; + int queryCount = (int) Math.ceil((double) handle.length / MAX_MEMBER_PER_QUERY); + + // 난이도 설정 쿼리 + String silverQuery = "*s4..s1 "; + String goldQuery = "*g "; + + // 주차별 알고리즘 유형 설정 쿼리 + String algorithmQuery = getAlgorithmQuery(week); + + // 스터디원이 푼 문제 제외 쿼리 + List queryList = new ArrayList<>(); + for (int count = 0; count < queryCount; count++) { + queryList.add(new StringBuilder(algorithmQuery)); + for (int i = 0; i < MAX_MEMBER_PER_QUERY; i++) { + int idx = count * MAX_MEMBER_PER_QUERY + i; + if (idx >= handle.length) break; + + queryList.get(count).append(" -s@").append(handle[idx]); + } + } + + // solved.ac 요청 + List> silverProblemSetList = new ArrayList<>(); + List> goldProblemSetList = new ArrayList<>(); + for (int count = 0; count < queryCount; count++) { + + System.out.println("silverQuery + queryList.get(count) = " + silverQuery + queryList.get(count)); + System.out.println("goldQuery + queryList.get(count) = " + goldQuery + queryList.get(count)); + ProblemResponse silverProblemResponsePage1 = solvedAcClient.searchProblems(1, silverQuery + queryList.get(count), SORT, DIRECTION); + ProblemResponse silverProblemResponsePage2 = solvedAcClient.searchProblems(2, silverQuery + queryList.get(count), SORT, DIRECTION); + ProblemResponse goldProblemResponsePage1 = solvedAcClient.searchProblems(1, goldQuery + queryList.get(count), SORT, DIRECTION); + ProblemResponse goldProblemResponsePage2 = solvedAcClient.searchProblems(2, goldQuery + queryList.get(count), SORT, DIRECTION); + + System.out.println("goldProblemResponsePage1.getProblemList() = " + goldProblemResponsePage1.getProblemList()); + System.out.println("goldProblemResponsePage2.getProblemList() = " + goldProblemResponsePage2.getProblemList()); + Set silverPage1 = silverProblemResponsePage1.getProblemList().stream().map(ProblemDto::getNumber) + .collect(Collectors.toCollection(LinkedHashSet::new)); + Set silverPage2 = silverProblemResponsePage2.getProblemList().stream().map(ProblemDto::getNumber) + .collect(Collectors.toCollection(LinkedHashSet::new)); + Set goldPage1 = goldProblemResponsePage1.getProblemList().stream().map(ProblemDto::getNumber) + .collect(Collectors.toCollection(LinkedHashSet::new)); + Set goldPage2 = goldProblemResponsePage2.getProblemList().stream().map(ProblemDto::getNumber) + .collect(Collectors.toCollection(LinkedHashSet::new)); + + Set silverProblemSet = new LinkedHashSet<>(); + silverProblemSet.addAll(silverPage1); + silverProblemSet.addAll(silverPage2); + System.out.println("silverProblemSet = " + silverProblemSet); + silverProblemSetList.add(silverProblemSet); + + Set goldProblemSet = new LinkedHashSet<>(); + goldProblemSet.addAll(goldPage1); + goldProblemSet.addAll(goldPage2); + goldProblemSetList.add(goldProblemSet); + } + + List result = new ArrayList<>(); + if (!silverProblemSetList.isEmpty()) { + Set silverResultSet = new LinkedHashSet<>(silverProblemSetList.get(0)); + for (int i = 1; i < silverProblemSetList.size(); i++) { + silverResultSet.retainAll(silverProblemSetList.get(i)); + } + System.out.println("silverResultSet = " + silverResultSet); + result.addAll(silverResultSet.stream().limit(3).toList()); + } + + if (!goldProblemSetList.isEmpty()) { + Set goldResultSet = new LinkedHashSet<>(goldProblemSetList.get(0)); + for (int i = 1; i < goldProblemSetList.size(); i++) { + goldResultSet.retainAll(goldProblemSetList.get(i)); + } + result.addAll(goldResultSet.stream().limit(3).toList()); + } + + System.out.println(result); + + } + + private String getAlgorithmQuery(int week) { + String algorithmQuery = ""; + switch (week) { + case 1 -> algorithmQuery = "(#bruteforcing | #backtracking) -#dfs -#bfs"; + case 2 -> algorithmQuery = "#dp"; + case 3 -> algorithmQuery = "(#simulation | #two_pointer)"; + case 4 -> algorithmQuery = "(#binary_search | #prefix_sum)"; + case 5 -> algorithmQuery = "#data_structures"; + case 6 -> algorithmQuery = "(#bfs | #dfs)"; + case 7 -> algorithmQuery = "#dijkstra"; + case 8 -> algorithmQuery = "#greedy"; + } + return algorithmQuery; + } + + +} \ No newline at end of file