diff --git a/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/domain/CrawlingJobPostingService.kt b/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/domain/CrawlingJobPostingService.kt index 869b35b8..5f3c23dc 100644 --- a/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/domain/CrawlingJobPostingService.kt +++ b/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/domain/CrawlingJobPostingService.kt @@ -29,11 +29,13 @@ class CrawlingJobPostingService( } fun findAllByCarerLocationInRange( + carerId: UUID, location: Point, next: UUID?, limit: Long, ): List { return crawlingJobPostingSpatialQueryRepository.findAllInRange( + carerId = carerId, location = location, next = next, limit = limit, diff --git a/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/domain/JobPostingService.kt b/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/domain/JobPostingService.kt index 2bf2c274..9cad2995 100644 --- a/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/domain/JobPostingService.kt +++ b/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/domain/JobPostingService.kt @@ -11,7 +11,6 @@ import com.swm.idle.domain.jobposting.enums.PayType import com.swm.idle.domain.jobposting.repository.jpa.JobPostingJpaRepository import com.swm.idle.domain.jobposting.repository.querydsl.JobPostingQueryRepository import com.swm.idle.domain.jobposting.repository.querydsl.JobPostingSpatialQueryRepository -import com.swm.idle.domain.user.carer.entity.jpa.Carer import com.swm.idle.domain.user.common.enum.GenderType import com.swm.idle.domain.user.common.vo.BirthYear import org.locationtech.jts.geom.Point @@ -195,13 +194,13 @@ class JobPostingService( } fun findAllByCarerLocationInRange( - carer: Carer, + carerId: UUID, location: Point, next: UUID?, limit: Long, ): List { return jobPostingSpatialQueryRepository.findAllWithWeekdaysInRange( - carer = carer, + carerId = carerId, location = location, next = next, limit = limit, diff --git a/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/facade/CarerJobPostingFacadeService.kt b/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/facade/CarerJobPostingFacadeService.kt index aed5b300..cefab582 100644 --- a/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/facade/CarerJobPostingFacadeService.kt +++ b/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/facade/CarerJobPostingFacadeService.kt @@ -106,19 +106,17 @@ class CarerJobPostingFacadeService( } val jobPostingPreviewDtos = jobPostingService.findAllByCarerLocationInRange( - carer = carer, + carerId = carer.id, location = location, next = next, limit = limit + 1, ) - val carerLocation = PointConverter.convertToPoint( latitude = carer.latitude.toDouble(), longitude = carer.longitude.toDouble(), ) - for (jobPostingPreviewDto in jobPostingPreviewDtos) { jobPostingPreviewDto.distance = jobPostingService.calculateDistance( jobPostingPreviewDto.jobPosting, diff --git a/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/facade/CrawlingJobPostingFacadeService.kt b/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/facade/CrawlingJobPostingFacadeService.kt index cf72c638..411e3d1f 100644 --- a/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/facade/CrawlingJobPostingFacadeService.kt +++ b/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/facade/CrawlingJobPostingFacadeService.kt @@ -7,7 +7,6 @@ import com.swm.idle.application.jobposting.domain.JobPostingFavoriteService import com.swm.idle.application.user.carer.domain.CarerService import com.swm.idle.domain.common.dto.CrawlingJobPostingPreviewDto import com.swm.idle.domain.user.carer.entity.jpa.Carer -import com.swm.idle.infrastructure.client.geocode.service.GeoCodeService import com.swm.idle.support.transfer.common.CursorScrollRequest import com.swm.idle.support.transfer.jobposting.carer.CrawlingJobPostingFavoriteResponse import com.swm.idle.support.transfer.jobposting.carer.CrawlingJobPostingScrollResponse @@ -19,7 +18,6 @@ import java.util.* @Service class CrawlingJobPostingFacadeService( private val crawlingJobPostingService: CrawlingJobPostingService, - private val geoCodeService: GeoCodeService, private val carerService: CarerService, private val jobPostingFavoriteService: JobPostingFavoriteService, ) { @@ -99,20 +97,21 @@ class CrawlingJobPostingFacadeService( next: UUID?, limit: Long, ): Pair, UUID?> { + val carer = getUserAuthentication().userId.let { + carerService.getById(it) + } + val crawlingJobPostingPreviewDtos = crawlingJobPostingService.findAllByCarerLocationInRange( + carerId = carer.id, location = location, next = next, limit = limit + 1, ) - val carerLocation = getUserAuthentication().userId.let { - carerService.getById(it) - }.let { - PointConverter.convertToPoint( - latitude = it.latitude.toDouble(), - longitude = it.longitude.toDouble(), - ) - } + val carerLocation = PointConverter.convertToPoint( + latitude = carer.latitude.toDouble(), + longitude = carer.longitude.toDouble(), + ) for (crawlingJobPostingPreviewDto in crawlingJobPostingPreviewDtos) { crawlingJobPostingPreviewDto.distance = crawlingJobPostingService.calculateDistance( diff --git a/idle-application/src/main/kotlin/com/swm/idle/application/user/center/service/domain/CenterManagerService.kt b/idle-application/src/main/kotlin/com/swm/idle/application/user/center/service/domain/CenterManagerService.kt index 6fd56c9f..47681d49 100644 --- a/idle-application/src/main/kotlin/com/swm/idle/application/user/center/service/domain/CenterManagerService.kt +++ b/idle-application/src/main/kotlin/com/swm/idle/application/user/center/service/domain/CenterManagerService.kt @@ -91,4 +91,8 @@ class CenterManagerService( ) } + fun findAllByStatusPending(): List? { + return centerManagerJpaRepository.findAllByStatusPending() + } + } diff --git a/idle-application/src/main/kotlin/com/swm/idle/application/user/center/service/facade/CenterAuthFacadeService.kt b/idle-application/src/main/kotlin/com/swm/idle/application/user/center/service/facade/CenterAuthFacadeService.kt index f4467be9..a2e6ea1e 100644 --- a/idle-application/src/main/kotlin/com/swm/idle/application/user/center/service/facade/CenterAuthFacadeService.kt +++ b/idle-application/src/main/kotlin/com/swm/idle/application/user/center/service/facade/CenterAuthFacadeService.kt @@ -19,6 +19,7 @@ import com.swm.idle.infrastructure.client.businessregistration.exception.Busines import com.swm.idle.infrastructure.client.businessregistration.service.BusinessRegistrationNumberValidationService import com.swm.idle.support.common.encrypt.PasswordEncryptor import com.swm.idle.support.security.exception.SecurityException +import com.swm.idle.support.transfer.auth.center.CenterManagerForPendingResponse import com.swm.idle.support.transfer.auth.center.ValidateBusinessRegistrationNumberResponse import com.swm.idle.support.transfer.auth.common.LoginResponse import com.swm.idle.support.transfer.user.center.JoinStatusInfoResponse @@ -151,4 +152,14 @@ class CenterAuthFacadeService( } } + fun getCenterManagerForPending(): CenterManagerForPendingResponse { + val centerManagers = centerManagerService.findAllByStatusPending() + + return centerManagers?.map { centerManager -> + CenterManagerForPendingResponse.PendingCenterManagerDto.of(centerManager) + }?.let { + CenterManagerForPendingResponse.of(it) + } ?: CenterManagerForPendingResponse.of(emptyList()) + } + } diff --git a/idle-batch/src/main/kotlin/com/swm/idle/batch/common/scheduler/CrawlingJobScheduler.kt b/idle-batch/src/main/kotlin/com/swm/idle/batch/common/scheduler/CrawlingJobScheduler.kt index 2db761e8..7192a043 100644 --- a/idle-batch/src/main/kotlin/com/swm/idle/batch/common/scheduler/CrawlingJobScheduler.kt +++ b/idle-batch/src/main/kotlin/com/swm/idle/batch/common/scheduler/CrawlingJobScheduler.kt @@ -13,7 +13,7 @@ class CrawlingJobScheduler( private val crawlingJobConfig: CrawlingJobConfig, ) { - @Scheduled(cron = "0 05 15 * * *") + @Scheduled(cron = "0 0 23 * * *") fun scheduleJob() { val jobParameters: JobParameters = JobParametersBuilder() .addLong("timestamp", System.currentTimeMillis()) diff --git a/idle-batch/src/main/kotlin/com/swm/idle/batch/util/WorknetCrawler.kt b/idle-batch/src/main/kotlin/com/swm/idle/batch/util/WorknetCrawler.kt index 810c75dd..3c8bf139 100644 --- a/idle-batch/src/main/kotlin/com/swm/idle/batch/util/WorknetCrawler.kt +++ b/idle-batch/src/main/kotlin/com/swm/idle/batch/util/WorknetCrawler.kt @@ -1,293 +1,3 @@ -//package com.swm.idle.batch.util -// -//import com.swm.idle.batch.common.dto.CrawledJobPostingDto -//import io.github.oshai.kotlinlogging.KotlinLogging -//import org.openqa.selenium.Alert -//import org.openqa.selenium.By -//import org.openqa.selenium.NoAlertPresentException -//import org.openqa.selenium.WebDriver -//import org.openqa.selenium.chrome.ChromeDriver -//import org.openqa.selenium.chrome.ChromeDriverService -//import org.openqa.selenium.chrome.ChromeOptions -//import org.openqa.selenium.support.ui.ExpectedConditions -//import org.openqa.selenium.support.ui.WebDriverWait -//import java.io.File -//import java.time.Duration -//import java.time.LocalDate -//import java.time.format.DateTimeFormatter -// -//object WorknetCrawler { -// -// private val logger = KotlinLogging.logger { } -// -// private const val CRAWLING_TARGET_URL_FORMAT = -// "https://www.work24.go.kr/wk/a/b/1200/retriveDtlEmpSrchList.do?basicSetupYn=&careerTo=&keywordJobCd=&occupation=&seqNo=&cloDateEndtParam=&payGbn=&templateInfo=&rot2WorkYn=&shsyWorkSecd=&srcKeywordParam=%EC%9A%94%EC%96%91%EB%B3%B4%ED%98%B8%EC%82%AC&resultCnt=10&keywordJobCont=&cert=&moreButtonYn=Y&minPay=&codeDepth2Info=11000¤tPageNo=1&eventNo=&mode=&major=&resrDutyExcYn=&eodwYn=&sortField=DATE&staArea=&sortOrderBy=DESC&keyword=%EC%9A%94%EC%96%91%EB%B3%B4%ED%98%B8%EC%82%AC&termSearchGbn=all&carrEssYns=&benefitSrchAndOr=O&disableEmpHopeGbn=&actServExcYn=&keywordStaAreaNm=&maxPay=&emailApplyYn=&codeDepth1Info=11000&keywordEtcYn=®DateStdtParam={yesterday}&publDutyExcYn=&keywordJobCdSeqNo=&viewType=&exJobsCd=&templateDepthNmInfo=®ion=&employGbn=&empTpGbcd=&computerPreferential=&infaYn=&cloDateStdtParam=&siteClcd=WORK&searchMode=Y&birthFromYY=&indArea=&careerTypes=&subEmpHopeYn=&tlmgYn=&academicGbn=&templateDepthNoInfo=&foriegn=&entryRoute=&mealOfferClcd=&basicSetupYnChk=&station=&holidayGbn=&srcKeyword=%EC%9A%94%EC%96%91%EB%B3%B4%ED%98%B8%EC%82%AC&academicGbnoEdu=noEdu&enterPriseGbn=all&cloTermSearchGbn=all&birthToYY=&keywordWantedTitle=&stationNm=&benefitGbn=¬SrcKeywordParam=&keywordFlag=¬SrcKeyword=&essCertChk=&depth2SelCode=&keywordBusiNm=&preferentialGbn=&rot3WorkYn=®DateEndtParam={yesterday}&pfMatterPreferential=&pageIndex={pageIndex}&termContractMmcnt=&careerFrom=&laborHrShortYn=#scrollLoc" -// -// private const val JOB_POSTING_COUNT_PER_PAGE = 50 -// -// private lateinit var driver: WebDriver -// -// private val postings = mutableListOf() -// -// private fun initializeDriver() { -// val service = ChromeDriverService.Builder() -// .usingDriverExecutable(File(System.getenv("CHROMEDRIVER_BIN"))) -// .build() -// -// val options = ChromeOptions().apply { -// addArguments("--headless") -// addArguments("--no-sandbox") -// addArguments("--disable-dev-shm-usage") -// addArguments("--disable-gpu") -// addArguments("window-size=1920x1080") -// addArguments("--disable-software-rasterizer") -// addArguments("--ignore-ssl-errors=yes") -// addArguments("--ignore-certificate-errors") -// -// setBinary(System.getenv("CHROME_BIN")) -// } -// -// driver = ChromeDriver(service, options) -// } -// -// fun run(): List? { -// try { -// initializeDriver() -// } catch (e: Exception) { -// logger.error { e.toString() } -// } -// -// logger.info { "=====초기화 완료, 크롤링 작업 시작" } -// -// val formatter = DateTimeFormatter.ofPattern("yyyyMMdd") -// val yesterday = LocalDate.now().minusDays(1).format(formatter) -// val crawlingUrl = CRAWLING_TARGET_URL_FORMAT -// .replace("{yesterday}", yesterday) -// .replace("{pageIndex}", "1") -// -// driver.get(crawlingUrl) -// -// logger.info { "=====크롤링 url: $crawlingUrl" } -// -// val wait = WebDriverWait(driver, Duration.ofSeconds(10)) -// wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[@id=\"mForm\"]/div[2]/div/div[1]/div[1]/span/span"))) -// -// val jobPostingCountText = -// driver.findElement(By.xpath("//*[@id=\"mForm\"]/div[2]/div/div[1]/div[1]/span/span")).text -// -// logger.info { "=====크롤링 대상 공고 수: $jobPostingCountText" } -// -// val jobPostingCount = Integer.parseInt(jobPostingCountText.replace(",", "")) -// -// if (jobPostingCount == 0) { -// driver.quit() -// logger.info { "=====크롤링 할 공고가 없어 미리 종료합니다." } -// return null -// } -// -// val pageCount = jobPostingCount / JOB_POSTING_COUNT_PER_PAGE -// -// logger.warn { "===== 크롤링 페이지 수 " + pageCount } -// -// for (i in 1..pageCount) { -// if (i >= 2) { -// val updatedCrawlingUrl = crawlingUrl -// .replace("{yesterday}", yesterday) -// .replace(Regex("pageIndex=\\d+"), "pageIndex=${i}") -// driver.get(updatedCrawlingUrl) -// } -// -// wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#list1"))) -// -// crawlPosts(1, JOB_POSTING_COUNT_PER_PAGE, postings) -// } -// -// val lastPageJobPostingCount = jobPostingCount % JOB_POSTING_COUNT_PER_PAGE -// -// if (lastPageJobPostingCount > 0) { -// val updateCrawlingUrl = crawlingUrl -// .replace("{yesterday}", yesterday) -// .replace(Regex("pageIndex=\\d+"), "pageIndex=${pageCount + 1}") -// driver.get(updateCrawlingUrl) -// -// wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#list1"))) -// -// crawlPosts(1, lastPageJobPostingCount, postings) -// } -// -// driver.quit() -// return postings -// } -// -// private fun handleAlertIfPresent() { -// try { -// val alert: Alert = driver.switchTo().alert() -// alert.accept() -// driver.navigate().back() -// } catch (e: NoAlertPresentException) { -// } -// } -// -// private fun crawlPosts( -// start: Int, -// end: Int, -// postings: MutableList, -// ) { -// for (i in start..end) { -// try { -// val originalWindow = driver.windowHandle -// -// val element = driver.findElement(By.xpath("//*[@id=\"list$i\"]/td[2]/a")) -// element.click() -// -// handleAlertIfPresent() -// -// val wait = WebDriverWait(driver, Duration.ofSeconds(5)) -// wait.until(ExpectedConditions.numberOfWindowsToBe(2)) -// -// val allWindows = driver.windowHandles -// -// for (windowHandle in allWindows) { -// if (windowHandle != originalWindow) { -// driver.switchTo().window(windowHandle) -// break -// } -// } -// -// val crawledJobPostingDto = CrawledJobPostingDto( -// title = getTitle(), -// content = getContent(), -// clientAddress = getClientAddress(), -// createdAt = getCreatedAt(), -// payInfo = getPayInfo(), -// workTime = getWorkTime(), -// workSchedule = getWorkSchedule(), -// applyDeadline = getApplyDeadline(), -// recruitmentProcess = getRecruitmentProcess(), -// applyMethod = getApplyMethod(), -// requiredDocument = getRequiredDocument(), -// centerName = getCenterName(), -// centerAddress = getCenterAddress(), -// directUrl = driver.currentUrl, -// ) -// -// postings.add(crawledJobPostingDto) -// -// driver.close() -// driver.switchTo().window(originalWindow) -// } catch (e: Exception) { -// handleAlertIfPresent() -// } -// } -// } -// -// private fun getClientAddress(): String { -// val xpaths = listOf( -// "//*[@id=\"contents\"]/section/div/div[3]/div[15]/div/table/tbody/tr[4]/td/p[2]", -// "//*[@id=\"contents\"]/section/div/div[3]/div[17]/div/table/tbody/tr[4]/td/p[2]", -// "//*[@id=\"contents\"]/section/div/div[3]/div[16]/div/table/tbody/tr[4]/td/p[2]" -// ) -// -// for (xpath in xpaths) { -// try { -// val address = driver.findElement(By.xpath(xpath)).text -// return address.replace("지도보기", "").trim() -// } catch (e: Exception) { -// // Ignore and try the next XPath -// } -// } -// -// throw NoSuchElementException("클라이언트 주소 크롤링 에러") -// } -// -// private fun getRequiredDocument(): String { -// return driver.findElement(By.xpath("//*[@id=\"contents\"]/section/div/div[3]/div[7]/table/tbody/tr/td[4]")).text -// } -// -// private fun getApplyMethod(): String { -// return driver.findElement(By.xpath("//*[@id=\"contents\"]/section/div/div[3]/div[7]/table/tbody/tr/td[3]")).text -// } -// -// private fun getRecruitmentProcess(): String { -// return driver.findElement(By.xpath("//*[@id=\"contents\"]/section/div/div[3]/div[7]/table/tbody/tr/td[2]")).text -// } -// -// private fun getApplyDeadline(): String { -// val applyDeadline = -// driver.findElement(By.xpath("//*[@id=\"contents\"]/section/div/div[3]/div[7]/table/tbody/tr/td[1]")).text -// -// return if (applyDeadline.contains("채용시까지")) { -// LocalDate.now().plusDays(15).format(DateTimeFormatter.ofPattern("yyyyMMdd")) -// } else { -// applyDeadline -// } -// } -// -// private fun getWorkSchedule(): String { -// return driver.findElement(By.xpath("//*[@id=\"contents\"]/section/div/div[3]/div[6]/table/tbody/tr/td[3]")).text -// } -// -// private fun getWorkTime(): String { -// return driver.findElement(By.xpath("//*[@id=\"contents\"]/section/div/div[3]/div[6]/table/tbody/tr/td[2]")).text -// .replace("(근무시간) ", "") -// .substringBefore("주 소정근로시간").trim() -// } -// -// private fun getPayInfo(): String { -// return driver.findElement(By.xpath("//*[@id=\"contents\"]/section/div/div[3]/div[2]/div[1]/div[1]/div[2]/div[2]/div/ul/li[2]/span")).text -// } -// -// private fun getCenterName(): String { -// return driver.findElement(By.xpath("//*[@id=\"contents\"]/section/div/div[3]/div[2]/div[1]/div[2]/div[2]/ul/li[1]/div")).text -// } -// -// private fun getCreatedAt(): String { -// val xpaths = listOf( -// "//*[@id=\"contents\"]/section/div/div[3]/div[16]/table/tbody/tr/td[1]", -// "//*[@id=\"contents\"]/section/div/div[3]/div[18]/table/tbody/tr/td[1]", -// "//*[@id=\"contents\"]/section/div/div[3]/div[17]/table/tbody/tr/td[1]" -// ) -// -// for (xpath in xpaths) { -// try { -// return driver.findElement(By.xpath(xpath)).text -// } catch (e: Exception) { -// // Ignore and try the next XPath -// } -// } -// -// throw NoSuchElementException("CreatedAt element not found using any of the provided XPaths") -// } -// -// private fun getCenterAddress(): String { -// val xpaths = listOf( -// "//*[@id=\"contents\"]/section/div/div[3]/div[15]/div/table/tbody/tr[1]/td", -// "//*[@id=\"contents\"]/section/div/div[3]/div[17]/div/table/tbody/tr[1]/td", -// "//*[@id=\"contents\"]/section/div/div[3]/div[16]/div/table/tbody/tr[4]/td/p[2]" -// ) -// -// for (xpath in xpaths) { -// try { -// val address = driver.findElement(By.xpath(xpath)).text -// return address.replace("지도보기", "").trim().replace(Regex("\\(\\d{5}\\)"), "").trim() -// } catch (e: Exception) { -// } -// } -// -// throw NoSuchElementException("Center address not found using any of the provided XPaths") -// } -// -// private fun getContent(): String { -// return driver.findElement(By.xpath("//*[@id=\"contents\"]/section/div/div[3]/div[3]/table/tbody/tr/td")).text -// } -// -// private fun getTitle(): String { -// val em = driver.findElement(By.cssSelector(".left")) -// return em.findElement(By.cssSelector(".tit-area .tit")).text -// } -// -//} - package com.swm.idle.batch.util import com.swm.idle.batch.common.dto.CrawledJobPostingDto @@ -358,7 +68,7 @@ object WorknetCrawler { logger.info { "=====초기화 완료, 크롤링 작업 시작" } val formatter = DateTimeFormatter.ofPattern("yyyyMMdd") - val yesterday = LocalDate.now().minusDays(1).format(formatter) + val yesterday = LocalDate.now().format(formatter) val crawlingUrl = CRAWLING_TARGET_URL_FORMAT .replace("{yesterday}", yesterday) .replace("{pageIndex}", "1") @@ -422,16 +132,6 @@ object WorknetCrawler { errorCountMap[method] = errorCountMap.getOrDefault(method, 0) + 1 } - private fun handleAlertIfPresent() { - try { - val alert: Alert = driver.switchTo().alert() - alert.accept() - driver.navigate().back() - } catch (e: NoAlertPresentException) { - logError("handleAlertIfPresent", e) - } - } - private fun crawlPosts( start: Int, end: Int, @@ -444,7 +144,10 @@ object WorknetCrawler { val element = driver.findElement(By.xpath("//*[@id=\"list$i\"]/td[2]/a")) element.click() - handleAlertIfPresent() + if (handleAlertIfPresent()) { + driver.navigate().back() + continue + } val wait = WebDriverWait(driver, Duration.ofSeconds(5)) wait.until(ExpectedConditions.numberOfWindowsToBe(2)) @@ -480,12 +183,21 @@ object WorknetCrawler { driver.close() driver.switchTo().window(originalWindow) } catch (e: Exception) { - logError("crawlPosts", e) - handleAlertIfPresent() + logError("=== 에러 원인은..", e) } } } + private fun handleAlertIfPresent(): Boolean { + return try { + val alert: Alert = driver.switchTo().alert() + alert.accept() // 알림창이 있을 경우 수락 + true // 알림창이 있었음을 표시 + } catch (e: NoAlertPresentException) { + false // 알림창이 없었음을 표시 + } + } + private fun getClientAddress(): String { val xpaths = listOf( "//*[@id=\"contents\"]/section/div/div[3]/div[15]/div/table/tbody/tr[4]/td/p[2]", @@ -644,9 +356,9 @@ object WorknetCrawler { // 에러 집계를 출력하는 메서드 추가 fun printErrorSummary() { - logger.info { "===== 에러 집계 =====" } + logger.error { "===== 에러 집계 =====" } errorCountMap.forEach { (method, count) -> - logger.info { "$method: $count errors" } + logger.error { "$method: $count errors" } } } } diff --git a/idle-domain/src/main/kotlin/com/swm/idle/domain/jobposting/repository/querydsl/CrawlingJobPostingSpatialQueryRepository.kt b/idle-domain/src/main/kotlin/com/swm/idle/domain/jobposting/repository/querydsl/CrawlingJobPostingSpatialQueryRepository.kt index 43b6f8fe..91f495b1 100644 --- a/idle-domain/src/main/kotlin/com/swm/idle/domain/jobposting/repository/querydsl/CrawlingJobPostingSpatialQueryRepository.kt +++ b/idle-domain/src/main/kotlin/com/swm/idle/domain/jobposting/repository/querydsl/CrawlingJobPostingSpatialQueryRepository.kt @@ -19,6 +19,7 @@ class CrawlingJobPostingSpatialQueryRepository( ) { fun findAllInRange( + carerId: UUID, location: Point, next: UUID?, limit: Long, @@ -41,8 +42,11 @@ class CrawlingJobPostingSpatialQueryRepository( return jpaQueryFactory .select(crawledJobPosting, jobPostingFavorite) .from(crawledJobPosting) - .leftJoin(jobPostingFavorite).fetchJoin() - .on(crawledJobPosting.id.eq(jobPostingFavorite.jobPostingId)) + .leftJoin(jobPostingFavorite) + .on( + crawledJobPosting.id.eq(jobPostingFavorite.jobPostingId) + .and(jobPostingFavorite.carerId.eq(carerId)) + ) .where(crawledJobPosting.id.`in`(crawledJobPostingIds)) .transform( groupBy(crawledJobPosting.id) @@ -61,7 +65,7 @@ class CrawlingJobPostingSpatialQueryRepository( location: Point, ): BooleanExpression { return Expressions.booleanTemplate( - "ST_Contains(ST_BUFFER({0}, 3000), {1})", + "ST_Contains(ST_BUFFER({0}, 5000), {1})", location, crawledJobPosting.location, ) diff --git a/idle-domain/src/main/kotlin/com/swm/idle/domain/jobposting/repository/querydsl/JobPostingSpatialQueryRepository.kt b/idle-domain/src/main/kotlin/com/swm/idle/domain/jobposting/repository/querydsl/JobPostingSpatialQueryRepository.kt index 085f224c..70d9ed8d 100644 --- a/idle-domain/src/main/kotlin/com/swm/idle/domain/jobposting/repository/querydsl/JobPostingSpatialQueryRepository.kt +++ b/idle-domain/src/main/kotlin/com/swm/idle/domain/jobposting/repository/querydsl/JobPostingSpatialQueryRepository.kt @@ -13,7 +13,6 @@ import com.swm.idle.domain.jobposting.entity.jpa.QJobPosting.jobPosting import com.swm.idle.domain.jobposting.entity.jpa.QJobPostingFavorite.jobPostingFavorite import com.swm.idle.domain.jobposting.entity.jpa.QJobPostingWeekday.jobPostingWeekday import com.swm.idle.domain.jobposting.enums.JobPostingStatus -import com.swm.idle.domain.user.carer.entity.jpa.Carer import org.locationtech.jts.geom.Point import org.springframework.stereotype.Repository import java.util.* @@ -24,7 +23,7 @@ class JobPostingSpatialQueryRepository( ) { fun findAllWithWeekdaysInRange( - carer: Carer, + carerId: UUID, location: Point, next: UUID?, limit: Long, @@ -58,7 +57,7 @@ class JobPostingSpatialQueryRepository( .leftJoin(applys) .on( jobPosting.id.eq(applys.jobPostingId) - .and(applys.carerId.eq(carer.id)) + .and(applys.carerId.eq(carerId)) ) .leftJoin(jobPostingFavorite) .on(jobPosting.id.eq(jobPostingFavorite.jobPostingId)) @@ -86,7 +85,7 @@ class JobPostingSpatialQueryRepository( location: Point, ): BooleanExpression { return Expressions.booleanTemplate( - "ST_Contains(ST_BUFFER({0}, 3000), {1})", + "ST_Contains(ST_BUFFER({0}, 5000), {1})", location, jobPosting.location, ) diff --git a/idle-domain/src/main/kotlin/com/swm/idle/domain/user/center/repository/jpa/CenterManagerJpaRepository.kt b/idle-domain/src/main/kotlin/com/swm/idle/domain/user/center/repository/jpa/CenterManagerJpaRepository.kt index 76fc4261..db066d23 100644 --- a/idle-domain/src/main/kotlin/com/swm/idle/domain/user/center/repository/jpa/CenterManagerJpaRepository.kt +++ b/idle-domain/src/main/kotlin/com/swm/idle/domain/user/center/repository/jpa/CenterManagerJpaRepository.kt @@ -2,6 +2,7 @@ package com.swm.idle.domain.user.center.repository.jpa import com.swm.idle.domain.user.center.entity.jpa.CenterManager import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query import org.springframework.stereotype.Repository import java.util.* @@ -16,4 +17,15 @@ interface CenterManagerJpaRepository : JpaRepository { fun findAllByCenterBusinessRegistrationNumber(centerBusinessRegistrationNumber: String): List? + @Query( + value = + """ + SELECT * + FROM center_manager + WHERE center_manager.status = 'PENDING' + """, + nativeQuery = true + ) + fun findAllByStatusPending(): List? + } diff --git a/idle-presentation/src/main/kotlin/com/swm/idle/presentation/auth/center/api/CenterAuthApi.kt b/idle-presentation/src/main/kotlin/com/swm/idle/presentation/auth/center/api/CenterAuthApi.kt index cc483d83..658dcdf4 100644 --- a/idle-presentation/src/main/kotlin/com/swm/idle/presentation/auth/center/api/CenterAuthApi.kt +++ b/idle-presentation/src/main/kotlin/com/swm/idle/presentation/auth/center/api/CenterAuthApi.kt @@ -3,12 +3,14 @@ package com.swm.idle.presentation.auth.center.api import com.swm.idle.presentation.common.exception.ErrorResponse import com.swm.idle.presentation.common.security.annotation.Secured import com.swm.idle.support.transfer.auth.center.CenterLoginRequest +import com.swm.idle.support.transfer.auth.center.CenterManagerForPendingResponse import com.swm.idle.support.transfer.auth.center.ChangePasswordRequest import com.swm.idle.support.transfer.auth.center.JoinRequest import com.swm.idle.support.transfer.auth.center.ValidateBusinessRegistrationNumberResponse import com.swm.idle.support.transfer.auth.center.WithdrawRequest import com.swm.idle.support.transfer.auth.common.LoginResponse import com.swm.idle.support.transfer.user.center.JoinStatusInfoResponse +import io.swagger.v3.oas.annotations.Hidden import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.Schema @@ -47,6 +49,12 @@ interface CenterAuthApi { @ResponseStatus(HttpStatus.NO_CONTENT) fun requestCenterManagerVerification() + @Hidden + @Operation(summary = "센터 관리자 인증 대기 목록 조회 API") + @GetMapping("/join/requests") + @ResponseStatus(HttpStatus.OK) + fun getCenterManagerForPending(): CenterManagerForPendingResponse + @Operation(summary = "사업자 등록번호 인증 API") @GetMapping("/authentication/{business-registration-number}") @ResponseStatus(HttpStatus.OK) diff --git a/idle-presentation/src/main/kotlin/com/swm/idle/presentation/auth/center/controller/CenterAuthController.kt b/idle-presentation/src/main/kotlin/com/swm/idle/presentation/auth/center/controller/CenterAuthController.kt index 9b59cb1d..00d7c40e 100644 --- a/idle-presentation/src/main/kotlin/com/swm/idle/presentation/auth/center/controller/CenterAuthController.kt +++ b/idle-presentation/src/main/kotlin/com/swm/idle/presentation/auth/center/controller/CenterAuthController.kt @@ -7,6 +7,7 @@ import com.swm.idle.domain.user.center.vo.Password import com.swm.idle.domain.user.common.vo.PhoneNumber import com.swm.idle.presentation.auth.center.api.CenterAuthApi import com.swm.idle.support.transfer.auth.center.CenterLoginRequest +import com.swm.idle.support.transfer.auth.center.CenterManagerForPendingResponse import com.swm.idle.support.transfer.auth.center.ChangePasswordRequest import com.swm.idle.support.transfer.auth.center.JoinRequest import com.swm.idle.support.transfer.auth.center.ValidateBusinessRegistrationNumberResponse @@ -38,6 +39,10 @@ class CenterAuthController( return centerAuthFacadeService.requestCenterManagerVerification() } + override fun getCenterManagerForPending(): CenterManagerForPendingResponse { + return centerAuthFacadeService.getCenterManagerForPending() + } + override fun validateBusinessRegistrationNumber(businessRegistrationNumber: String): ValidateBusinessRegistrationNumberResponse { return centerAuthFacadeService.validateCompany( businessRegistrationNumber = BusinessRegistrationNumber(businessRegistrationNumber), diff --git a/idle-presentation/src/main/resources/static/.well-known/assetlinks.json b/idle-presentation/src/main/resources/static/.well-known/assetlinks.json new file mode 100644 index 00000000..5b52c0e2 --- /dev/null +++ b/idle-presentation/src/main/resources/static/.well-known/assetlinks.json @@ -0,0 +1,14 @@ +[ + { + "relation": [ + "delegate_permission/common.handle_all_urls" + ], + "target": { + "namespace": "android_app", + "package_name": "com.idle.care", + "sha256_cert_fingerprints": [ + "0F:82:C2:F8:FE:04:0F:B0:61:7E:8A:68:DE:D8:35:81:15:D1:E5:6D:30:78:1C:1A:0E:83:F3:EB:5E:2F:8E:68" + ] + } + } +] diff --git a/idle-support/transfer/src/main/kotlin/com/swm/idle/support/transfer/auth/center/CenterManagerForPendingResponse.kt b/idle-support/transfer/src/main/kotlin/com/swm/idle/support/transfer/auth/center/CenterManagerForPendingResponse.kt new file mode 100644 index 00000000..5e126549 --- /dev/null +++ b/idle-support/transfer/src/main/kotlin/com/swm/idle/support/transfer/auth/center/CenterManagerForPendingResponse.kt @@ -0,0 +1,56 @@ +package com.swm.idle.support.transfer.auth.center + +import com.swm.idle.domain.user.center.entity.jpa.CenterManager +import io.swagger.v3.oas.annotations.media.Schema +import java.util.* + +@Schema( + name = "CenterManagerForPendingResponse", + description = "센터 관리자 인증 대기 목록 조회 응답" +) +data class CenterManagerForPendingResponse( + val pendingCenterManagers: List?, +) { + + data class PendingCenterManagerDto( + @Schema(description = "센터 관리자 ID") + val id: UUID, + + @Schema(description = "센터 관리자 로그인 ID") + val identifier: String, + + @Schema(description = "센터 관리자 성명") + val managerName: String, + + @Schema(description = "센터 사업자 등록 번호") + val centerBusinessRegistrationNumber: String, + + @Schema(description = "센터 관리자 개인 연락처") + val phoneNumber: String, + ) { + + companion object { + + fun of(centerManager: CenterManager): PendingCenterManagerDto { + return PendingCenterManagerDto( + id = centerManager.id, + identifier = centerManager.identifier, + managerName = centerManager.name, + centerBusinessRegistrationNumber = centerManager.centerBusinessRegistrationNumber, + phoneNumber = centerManager.phoneNumber + ) + } + + } + + } + + companion object { + + fun of(pendingCenterManagerDtos: List?): CenterManagerForPendingResponse { + return CenterManagerForPendingResponse(pendingCenterManagerDtos) + } + + } + +}