diff --git a/src/main/java/com/kustacks/kuring/admin/adapter/in/web/AdminCommandApiV2.java b/src/main/java/com/kustacks/kuring/admin/adapter/in/web/AdminCommandApiV2.java index d4518413e..43e352ffc 100644 --- a/src/main/java/com/kustacks/kuring/admin/adapter/in/web/AdminCommandApiV2.java +++ b/src/main/java/com/kustacks/kuring/admin/adapter/in/web/AdminCommandApiV2.java @@ -1,6 +1,7 @@ package com.kustacks.kuring.admin.adapter.in.web; import com.google.firebase.database.annotations.NotNull; +import com.kustacks.kuring.admin.adapter.in.web.dto.AcademicTestNotificationRequest; import com.kustacks.kuring.admin.adapter.in.web.dto.AdminAlertCreateRequest; import com.kustacks.kuring.admin.adapter.in.web.dto.RealNotificationRequest; import com.kustacks.kuring.admin.adapter.in.web.dto.TestNotificationRequest; @@ -38,6 +39,7 @@ import static com.kustacks.kuring.common.dto.ResponseCodeAndMessages.ADMIN_EMBEDDING_NOTICE_SUCCESS; import static com.kustacks.kuring.common.dto.ResponseCodeAndMessages.ADMIN_REAL_NOTICE_CREATE_SUCCESS; +import static com.kustacks.kuring.common.dto.ResponseCodeAndMessages.ADMIN_TEST_ACADEMIC_CREATE_SUCCESS; import static com.kustacks.kuring.common.dto.ResponseCodeAndMessages.ADMIN_TEST_NOTICE_CREATE_SUCCESS; @Tag(name = "Admin-Command", description = "관리자가 주체가 되는 정보 수정") @@ -75,6 +77,18 @@ public ResponseEntity> createRealNotice( return ResponseEntity.ok().body(new BaseResponse<>(ADMIN_REAL_NOTICE_CREATE_SUCCESS, null)); } + @Operation(summary = "테스트 학사일정 알림 전송", description = "테스트 학사일정 알림을 전송합니다, 실제 운영시 사용하지 않습니다") + @SecurityRequirement(name = "JWT") + @Secured(AdminRole.ROLE_ROOT) + @PostMapping("/academic/dev") + public ResponseEntity> sendAcademicTest( + @RequestBody AcademicTestNotificationRequest request + ) { + adminCommandUseCase.createAcademicTestNotification(request.toCommand()); + return ResponseEntity.ok().body(new BaseResponse<>(ADMIN_TEST_ACADEMIC_CREATE_SUCCESS, null)); + } + + @Operation(summary = "예약 알림 등록", description = "서버에 알림 시간을 yyyy-MM-dd HH:mm:ss 형태로 요청시 예약 알림을 등록한다") @SecurityRequirement(name = "JWT") @Secured(AdminRole.ROLE_ROOT) diff --git a/src/main/java/com/kustacks/kuring/admin/adapter/in/web/dto/AcademicTestNotificationRequest.java b/src/main/java/com/kustacks/kuring/admin/adapter/in/web/dto/AcademicTestNotificationRequest.java new file mode 100644 index 000000000..ee98817f8 --- /dev/null +++ b/src/main/java/com/kustacks/kuring/admin/adapter/in/web/dto/AcademicTestNotificationRequest.java @@ -0,0 +1,12 @@ +package com.kustacks.kuring.admin.adapter.in.web.dto; + +import com.kustacks.kuring.message.application.port.in.dto.AcademicTestNotificationCommand; + +public record AcademicTestNotificationRequest( + String title, + String body +) { + public AcademicTestNotificationCommand toCommand() { + return new AcademicTestNotificationCommand(title, body); + } +} \ No newline at end of file diff --git a/src/main/java/com/kustacks/kuring/admin/adapter/out/event/AdminFirebaseMessageAdapter.java b/src/main/java/com/kustacks/kuring/admin/adapter/out/event/AdminFirebaseMessageAdapter.java index 80b04e495..61d238e89 100644 --- a/src/main/java/com/kustacks/kuring/admin/adapter/out/event/AdminFirebaseMessageAdapter.java +++ b/src/main/java/com/kustacks/kuring/admin/adapter/out/event/AdminFirebaseMessageAdapter.java @@ -2,6 +2,7 @@ import com.kustacks.kuring.admin.application.port.out.AdminEventPort; import com.kustacks.kuring.common.domain.Events; +import com.kustacks.kuring.message.adapter.in.event.dto.AcademicTestNotificationEvent; import com.kustacks.kuring.message.adapter.in.event.dto.AdminNotificationEvent; import com.kustacks.kuring.message.adapter.in.event.dto.AdminTestNotificationEvent; import com.kustacks.kuring.message.application.service.exception.FirebaseMessageSendException; @@ -37,4 +38,9 @@ public void sendTestNotificationByAdmin( .build() ); } + + @Override + public void sendAcademicTestNotification(String title, String body) { + Events.raise(new AcademicTestNotificationEvent(title, body)); + } } diff --git a/src/main/java/com/kustacks/kuring/admin/application/port/in/AdminCommandUseCase.java b/src/main/java/com/kustacks/kuring/admin/application/port/in/AdminCommandUseCase.java index 005e3f051..68ae6de59 100644 --- a/src/main/java/com/kustacks/kuring/admin/application/port/in/AdminCommandUseCase.java +++ b/src/main/java/com/kustacks/kuring/admin/application/port/in/AdminCommandUseCase.java @@ -4,6 +4,7 @@ import com.kustacks.kuring.admin.application.port.in.dto.TestNotificationCommand; import com.kustacks.kuring.alert.application.port.in.dto.AlertCreateCommand; import com.kustacks.kuring.alert.application.port.in.dto.DataEmbeddingCommand; +import com.kustacks.kuring.message.application.port.in.dto.AcademicTestNotificationCommand; public interface AdminCommandUseCase { @@ -18,4 +19,7 @@ public interface AdminCommandUseCase { void embeddingCustomData(DataEmbeddingCommand command); void resubscribeAllUsersToTopics(); + + void createAcademicTestNotification(AcademicTestNotificationCommand command); + } diff --git a/src/main/java/com/kustacks/kuring/admin/application/port/out/AdminEventPort.java b/src/main/java/com/kustacks/kuring/admin/application/port/out/AdminEventPort.java index 3eeb8a351..0b8e5a9e7 100644 --- a/src/main/java/com/kustacks/kuring/admin/application/port/out/AdminEventPort.java +++ b/src/main/java/com/kustacks/kuring/admin/application/port/out/AdminEventPort.java @@ -13,4 +13,7 @@ void sendTestNotificationByAdmin( String korName, String url ) throws FirebaseMessageSendException; + + void sendAcademicTestNotification(String title, String body); + } diff --git a/src/main/java/com/kustacks/kuring/admin/application/service/AdminCommandService.java b/src/main/java/com/kustacks/kuring/admin/application/service/AdminCommandService.java index 1e6b78b91..e34225d91 100644 --- a/src/main/java/com/kustacks/kuring/admin/application/service/AdminCommandService.java +++ b/src/main/java/com/kustacks/kuring/admin/application/service/AdminCommandService.java @@ -12,6 +12,7 @@ import com.kustacks.kuring.auth.userdetails.UserDetailsServicePort; import com.kustacks.kuring.common.annotation.UseCase; import com.kustacks.kuring.common.properties.ServerProperties; +import com.kustacks.kuring.message.application.port.in.dto.AcademicTestNotificationCommand; import com.kustacks.kuring.message.application.port.out.FirebaseSubscribePort; import com.kustacks.kuring.notice.domain.CategoryName; import com.kustacks.kuring.user.application.port.out.UserQueryPort; @@ -82,6 +83,14 @@ public void createRealNoticeForAllUser(RealNotificationCommand command) { adminEventPort.sendNotificationByAdmin(command.title(), command.body(), command.url()); } + @Override + public void createAcademicTestNotification(AcademicTestNotificationCommand command) { + adminEventPort.sendAcademicTestNotification( + command.title(), + command.body() + ); + } + @Override public void addAlertSchedule(AlertCreateCommand command) { adminAlertEventPort.addAlertSchedule(command.title(), command.content(), command.alertTime()); diff --git a/src/main/java/com/kustacks/kuring/calendar/application/service/AcademicEventNotificationService.java b/src/main/java/com/kustacks/kuring/calendar/application/service/AcademicEventNotificationService.java index 454c164eb..7ecef0004 100644 --- a/src/main/java/com/kustacks/kuring/calendar/application/service/AcademicEventNotificationService.java +++ b/src/main/java/com/kustacks/kuring/calendar/application/service/AcademicEventNotificationService.java @@ -16,6 +16,7 @@ import java.util.List; import static com.kustacks.kuring.message.application.service.FirebaseSubscribeService.ACADEMIC_EVENT_TOPIC; +import static com.kustacks.kuring.message.domain.MessageType.ACADEMIC; @Slf4j @UseCase @@ -99,6 +100,7 @@ private Message makeMessage(String title, String body) { .setTopic(serverProperties.ifDevThenAddSuffix(ACADEMIC_EVENT_TOPIC)) .putData("title", title) .putData("body", body) + .putData("messageType", ACADEMIC.getValue()) .build(); } } \ No newline at end of file diff --git a/src/main/java/com/kustacks/kuring/common/dto/ResponseCodeAndMessages.java b/src/main/java/com/kustacks/kuring/common/dto/ResponseCodeAndMessages.java index 406454886..5c019a824 100644 --- a/src/main/java/com/kustacks/kuring/common/dto/ResponseCodeAndMessages.java +++ b/src/main/java/com/kustacks/kuring/common/dto/ResponseCodeAndMessages.java @@ -30,6 +30,7 @@ public enum ResponseCodeAndMessages { ADMIN_LOAD_BAD_WORDS(HttpStatus.OK.value(), "금칙어 로드에 성공했습니다."), ADMIN_LOAD_WHITELIST_WORDS(HttpStatus.OK.value(), "허용 단어 로드에 성공했습니다."), ADMIN_USER_SUBSCRIPTION_UPDATE_SUCCESS(HttpStatus.OK.value(), "사용자들의 구독 정보를 성공적으로 재설정했습니다."), + ADMIN_TEST_ACADEMIC_CREATE_SUCCESS(HttpStatus.OK.value(), "테스트 학사일정 알림 생성에 성공하였습니다"), /* User */ USER_REGISTER_SUCCESS(HttpStatus.OK.value(), "회원가입에 성공하였습니다"), @@ -52,7 +53,7 @@ public enum ResponseCodeAndMessages { /* Email */ EMAIL_SEND_SUCCESS(HttpStatus.OK.value(), "이메일 전송에 성공했습니다."), - EMAIL_CODE_VERIFY_SUCCESS(HttpStatus.OK.value(),"인증에 성공했습니다."), + EMAIL_CODE_VERIFY_SUCCESS(HttpStatus.OK.value(), "인증에 성공했습니다."), REPORT_SEARCH_SUCCESS(HttpStatus.OK.value(), "신고 목록 조회에 성공하였습니다"), REPORT_COMMENT_SUCCESS(HttpStatus.CREATED.value(), "댓글 신고에 성공했습니다"), diff --git a/src/main/java/com/kustacks/kuring/message/adapter/in/event/MessageAdminEventListener.java b/src/main/java/com/kustacks/kuring/message/adapter/in/event/MessageAdminEventListener.java index 5103ccc84..500a8d988 100644 --- a/src/main/java/com/kustacks/kuring/message/adapter/in/event/MessageAdminEventListener.java +++ b/src/main/java/com/kustacks/kuring/message/adapter/in/event/MessageAdminEventListener.java @@ -1,5 +1,6 @@ package com.kustacks.kuring.message.adapter.in.event; +import com.kustacks.kuring.message.adapter.in.event.dto.AcademicTestNotificationEvent; import com.kustacks.kuring.message.adapter.in.event.dto.AdminNotificationEvent; import com.kustacks.kuring.message.adapter.in.event.dto.AdminTestNotificationEvent; import com.kustacks.kuring.message.adapter.in.event.dto.AlertSendEvent; @@ -37,4 +38,13 @@ public void sendAlertEvent( ) { firebaseWithAdminUseCase.sendNotificationByAdmin(event.toCommand()); } + + @Async + @EventListener + public void sendAcademicTestNotificationEvent( + AcademicTestNotificationEvent event + ) { + firebaseWithAdminUseCase.sendAcademicTestNotification(event.toCommand()); + } + } diff --git a/src/main/java/com/kustacks/kuring/message/adapter/in/event/dto/AcademicTestNotificationEvent.java b/src/main/java/com/kustacks/kuring/message/adapter/in/event/dto/AcademicTestNotificationEvent.java new file mode 100644 index 000000000..64c724c79 --- /dev/null +++ b/src/main/java/com/kustacks/kuring/message/adapter/in/event/dto/AcademicTestNotificationEvent.java @@ -0,0 +1,12 @@ +package com.kustacks.kuring.message.adapter.in.event.dto; + +import com.kustacks.kuring.message.application.port.in.dto.AcademicTestNotificationCommand; + +public record AcademicTestNotificationEvent( + String title, + String body +) { + public AcademicTestNotificationCommand toCommand() { + return new AcademicTestNotificationCommand(title, body); + } +} diff --git a/src/main/java/com/kustacks/kuring/message/application/port/in/FirebaseWithAdminUseCase.java b/src/main/java/com/kustacks/kuring/message/application/port/in/FirebaseWithAdminUseCase.java index 76f9ed305..22970b96b 100644 --- a/src/main/java/com/kustacks/kuring/message/application/port/in/FirebaseWithAdminUseCase.java +++ b/src/main/java/com/kustacks/kuring/message/application/port/in/FirebaseWithAdminUseCase.java @@ -1,9 +1,14 @@ package com.kustacks.kuring.message.application.port.in; +import com.kustacks.kuring.message.application.port.in.dto.AcademicTestNotificationCommand; import com.kustacks.kuring.message.application.port.in.dto.AdminNotificationCommand; import com.kustacks.kuring.message.application.port.in.dto.AdminTestNotificationCommand; public interface FirebaseWithAdminUseCase { void sendNotificationByAdmin(AdminNotificationCommand command); + void sendTestNotificationByAdmin(AdminTestNotificationCommand command); + + void sendAcademicTestNotification(AcademicTestNotificationCommand command); + } diff --git a/src/main/java/com/kustacks/kuring/message/application/port/in/dto/AcademicTestNotificationCommand.java b/src/main/java/com/kustacks/kuring/message/application/port/in/dto/AcademicTestNotificationCommand.java new file mode 100644 index 000000000..706bf7147 --- /dev/null +++ b/src/main/java/com/kustacks/kuring/message/application/port/in/dto/AcademicTestNotificationCommand.java @@ -0,0 +1,7 @@ +package com.kustacks.kuring.message.application.port.in.dto; + +public record AcademicTestNotificationCommand( + String title, + String body +) { +} diff --git a/src/main/java/com/kustacks/kuring/message/application/service/FirebaseNotificationService.java b/src/main/java/com/kustacks/kuring/message/application/service/FirebaseNotificationService.java index 6bf7f55e3..d736732e4 100644 --- a/src/main/java/com/kustacks/kuring/message/application/service/FirebaseNotificationService.java +++ b/src/main/java/com/kustacks/kuring/message/application/service/FirebaseNotificationService.java @@ -9,6 +9,7 @@ import com.kustacks.kuring.common.exception.code.ErrorCode; import com.kustacks.kuring.common.properties.ServerProperties; import com.kustacks.kuring.message.application.port.in.FirebaseWithAdminUseCase; +import com.kustacks.kuring.message.application.port.in.dto.AcademicTestNotificationCommand; import com.kustacks.kuring.message.application.port.in.dto.AdminNotificationCommand; import com.kustacks.kuring.message.application.port.in.dto.AdminTestNotificationCommand; import com.kustacks.kuring.message.application.port.out.FirebaseMessagingPort; @@ -22,7 +23,11 @@ import java.util.Map; import java.util.function.UnaryOperator; +import static com.kustacks.kuring.message.application.service.FirebaseSubscribeService.ACADEMIC_EVENT_TOPIC; import static com.kustacks.kuring.message.application.service.FirebaseSubscribeService.ALL_DEVICE_SUBSCRIBED_TOPIC; +import static com.kustacks.kuring.message.domain.MessageType.ACADEMIC; +import static com.kustacks.kuring.message.domain.MessageType.ADMIN; +import static com.kustacks.kuring.message.domain.MessageType.NOTICE; @Slf4j @UseCase @@ -62,6 +67,29 @@ public void sendNotifications(List noticeList) { sendNotices(notificationDtoList); } + @Override + public void sendAcademicTestNotification(AcademicTestNotificationCommand command) { + try { + Message newMessage = Message.builder() + .setNotification(Notification.builder() + .setTitle(command.title()) + .setBody(command.body()) + .build()) + .putAllData(Map.of( + "title", command.title(), + "body", command.body(), + "messageType", ACADEMIC.getValue() + )) + .setTopic(serverProperties.addDevSuffix(ACADEMIC_EVENT_TOPIC)) + .build(); + + firebaseMessagingPort.send(newMessage); + } catch (FirebaseMessagingException exception) { + throw new FirebaseMessageSendException(); + } + } + + private void sendNotices(List notificationDtoList) { try { loggingNoticeSendInfo(notificationDtoList); @@ -127,6 +155,7 @@ private Message createMessageFromCommand(AdminNotificationCommand command) { .setBody(command.body()) .build()) .putAllData(objectMapper.convertValue(command, Map.class)) + .putData("messageType", ADMIN.getValue()) .setTopic(serverProperties.ifDevThenAddSuffix(ALL_DEVICE_SUBSCRIBED_TOPIC)) .build(); } @@ -139,6 +168,7 @@ private Message createMessageFromDto(NoticeMessageDto messageDto, UnaryOperator< .setBody(messageDto.getSubject()) .build()) .putAllData(objectMapper.convertValue(messageDto, Map.class)) + .putData("messageType", NOTICE.getValue()) .setTopic(suffixUtil.apply(messageDto.getCategory())) .build(); } diff --git a/src/main/java/com/kustacks/kuring/message/domain/MessageType.java b/src/main/java/com/kustacks/kuring/message/domain/MessageType.java new file mode 100644 index 000000000..35f830d68 --- /dev/null +++ b/src/main/java/com/kustacks/kuring/message/domain/MessageType.java @@ -0,0 +1,15 @@ +package com.kustacks.kuring.message.domain; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum MessageType { + + NOTICE("notice"), + ADMIN("admin"), + ACADEMIC("academic"); + + private final String value; +} diff --git a/src/main/java/com/kustacks/kuring/notice/domain/DepartmentName.java b/src/main/java/com/kustacks/kuring/notice/domain/DepartmentName.java index 2ef9eb11f..0c3e0783c 100644 --- a/src/main/java/com/kustacks/kuring/notice/domain/DepartmentName.java +++ b/src/main/java/com/kustacks/kuring/notice/domain/DepartmentName.java @@ -53,7 +53,7 @@ public enum DepartmentName { BUIS_ADMIN("business_administration", "biz", "경영학과"), TECH_BUSI("technological_business", "mot", "기술경영학과"), - REAL_ESTATE("real_estate", "rest", "부동산학과"), + REAL_ESTATE("real_estate", "kure", "부동산학과"), ENERGY("energy", "energy", "미래에너지공학과"), SMART_VEHICLE("smart_vehicle", "smartvehicle", "스마트운행체공학과"), diff --git a/src/main/java/com/kustacks/kuring/worker/parser/notice/LatestPageNoticeHtmlParser.java b/src/main/java/com/kustacks/kuring/worker/parser/notice/LatestPageNoticeHtmlParser.java index 9f9127fc7..107e2dc04 100644 --- a/src/main/java/com/kustacks/kuring/worker/parser/notice/LatestPageNoticeHtmlParser.java +++ b/src/main/java/com/kustacks/kuring/worker/parser/notice/LatestPageNoticeHtmlParser.java @@ -1,7 +1,6 @@ package com.kustacks.kuring.worker.parser.notice; import com.kustacks.kuring.worker.scrap.deptinfo.DeptInfo; -import com.kustacks.kuring.worker.scrap.deptinfo.real_estate.RealEstateDept; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; @@ -12,7 +11,7 @@ public class LatestPageNoticeHtmlParser extends NoticeHtmlParserTemplate { @Override public boolean support(DeptInfo deptInfo) { - return !(deptInfo instanceof RealEstateDept); + return true; } @Override diff --git a/src/main/java/com/kustacks/kuring/worker/parser/notice/RealEstateNoticeHtmlParser.java b/src/main/java/com/kustacks/kuring/worker/parser/notice/RealEstateNoticeHtmlParser.java deleted file mode 100644 index 3d04d8134..000000000 --- a/src/main/java/com/kustacks/kuring/worker/parser/notice/RealEstateNoticeHtmlParser.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.kustacks.kuring.worker.parser.notice; - -import com.kustacks.kuring.worker.scrap.deptinfo.DeptInfo; -import com.kustacks.kuring.worker.scrap.deptinfo.real_estate.RealEstateDept; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; -import org.springframework.stereotype.Component; -import org.springframework.util.MultiValueMap; -import org.springframework.web.util.UriComponents; -import org.springframework.web.util.UriComponentsBuilder; - -@Component -public class RealEstateNoticeHtmlParser extends NoticeHtmlParserTemplate { - - @Override - public boolean support(DeptInfo deptInfo) { - return deptInfo instanceof RealEstateDept; - } - - @Override - protected Elements selectImportantRows(Document document) { - return new Elements(); - } - - @Override - protected Elements selectNormalRows(Document document) { - return document.select(".board_list > table > tbody > tr"); - } - - @Override - protected String[] extractNoticeFromRow(Element row) { - String[] oneNoticeInfo = new String[3]; - Elements tds = row.getElementsByTag("td"); - - Element subjectAndIdElement = tds.get(2).getElementsByTag("a").get(0); - - UriComponents hrefUri = UriComponentsBuilder.fromUriString(subjectAndIdElement.attr("href")).build(); - MultiValueMap queryParams = hrefUri.getQueryParams(); - - oneNoticeInfo[0] = queryParams.get("wr_id").get(0); - oneNoticeInfo[1] = tds.get(3).ownText(); - oneNoticeInfo[2] = subjectAndIdElement.ownText(); - return oneNoticeInfo; - } -} diff --git a/src/main/java/com/kustacks/kuring/worker/scrap/client/notice/RealEstateNoticeApiClient.java b/src/main/java/com/kustacks/kuring/worker/scrap/client/notice/RealEstateNoticeApiClient.java deleted file mode 100644 index 8605a7c7c..000000000 --- a/src/main/java/com/kustacks/kuring/worker/scrap/client/notice/RealEstateNoticeApiClient.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.kustacks.kuring.worker.scrap.client.notice; - -import com.kustacks.kuring.common.exception.InternalLogicException; -import com.kustacks.kuring.common.exception.code.ErrorCode; -import com.kustacks.kuring.worker.dto.ScrapingResultDto; -import com.kustacks.kuring.worker.scrap.client.ProxyJsoupClient; -import com.kustacks.kuring.worker.scrap.client.notice.property.RealEstateNoticeProperties; -import com.kustacks.kuring.worker.scrap.deptinfo.DeptInfo; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.springframework.stereotype.Component; -import org.springframework.util.MultiValueMap; -import org.springframework.web.util.UriComponents; -import org.springframework.web.util.UriComponentsBuilder; - -import java.io.IOException; -import java.util.LinkedList; -import java.util.List; - -@Component -public class RealEstateNoticeApiClient implements NoticeApiClient { - - private static final int PAGE_NUM = 1; - private static final int UNKNOWN_PAGE_NUM = -1; - private static final int ESTATE_SCRAP_TIMEOUT = 300000; - - private final ProxyJsoupClient jsoupClient; - private final RealEstateNoticeProperties realEstateNoticeProperties; - - public RealEstateNoticeApiClient(ProxyJsoupClient proxyJsoupClient, RealEstateNoticeProperties realEstateNoticeProperties) { - this.jsoupClient = proxyJsoupClient; - this.realEstateNoticeProperties = realEstateNoticeProperties; - } - - @Override - public List request(DeptInfo deptInfo) throws InternalLogicException { - try { - String sca = "학부"; - String viewUrl = createViewUrl(sca); - String reqUrl = createRequestUrl(sca, PAGE_NUM); - - Document document = jsoupClient.get(reqUrl, ESTATE_SCRAP_TIMEOUT); - - return List.of(new ScrapingResultDto(document, viewUrl)); - } catch (IOException e) { - throw new InternalLogicException(ErrorCode.NOTICE_SCRAPER_CANNOT_SCRAP, e); - } catch (IndexOutOfBoundsException e) { - throw new InternalLogicException(ErrorCode.NOTICE_SCRAPER_CANNOT_PARSE, e); - } - } - - @Override - public List requestAll(DeptInfo deptInfo) throws InternalLogicException { - int totalPageNum = UNKNOWN_PAGE_NUM; - int nowPageNum = 1; - String sca = "학부"; - String viewUrl = createViewUrl(sca); - - List reqResults = new LinkedList<>(); - do { - try { - String requestUrl = createRequestUrl(sca, nowPageNum); - - Document document = jsoupClient.get(requestUrl, ESTATE_SCRAP_TIMEOUT); - reqResults.add(new ScrapingResultDto(document, viewUrl)); - - if (totalPageNum == UNKNOWN_PAGE_NUM) { - totalPageNum = getTotalPageNum(document); - } - - nowPageNum++; - } catch (IOException e) { - throw new InternalLogicException(ErrorCode.NOTICE_SCRAPER_CANNOT_SCRAP, e); - } catch (IndexOutOfBoundsException e) { - throw new InternalLogicException(ErrorCode.NOTICE_SCRAPER_CANNOT_PARSE, e); - } - } while (nowPageNum <= totalPageNum); - - return reqResults; - } - - @Override - public ScrapingResultDto requestSinglePageWithUrl(DeptInfo noticeInfo, String url) { - throw new InternalLogicException(ErrorCode.NOTICE_SCRAPER_CANNOT_PARSE); - } - - private int getTotalPageNum(Document document) { - Element lastPageNumElement = document.select(".paging > ul > li").last(); - Element lastPageBtnElement = lastPageNumElement.getElementsByTag("a").get(1); - String hrefValue = lastPageBtnElement.attr("href"); - - UriComponents hrefUri = UriComponentsBuilder.fromUriString(hrefValue).build(); - MultiValueMap queryParams = hrefUri.getQueryParams(); - List page = queryParams.get("page"); - return Integer.parseInt(page.get(0)); - } - - private String createRequestUrl(String sca, int pageNum) { - return UriComponentsBuilder - .fromUriString(realEstateNoticeProperties.listUrl()) - .queryParam("sca", sca) - .queryParam("page", pageNum) - .build() - .toUriString(); - } - - private String createViewUrl(String sca) { - return UriComponentsBuilder - .fromUriString(realEstateNoticeProperties.viewUrl()) - .queryParam("sca", sca) - .queryParam("wr_id", "") - .build() - .toUriString(); - } -} diff --git a/src/main/java/com/kustacks/kuring/worker/scrap/client/notice/property/RealEstateNoticeProperties.java b/src/main/java/com/kustacks/kuring/worker/scrap/client/notice/property/RealEstateNoticeProperties.java deleted file mode 100644 index 55a5f1066..000000000 --- a/src/main/java/com/kustacks/kuring/worker/scrap/client/notice/property/RealEstateNoticeProperties.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.kustacks.kuring.worker.scrap.client.notice.property; - -import org.springframework.boot.context.properties.ConfigurationProperties; - - -@ConfigurationProperties(prefix = "notice.real-estate") -public record RealEstateNoticeProperties( - String listUrl, - String viewUrl -) { -} diff --git a/src/main/java/com/kustacks/kuring/worker/scrap/deptinfo/real_estate/RealEstateDept.java b/src/main/java/com/kustacks/kuring/worker/scrap/deptinfo/real_estate/RealEstateDept.java index 3669edcf6..b97191292 100644 --- a/src/main/java/com/kustacks/kuring/worker/scrap/deptinfo/real_estate/RealEstateDept.java +++ b/src/main/java/com/kustacks/kuring/worker/scrap/deptinfo/real_estate/RealEstateDept.java @@ -1,8 +1,8 @@ package com.kustacks.kuring.worker.scrap.deptinfo.real_estate; -import com.kustacks.kuring.worker.parser.notice.RealEstateNoticeHtmlParser; +import com.kustacks.kuring.worker.parser.notice.LatestPageNoticeHtmlParser; import com.kustacks.kuring.worker.scrap.client.notice.LatestPageGraduateNoticeApiClient; -import com.kustacks.kuring.worker.scrap.client.notice.RealEstateNoticeApiClient; +import com.kustacks.kuring.worker.scrap.client.notice.LatestPageNoticeApiClient; import com.kustacks.kuring.worker.scrap.client.notice.property.LatestPageNoticeProperties; import com.kustacks.kuring.worker.scrap.deptinfo.NoticeScrapInfo; import com.kustacks.kuring.worker.scrap.deptinfo.RegisterDepartmentMap; @@ -15,17 +15,19 @@ @RegisterDepartmentMap(key = REAL_ESTATE) public class RealEstateDept extends RealEstateCollege { - public RealEstateDept(RealEstateNoticeApiClient realEstateNoticeApiClient, - RealEstateNoticeHtmlParser realEstateNoticeHtmlParser, - LatestPageNoticeProperties latestPageNoticeProperties, - LatestPageGraduateNoticeApiClient latestPageGraduateNoticeApiClient) { + public RealEstateDept( + LatestPageNoticeApiClient latestPageNoticeApiClient, + LatestPageNoticeHtmlParser latestPageNoticeHtmlParser, + LatestPageNoticeProperties latestPageNoticeProperties, + LatestPageGraduateNoticeApiClient latestPageGraduateNoticeApiClient + ) { super(); - this.noticeApiClient = realEstateNoticeApiClient; - this.htmlParser = realEstateNoticeHtmlParser; + this.noticeApiClient = latestPageNoticeApiClient; + this.htmlParser = latestPageNoticeHtmlParser; this.latestPageNoticeProperties = latestPageNoticeProperties; List siteIds = List.of(13949); - this.staffScrapInfo = new StaffScrapInfo("kure", siteIds); + this.staffScrapInfo = new StaffScrapInfo(REAL_ESTATE.getHostPrefix(), siteIds); this.noticeScrapInfo = new NoticeScrapInfo(REAL_ESTATE.getHostPrefix(), 1563); this.departmentName = REAL_ESTATE; this.noticeGraduationInfo = new NoticeScrapInfo(REAL_ESTATE.getHostPrefix(), 1565); diff --git a/src/main/java/com/kustacks/kuring/worker/update/notice/DepartmentGraduationNoticeUpdater.java b/src/main/java/com/kustacks/kuring/worker/update/notice/DepartmentGraduationNoticeUpdater.java index dc12b4504..5b732c840 100644 --- a/src/main/java/com/kustacks/kuring/worker/update/notice/DepartmentGraduationNoticeUpdater.java +++ b/src/main/java/com/kustacks/kuring/worker/update/notice/DepartmentGraduationNoticeUpdater.java @@ -23,8 +23,6 @@ import java.util.concurrent.CompletableFuture; import java.util.function.Function; -import static com.kustacks.kuring.notice.domain.DepartmentName.REAL_ESTATE; - @Slf4j @Service @RequiredArgsConstructor @@ -68,10 +66,6 @@ public void updateAll() { List graduateDeptInfoList = getGraduateDeptInfoList(); for (DeptInfo deptInfo : graduateDeptInfoList) { - if (deptInfo.isSameDepartment(REAL_ESTATE)) { - continue; - } - CompletableFuture .supplyAsync(() -> updateDepartmentAsync(deptInfo, DeptInfo::scrapGraduateAllPageHtml), noticeUpdaterThreadTaskExecutor) .thenAccept(scrapResults -> compareAllAndUpdateDB(scrapResults, deptInfo.getDeptName())); diff --git a/src/main/java/com/kustacks/kuring/worker/update/notice/DepartmentNoticeUpdater.java b/src/main/java/com/kustacks/kuring/worker/update/notice/DepartmentNoticeUpdater.java index 31a5cbf9c..05633667a 100644 --- a/src/main/java/com/kustacks/kuring/worker/update/notice/DepartmentNoticeUpdater.java +++ b/src/main/java/com/kustacks/kuring/worker/update/notice/DepartmentNoticeUpdater.java @@ -24,8 +24,6 @@ import java.util.concurrent.CompletableFuture; import java.util.function.Function; -import static com.kustacks.kuring.notice.domain.DepartmentName.REAL_ESTATE; - @Slf4j @Service @RequiredArgsConstructor @@ -64,9 +62,6 @@ public void updateAll() { log.info("******** 학과별 (학사) 전체 공지 업데이트 시작 ********"); for (DeptInfo deptInfo : deptInfoList) { - if (deptInfo.isSameDepartment(REAL_ESTATE)) { - continue; - } CompletableFuture .supplyAsync(() -> updateDepartmentAsync(deptInfo, DeptInfo::scrapAllPageHtml), noticeUpdaterThreadTaskExecutor) .thenAccept(scrapResults -> compareAllAndUpdateDB(scrapResults, deptInfo.getDeptName())); diff --git a/src/main/resources/config/environments/common.yml b/src/main/resources/config/environments/common.yml index e404f6959..6cc06bbc7 100644 --- a/src/main/resources/config/environments/common.yml +++ b/src/main/resources/config/environments/common.yml @@ -135,9 +135,6 @@ notice: homepage: list-url: https://www.konkuk.ac.kr/bbs/{category}/{siteId}/artclList.do view-url: https://www.konkuk.ac.kr/bbs/{category}/{siteId}/{noticeId}/artclView.do - real-estate: - list-url: http://www.realestate.ac.kr/gb/bbs/board.php?bo_table=notice - view-url: http://www.realestate.ac.kr/gb/bbs/board.php?bo_table=notice recent: list-url: https://{department}.konkuk.ac.kr/bbs/{department}/{siteId}/artclList.do view-url: https://{department}.konkuk.ac.kr/bbs/{department}/{siteId}/{noticeId}/artclView.do diff --git a/src/test/java/com/kustacks/kuring/acceptance/AdminAcceptanceTest.java b/src/test/java/com/kustacks/kuring/acceptance/AdminAcceptanceTest.java index 836512b83..8d32f08f9 100644 --- a/src/test/java/com/kustacks/kuring/acceptance/AdminAcceptanceTest.java +++ b/src/test/java/com/kustacks/kuring/acceptance/AdminAcceptanceTest.java @@ -1,5 +1,6 @@ package com.kustacks.kuring.acceptance; +import com.kustacks.kuring.admin.adapter.in.web.dto.AcademicTestNotificationRequest; import com.kustacks.kuring.admin.adapter.in.web.dto.AdminAlertCreateRequest; import com.kustacks.kuring.admin.adapter.in.web.dto.RealNotificationRequest; import com.kustacks.kuring.admin.adapter.in.web.dto.TestNotificationRequest; @@ -27,6 +28,7 @@ import static com.kustacks.kuring.acceptance.AdminStep.알림_예약; import static com.kustacks.kuring.acceptance.AdminStep.예약_알림_삭제; import static com.kustacks.kuring.acceptance.AdminStep.예약_알림_조회; +import static com.kustacks.kuring.acceptance.AdminStep.테스트_학사일정_알림_발송; import static com.kustacks.kuring.acceptance.AdminStep.피드백_조회_확인; import static com.kustacks.kuring.acceptance.AdminStep.허용_단어_로드_요청; import static com.kustacks.kuring.acceptance.AuthStep.로그인_되어_있음; @@ -150,6 +152,28 @@ void role_root_admin_create_real_notification() { ); } + @DisplayName("[v2] 테스트 학사일정 알림 발송") + @Test + void role_root_admin_send_academic_test_notification() { + // given + String accessToken = 로그인_되어_있음(ADMIN_LOGIN_ID, ADMIN_PASSWORD); + + // when + var response = 테스트_학사일정_알림_발송( + accessToken, + new AcademicTestNotificationRequest("테스트-수강신청 일정", "오늘은 수강신청 일정이 있어요") + ); + + // then + assertAll( + () -> assertThat(response.statusCode()).isEqualTo(HttpStatus.OK.value()), + () -> assertThat(response.jsonPath().getInt("code")).isEqualTo(200), + () -> assertThat(response.jsonPath().getString("message")) + .isEqualTo("테스트 학사일정 알림 생성에 성공하였습니다"), + () -> assertThat(response.jsonPath().getString("data")).isNull() + ); + } + /** * Given : 등록된 ROLE_ROOT의 Admin이 있다. * When : 원하는 시간에 예약 알림을 등록한다 diff --git a/src/test/java/com/kustacks/kuring/acceptance/AdminStep.java b/src/test/java/com/kustacks/kuring/acceptance/AdminStep.java index 7707fc430..1fbb62573 100644 --- a/src/test/java/com/kustacks/kuring/acceptance/AdminStep.java +++ b/src/test/java/com/kustacks/kuring/acceptance/AdminStep.java @@ -1,5 +1,6 @@ package com.kustacks.kuring.acceptance; +import com.kustacks.kuring.admin.adapter.in.web.dto.AcademicTestNotificationRequest; import com.kustacks.kuring.admin.adapter.in.web.dto.AdminAlertCreateRequest; import io.restassured.RestAssured; import io.restassured.response.ExtractableResponse; @@ -137,4 +138,20 @@ public class AdminStep { () -> assertThat(response.jsonPath().getString("data")).isNull() ); } + + public static ExtractableResponse 테스트_학사일정_알림_발송( + String accessToken, + AcademicTestNotificationRequest request + ) { + return RestAssured + .given().log().all() + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .accept(MediaType.APPLICATION_JSON_VALUE) + .body(request) + .when().post("/api/v2/admin/academic/dev") + .then().log().all() + .extract(); + } + } diff --git a/src/test/java/com/kustacks/kuring/worker/parser/NoticeHtmlParserTemplateTest.java b/src/test/java/com/kustacks/kuring/worker/parser/NoticeHtmlParserTemplateTest.java index 0e00f37b3..81e05c687 100644 --- a/src/test/java/com/kustacks/kuring/worker/parser/NoticeHtmlParserTemplateTest.java +++ b/src/test/java/com/kustacks/kuring/worker/parser/NoticeHtmlParserTemplateTest.java @@ -1,7 +1,9 @@ package com.kustacks.kuring.worker.parser; import com.kustacks.kuring.support.TestFileLoader; -import com.kustacks.kuring.worker.parser.notice.*; +import com.kustacks.kuring.worker.parser.notice.KuisHomepageNoticeHtmlParser; +import com.kustacks.kuring.worker.parser.notice.LatestPageNoticeHtmlParser; +import com.kustacks.kuring.worker.parser.notice.RowsDto; import com.kustacks.kuring.worker.update.notice.dto.response.CommonNoticeFormatDto; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -133,24 +135,6 @@ void LatestPageNoticeHtmlParserNoticeId() throws IOException { ); } - @DisplayName("부동산 학과의 경우 별도의 HTML 파서를 사용하여 공지를 분석한다") - @Test - void RealEstateNoticeHtmlParser() throws IOException { - // given - Document doc = Jsoup.parse(TestFileLoader.loadHtmlFile("src/test/resources/notice/realestate.html")); - - // when - RowsDto rowsDto = new RealEstateNoticeHtmlParser().parse(doc); - List important = rowsDto.buildImportantRowList("important"); - List normal = rowsDto.buildNormalRowList("normal"); - - // then - assertAll( - () -> assertThat(important).isEmpty(), - () -> assertThat(normal).hasSize(15) - ); - } - @DisplayName("View Url이 정상적으로 생석되는지 확인한다") @Test void viewUrlCreate() {