From f5ee7d402b37d12039a1d9363a628fb8872fd1cd Mon Sep 17 00:00:00 2001 From: Wonjun You <59856002+wonjunYou@users.noreply.github.com> Date: Tue, 5 Nov 2024 15:17:40 +0900 Subject: [PATCH] hotfix/v1.1.0 (#230) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [IDLE-000] Production CI 스크립트 작성 * [IDLE-000] 센터 공고 수정 API 내 접수 방법 null 비허용 * [IDLE-000] 공고 지원자 조회 시, 삭제된 유저는 조회되지 않도록 수정 * [IDLE-363] 센터 관리자 전화 인증 요청 API * [IDLE-363] 개발 환경 ddl-auto 옵션 임시로 create 옵션으로 변경 * [IDLE-365] 공고 크롤러 selenium 로직 수정 및 로컬 동작 확인 * [IDLE-365] 테스트를 위한 스케줄러 기준 시각 변경 * [IDLE-365] batch job enable 옵션 비활성화 * [IDLE-365] ddl-auto update로 변경 * [IDLE-365] 크롤링 공고 필드 null 비허용 * [IDLE-365] 스케줄러 시간 02시로 설정 * [IDLE-366] spring batch selenium 크롤링을 위한 빌드 스크립트 수정 * [IDLE-366] worknet 사이트가 고용 24 사이트로 통합됨에 따라, 크롤링 스크립트 수정 * [IDLE-366] 크롤러 동작 스케줄링 시간 변경 * [IDLE-366] 스프링 초기 실행 시, spring batch 자동 실행 방지 옵션 추가 * [IDLE-366] spring batch 5 버전에서 업데이트 된 변경사항 적용 및 별도의 JobLauncher 구현 * [IDLE-366] 불필요 의존성 및 옵션 제거 * [IDLE-366] 크롤링 조회 API 내 entity status 필드 추가 및 쿼리 수정 * [IDLE-358] 운영 환경 CD 구축 및 운영 환경 profile 설정 추가 * [IDLE-358] 운영 환경 docker run 실행 시 예외 처리 * [IDLE-000] 크롤링 전체 조회 DTO 생성자 추가 * [IDLE-000] 공고 전체 조회 fetchJoin() 중복 이슈 해결을 위한 subquery 분리 * [IDLE-000] AI 코드리뷰 coderabbit 도입 * [IDLE-000] 크롤링 공고 반경범위 조회 필터를 위한 where절 추가 * [IDLE-000] TimeZone 설정이 적용되지 않는 문제 해결 * [IDLE-000] TimeZone 지정 및 @EnableScheduling 설정 * [IDLE-000] TimeZone 설정 제거 * [IDLE-000] 공고 전체 조회 쿼리 롤백 * [IDLE-000] 기존 공고 내 location을 기반으로 위.경도 값을 decoding하도록 변경 * [IDLE-000] 배포 전 최종 QA * [IDLE-000] 크롤링 공고 생성일자 필드 type 변경(timestamp -> date) * [IDLE-000] Redis 비밀번호 설정 추가 (#171) * [IDLE-000] Redis 비밀번호 설정 추가 * [IDLE-000] yaml 파일에 password 필드 추가 * [IDLE-000] redis local default password 설정 * [IDLE-000] compose 파일 내, 비밀번호 지정 command 설정 * [IDLE-000] Redis 볼륨 설정 * [IDLE-000] ci triggering branch 임시 변경 * [IDLE-000] ci triggering branch 롤백 * [IDLE-000] 테스트 심사 통과를 위한 전화번호 검증 로직 추가 * [IDLE-000] 테스트 심사 통과를 위한 전화번호 검증 로직 추가 * [IDLE-389] 센터 인증 요청 이벤트 발생 시, 디스코드 웹훅 알림을 전송하는 로직 작성 * [IDLE-389] 사업자 등록번호 client properties 클래스명 변경 * [IDLE-389] 코드 리뷰 반영 * [IDLE-000] 트랜잭션 전파 레벨 변경(REQUIRED -> REQUIRES_NEW) * [IDLE-396] FCM 모듈 추가 및 firebase 의존성 설정 * readme 제목 수정 * readme 제목 수정 * [IDLE-399] FCM Device Token 관리 API * [IDLE-399] 알림 도메인 설계 * [IDLE-000] fcm service 설정값 주입을 위한 디렉토리 구조 변경 * [IDLE-000] fcm service 설정값 주입을 위한 디렉토리 구조 변경 * [IDLE-400] 채용 공고 지원자 발생 시, 센터 관리자에게 알림을 발송한다. * [IDLE-400] fcm 모듈 설정 추가 * [IDLE-400] 공고 지원자 발생 시, 모든 센터 관리자들에게 다중 알림을 발송한다. * [IDLE-415] 알림 조회 처리 API * [IDLE-417] 읽지 않은 알림 수 집계 API * [IDLE-418] 알림 목록 조회 API * [IDLE-418] 피드백 반영 * [IDLE-423] soft-delete가 적용된 즐겨찾기 entity에서, 즐겨찾기 해제 후 다시 설정하는 경우 발생하는 버그를 해결한다. * [IDLE-424] 요양 보호사 공고 전체 조회 시, 삭제된 공고가 함께 보이는 문제 해결 * [IDLE-400] 채용 공고 지원자 발생 시, 센터 관리자에게 알림을 발송한다. (#183) * [IDLE-400] 채용 공고 지원자 발생 시, 센터 관리자에게 알림을 발송한다. * [IDLE-400] fcm 모듈 설정 추가 * [IDLE-400] 공고 지원자 발생 시, 모든 센터 관리자들에게 다중 알림을 발송한다. * [IDLE-400] 채용 공고 지원자 발생 시, 센터 관리자에게 알림을 발송한다. * [IDLE-400] fcm 모듈 설정 추가 * [IDLE-400] 공고 지원자 발생 시, 모든 센터 관리자들에게 다중 알림을 발송한다. * [IDLE-415] 알림 조회 처리 API * [IDLE-417] 읽지 않은 알림 수 집계 API * [IDLE-418] 알림 목록 조회 API * [IDLE-418] 피드백 반영 * [IDLE-423] soft-delete가 적용된 즐겨찾기 entity에서, 즐겨찾기 해제 후 다시 설정하는 경우 발생하는 버그를 해결한다. * [IDLE-424] 요양 보호사 공고 전체 조회 시, 삭제된 공고가 함께 보이는 문제 해결 * [IDLE-400] 알림 명세 변경 * [IDLE-400] fcm 설정 파일 디렉토리 path 변경 * [IDLE-400] ddl 옵션 변경 * [IDLE-400] ci/cd 옵션 변경 * [IDLE-000] ci triggering branch 복구 * [IDLE-000] develop 환경에서 fcm service 설정 파일 path 수정 * [IDLE-000] fcm service json 파일명 변경 * [IDLE-000] firebase service key 설정 경로 체크를 위해, cd 스크립트를 수정합니다. * Update README.md * [IDLE-000] fcm service key 경로를 class path 경로로 수정 시도 * [IDLE-000] ci triggering branch 임시 변경 * [IDLE-000] firebaseApp 초기화 임시 비활성화 * [IDLE-000] firebaseApp 초기화 임시 비활성화 * [IDLE-000] firebaseApp 초기화 임시 비활성화 * [IDLE-000] file path 앞에 ./ 제외 * [IDLE-000] 절대 경로로 변경 시도 * [IDLE-000] fcm service key 생성 path 수정 * [IDLE-000] fcm service key json file 생성 스크립트 작성 * [IDLE-000] ci triggering branch develop으로 롤백 * [IDLE-000] 불필요 스크립트 제거 * [IDLE-000] firebase config의 현재 경로를 출력하도록 print문 추가 (#197) * [IDLE-000] firebase config의 현재 경로를 출력하도록 print문 추가 * [IDLE-000] ci triggering branch 수정 * [IDLE-000] ci triggering branch 수정 * [IDLE-000] firebase app 초기화 로직 주석 처리 * [IDLE-000] firebase app 초기화 로직 주석 처리 * [IDLE-000] firebase app 초기화 로직 주석 처리 * [IDLE-000] file 대신 string으로 주입받아 초기화하는 방식으로 전환 * [IDLE-000] 일반 string 대신 base64 인코딩 된 문자열을 주입하도록 처리 * [IDLE-000] 일반 string 주입으로 rollback * [IDLE-000] json string log 추가 * [IDLE-000] base64 문자열로 재 변경 * [IDLE-000] firebase config의 현재 경로를 출력하도록 print문 추가 * [IDLE-429] DB 형상관리를 위한 Flyway 적용 * [IDLE-429] Flyway latest version으로 설정 * [IDLE-429] 피드백 반영 * [IDLE-000] firebase config의 현재 경로를 출력하도록 print문 추가 * [IDLE-000] 알림 조회 처리 로직에 @Transactional 추가 * [IDLE-000] 알림 조회 시, 생성 시각 기준이 아닌 uuid v7 id 기준으로 내림차순 정렬하도록 변경 * [IDLE-000] CI 트리거 브랜치 복구 * [IDLE-454] 테스트를 위한 크롤링 수행 시각 변경 및 로깅 추가 * [IDLE-000] 공고 범위 검색 내 중복 데이터 발생 방지 * [IDLE-000] ci 트리거 브랜치 변경 * [IDLE-000] ci 트리거 브랜치 롤백 * [IDLE-000] monitoring 모듈 추가 및 actuator, prometheus 의존성 추가 * [IDLE-456] monitoring.yml 작성 * [IDLE-456] monitoring profile 추가 * [IDLE-456] actuator dependency group name 수정 * [IDLE-000] 크롤링 주기 하루 2회로 변경 * [IDLE-000] 불필요 로그 제거 * [IDLE-000] 인증번호 SMS 내용 수정 * [IDLE-000] classPath 하위 yaml 파일 확장자 모두 .yml로 통일 * [IDLE-000] 즐겨찾기 facade service에 트랜잭션 추가 (#206) * [IDLE-000] firebase config의 현재 경로를 출력하도록 print문 추가 * [IDLE-000] facade service에 transaction 추가 * [IDLE-461] 유저가 다중 디바이스에서 알림을 받을 수 있도록 개선한다. (#207) * [IDLE-000] firebase config의 현재 경로를 출력하도록 print문 추가 * [IDLE-461] 한 유저가 다중 디바이스 설정이 가능하도록 한다. * [IDLE-000] firebase config의 현재 경로를 출력하도록 print문 추가 * [IDLE-000] presentation module의 gradle 파일에 monitoring 모듈 dependency 추가 * [IDLE-000] deviceToken 서비스에서 트랜잭션 어노테이션 추가 * [IDLE-000] batch 테스트를 위해 30분마다 동작하도록 변경 * [IDLE-475] 채팅, 채팅방 도메인 설계 * [IDLE-475] 채팅 메세지 최소, 최대 길이 제한 설정 * [IDLE-000] Batch 메타데이터 테이블 스크립트 변경 및 크롤링 수행 주기 설정 * [IDLE-000] 운영 환경 CD 스크립트에서 불필요한 step 제거 * [IDLE-000] 도텐브 파일 공백 제거 스크립트 작성, 크롤링 대상일자 전날 등록된 공고로 변경 * [IDLE-000] 크롤링 기준 시각 15시로 임시 변경 * [IDLE-000] cd env 파일 생성 스크립트 변경 * [IDLE-492] 동일 유저가 여러 개의 디바이스를 사용 시, 알림이 중복해서 누적되는 현상 * [IDLE-493] flyway 스크립트 오탈자 수정 * [IDLE-493] flyway 스크립트 오탈자 수정 * [IDLE-494] 요양 보호사 및 센터 프로필에서 긴 텍스트를 입력 가능한 항목을 TEXT 컬럼으로 지정한다. * [IDLE-495] 요양 보호사는 마감된 공고에 지원이 불가능하다. * [IDLE-495] 공고 마감 처리 메서드명 변경 complete -> completed * [IDLE-496] 스프링 프로파일 지정을 위한 환경변수 주입 * [IDLE-496] 로그 일부 수정 * hotfix/v1.1.0 --- .github/workflows/prod-server-deployer.yaml | 31 ++++++++++--------- .../applys/facade/CarerApplyFacadeService.kt | 26 +++++++++------- .../jobposting/domain/JobPostingService.kt | 4 +-- .../facade/CenterJobPostingFacadeService.kt | 4 +-- .../common/scheduler/CrawlingJobScheduler.kt | 2 +- .../batch/job/CrawlingJobPostingTasklet.kt | 2 +- .../com/swm/idle/batch/util/WorknetCrawler.kt | 16 +++++----- .../domain/applys/exception/ApplyException.kt | 3 ++ .../jobposting/entity/jpa/JobPosting.kt | 6 +++- ...e_notification_add_column_device_token.sql | 4 +++ ...ndex_receiver_id_in_notification_table.sql | 3 ++ ...__alter_table_carer_modify_column_type.sql | 5 +++ ..._alter_table_center_modify_column_type.sql | 4 +++ .../controller/CenterJobPostingController.kt | 2 +- 14 files changed, 69 insertions(+), 43 deletions(-) create mode 100644 idle-domain/src/main/resources/db/migration/V4__alter_table_notification_add_column_device_token.sql create mode 100644 idle-domain/src/main/resources/db/migration/V5__create_index_receiver_id_in_notification_table.sql create mode 100644 idle-domain/src/main/resources/db/migration/V6__alter_table_carer_modify_column_type.sql create mode 100644 idle-domain/src/main/resources/db/migration/V7__alter_table_center_modify_column_type.sql diff --git a/.github/workflows/prod-server-deployer.yaml b/.github/workflows/prod-server-deployer.yaml index 5575e115..c73e4822 100644 --- a/.github/workflows/prod-server-deployer.yaml +++ b/.github/workflows/prod-server-deployer.yaml @@ -9,18 +9,18 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 -# - name: Send discord notification (production server deploy start) -# uses: appleboy/discord-action@master -# with: -# webhook_id: ${{ secrets.SERVER_DEPLOY_DISCORD_WEBHOOK_ID }} -# webhook_token: ${{ secrets.SERVER_DEPLOY_DISCORD_WEBHOOK_TOKEN }} -# message: | -# > **🌈 Server Deployment Start (Production)** -# > -# > 🛢️ Repository : ${{ github.repository }} -# > 🎋 Branch : ${{ github.ref }} -# > 🔁 Run Attempt : ${{ github.run_attempt }} -# > 🤗 Actor : ${{ github.triggering_actor }} + - name: Send discord notification (production server deploy start) + uses: appleboy/discord-action@master + with: + webhook_id: ${{ secrets.SERVER_DEPLOY_DISCORD_WEBHOOK_ID }} + webhook_token: ${{ secrets.SERVER_DEPLOY_DISCORD_WEBHOOK_TOKEN }} + message: | + > **🌈 Server Deployment Start (Production)** + > + > 🛢️ Repository : ${{ github.repository }} + > 🎋 Branch : ${{ github.ref }} + > 🔁 Run Attempt : ${{ github.run_attempt }} + > 🤗 Actor : ${{ github.triggering_actor }} - name: Get Github Actions IP Addresses id: publicip @@ -88,13 +88,14 @@ jobs: key: ${{ secrets.INSTANCE_PEM_KEY }} script: | sudo docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} - sudo docker pull public.ecr.aws/f5q3r6m5/idle-prod-ecr:latest + sudo docker pull public.ecr.aws/f5q3r6m5/idle-prod-ecr:$IMAGE_TAG if [ $(sudo docker ps -q -f name=caremeet_server_prod) ]; then sudo docker stop caremeet_server_prod sudo docker rm caremeet_server_prod fi - sudo docker run --name caremeet_server_prod --env INSTANCE_PEM_KEY="${{ secrets.INSTANCE_PEM_KEY }}" \ - --env-file ./app/docker/.env -d -p 8080:8080 public.ecr.aws/f5q3r6m5/idle-prod-ecr:latest + sudo docker run --name caremeet_server_prod --env-file ./app/docker/.env \ + -e SPRING_PROFILES_ACTIVE=prod \ + -d -p 8080:8080 public.ecr.aws/f5q3r6m5/idle-prod-ecr:$IMAGE_TAG - name: Remove GitHub Actions IP run: | diff --git a/idle-application/src/main/kotlin/com/swm/idle/application/applys/facade/CarerApplyFacadeService.kt b/idle-application/src/main/kotlin/com/swm/idle/application/applys/facade/CarerApplyFacadeService.kt index fc2b120a..d8fc80f0 100644 --- a/idle-application/src/main/kotlin/com/swm/idle/application/applys/facade/CarerApplyFacadeService.kt +++ b/idle-application/src/main/kotlin/com/swm/idle/application/applys/facade/CarerApplyFacadeService.kt @@ -51,6 +51,10 @@ class CarerApplyFacadeService( throw ApplyException.AlreadyApplied() } + if (jobPosting.isCompleted()) { + throw ApplyException.JobPostingCompleted() + } + val centerManagers = centerService.getById(jobPosting.centerId).let { centerManagerService.findAllByCenterBusinessRegistrationNumber( BusinessRegistrationNumber(it.businessRegistrationNumber) @@ -62,20 +66,20 @@ class CarerApplyFacadeService( centerManagers?.forEach { centerManager -> val deviceTokens = deviceTokenService.findAllByUserId(centerManager.id) - deviceTokens?.forEach { deviceToken -> - val notificationInfo = CarerApplyNotificationInfo( - title = "${carer.name} 님이 공고에 지원하였습니다.", - body = createBodyMessage(jobPosting), - receiverId = centerManager.id, - notificationType = NotificationType.APPLICANT, - imageUrl = carer.profileImageUrl, - notificationDetails = mapOf( - "jobPostingId" to jobPostingId, - ) + val notificationInfo = CarerApplyNotificationInfo( + title = "${carer.name} 님이 공고에 지원하였습니다.", + body = createBodyMessage(jobPosting), + receiverId = centerManager.id, + notificationType = NotificationType.APPLICANT, + imageUrl = carer.profileImageUrl, + notificationDetails = mapOf( + "jobPostingId" to jobPostingId, ) + ) - val notification = notificationService.create(notificationInfo) + val notification = notificationService.create(notificationInfo) + deviceTokens?.forEach { deviceToken -> ApplyEvent.createApplyEvent( deviceToken = deviceToken, notificationId = notification.id, 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 a8aefb31..2bf2c274 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 @@ -190,8 +190,8 @@ class JobPostingService( jobPosting.delete() } - fun updateToComplete(jobPosting: JobPosting) { - jobPosting.updateToComplete() + fun updateToCompleted(jobPosting: JobPosting) { + jobPosting.updateToCompleted() } fun findAllByCarerLocationInRange( diff --git a/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/facade/CenterJobPostingFacadeService.kt b/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/facade/CenterJobPostingFacadeService.kt index 2b032e7a..79ac4119 100644 --- a/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/facade/CenterJobPostingFacadeService.kt +++ b/idle-application/src/main/kotlin/com/swm/idle/application/jobposting/facade/CenterJobPostingFacadeService.kt @@ -193,9 +193,9 @@ class CenterJobPostingFacadeService( } @Transactional - fun updateToComplete(jobPostingId: UUID) { + fun updateToCompleted(jobPostingId: UUID) { jobPostingService.getById(jobPostingId).let { - jobPostingService.updateToComplete(it) + jobPostingService.updateToCompleted(it) } } 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 ba7ba550..48846fa1 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 00 01 * * *") + @Scheduled(cron = "0 30 15 * * *") fun scheduleJob() { val jobParameters: JobParameters = JobParametersBuilder() .addLong("timestamp", System.currentTimeMillis()) diff --git a/idle-batch/src/main/kotlin/com/swm/idle/batch/job/CrawlingJobPostingTasklet.kt b/idle-batch/src/main/kotlin/com/swm/idle/batch/job/CrawlingJobPostingTasklet.kt index 84f1c67f..3cc54dbb 100644 --- a/idle-batch/src/main/kotlin/com/swm/idle/batch/job/CrawlingJobPostingTasklet.kt +++ b/idle-batch/src/main/kotlin/com/swm/idle/batch/job/CrawlingJobPostingTasklet.kt @@ -62,7 +62,7 @@ class CrawlingJobPostingTasklet( directUrl = crawledJobPosting.directUrl, ).toDomain(clientLocation) }.let { - logger.warn { "크롤링된 data 크기 : ${it.size}" } + println("크롤링된 data 크기 : ${it.size}") crawlingJobPostingService.saveAll(it) } 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 a2980781..6dbaa6bf 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 @@ -21,7 +21,7 @@ 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={today}&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={today}&pfMatterPreferential=&pageIndex={pageIndex}&termContractMmcnt=&careerFrom=&laborHrShortYn=#scrollLoc" + "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 @@ -60,9 +60,9 @@ object WorknetCrawler { logger.info { "=====초기화 완료, 크롤링 작업 시작" } val formatter = DateTimeFormatter.ofPattern("yyyyMMdd") - val today = LocalDate.now().minusDays(1).format(formatter) + val yesterday = LocalDate.now().minusDays(1).format(formatter) val crawlingUrl = CRAWLING_TARGET_URL_FORMAT - .replace("{today}", today) + .replace("{yesterday}", yesterday) .replace("{pageIndex}", "1") driver.get(crawlingUrl) @@ -86,12 +86,13 @@ object WorknetCrawler { } val pageCount = jobPostingCount / JOB_POSTING_COUNT_PER_PAGE - logger.warn { "=====크롤링 페이지 수:" + pageCount } + + logger.warn { "===== 크롤링 페이지 수 " + pageCount } for (i in 1..pageCount) { if (i >= 2) { val updatedCrawlingUrl = crawlingUrl - .replace("{today}", today) + .replace("{yesterday}", yesterday) .replace(Regex("pageIndex=\\d+"), "pageIndex=${i}") driver.get(updatedCrawlingUrl) } @@ -105,7 +106,7 @@ object WorknetCrawler { if (lastPageJobPostingCount > 0) { val updateCrawlingUrl = crawlingUrl - .replace("{today}", today) + .replace("{yesterday}", yesterday) .replace(Regex("pageIndex=\\d+"), "pageIndex=${pageCount + 1}") driver.get(updateCrawlingUrl) @@ -199,7 +200,6 @@ object WorknetCrawler { 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 } @@ -259,7 +259,6 @@ object WorknetCrawler { 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", @@ -278,7 +277,6 @@ object WorknetCrawler { 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 } diff --git a/idle-domain/src/main/kotlin/com/swm/idle/domain/applys/exception/ApplyException.kt b/idle-domain/src/main/kotlin/com/swm/idle/domain/applys/exception/ApplyException.kt index d7048fe0..f4119884 100644 --- a/idle-domain/src/main/kotlin/com/swm/idle/domain/applys/exception/ApplyException.kt +++ b/idle-domain/src/main/kotlin/com/swm/idle/domain/applys/exception/ApplyException.kt @@ -10,6 +10,9 @@ sealed class ApplyException( class AlreadyApplied(message: String = "이미 지원한 이력이 있는 공고입니다.") : ApplyException(codeNumber = 1, message = message) + class JobPostingCompleted(message: String = "마감된 공고에 지원할 수 없습니다.") : + ApplyException(codeNumber = 2, message = message) + companion object { const val CODE_PREFIX = "APPLY" diff --git a/idle-domain/src/main/kotlin/com/swm/idle/domain/jobposting/entity/jpa/JobPosting.kt b/idle-domain/src/main/kotlin/com/swm/idle/domain/jobposting/entity/jpa/JobPosting.kt index eb27bfa8..e10cac28 100644 --- a/idle-domain/src/main/kotlin/com/swm/idle/domain/jobposting/entity/jpa/JobPosting.kt +++ b/idle-domain/src/main/kotlin/com/swm/idle/domain/jobposting/entity/jpa/JobPosting.kt @@ -225,8 +225,12 @@ class JobPosting( this.applyDeadlineType = applyDeadlineType ?: this.applyDeadlineType } - fun updateToComplete() { + fun updateToCompleted() { this.jobPostingStatus = JobPostingStatus.COMPLETED } + fun isCompleted(): Boolean { + return this.jobPostingStatus == JobPostingStatus.COMPLETED + } + } diff --git a/idle-domain/src/main/resources/db/migration/V4__alter_table_notification_add_column_device_token.sql b/idle-domain/src/main/resources/db/migration/V4__alter_table_notification_add_column_device_token.sql new file mode 100644 index 00000000..3ba2e265 --- /dev/null +++ b/idle-domain/src/main/resources/db/migration/V4__alter_table_notification_add_column_device_token.sql @@ -0,0 +1,4 @@ +-- V4__alter_table_notification_add_column_device_token.sql + +-- Add secondary index on deviceToken and userId columns +CREATE INDEX idx_user_id ON notification(user_id); diff --git a/idle-domain/src/main/resources/db/migration/V5__create_index_receiver_id_in_notification_table.sql b/idle-domain/src/main/resources/db/migration/V5__create_index_receiver_id_in_notification_table.sql new file mode 100644 index 00000000..e67edf0c --- /dev/null +++ b/idle-domain/src/main/resources/db/migration/V5__create_index_receiver_id_in_notification_table.sql @@ -0,0 +1,3 @@ +-- V5__create_index_receiver_id_in_notification_table.sql + +CREATE INDEX idx_receiver_id ON notification(receiver_id); diff --git a/idle-domain/src/main/resources/db/migration/V6__alter_table_carer_modify_column_type.sql b/idle-domain/src/main/resources/db/migration/V6__alter_table_carer_modify_column_type.sql new file mode 100644 index 00000000..09ffddd1 --- /dev/null +++ b/idle-domain/src/main/resources/db/migration/V6__alter_table_carer_modify_column_type.sql @@ -0,0 +1,5 @@ +-- V6__alter_table_carer_modify_column_type.sql + +ALTER TABLE carer +MODIFY COLUMN introduce TEXT, +MODIFY COLUMN speciality TEXT diff --git a/idle-domain/src/main/resources/db/migration/V7__alter_table_center_modify_column_type.sql b/idle-domain/src/main/resources/db/migration/V7__alter_table_center_modify_column_type.sql new file mode 100644 index 00000000..7bec374c --- /dev/null +++ b/idle-domain/src/main/resources/db/migration/V7__alter_table_center_modify_column_type.sql @@ -0,0 +1,4 @@ +-- V7__alter_table_center_modify_column_type.sql + +ALTER TABLE center +MODIFY COLUMN introduce TEXT; diff --git a/idle-presentation/src/main/kotlin/com/swm/idle/presentation/jobposting/controller/CenterJobPostingController.kt b/idle-presentation/src/main/kotlin/com/swm/idle/presentation/jobposting/controller/CenterJobPostingController.kt index 143b7078..0faaf68f 100644 --- a/idle-presentation/src/main/kotlin/com/swm/idle/presentation/jobposting/controller/CenterJobPostingController.kt +++ b/idle-presentation/src/main/kotlin/com/swm/idle/presentation/jobposting/controller/CenterJobPostingController.kt @@ -35,7 +35,7 @@ class CenterJobPostingController( } override fun completeJobPosting(jobPostingId: UUID) { - centerJobPostingFacadeService.updateToComplete(jobPostingId) + centerJobPostingFacadeService.updateToCompleted(jobPostingId) } override fun getJobPostingDetail(jobPostingId: UUID): CenterJobPostingResponse {