Skip to content

Commit

Permalink
Merge pull request #17 from sopt-makers/feat/#16-sopticle-visitor-api
Browse files Browse the repository at this point in the history
[Feat]:sopticle, visitor 조회 기능 v2 API 마이그레이션 작업
  • Loading branch information
softmoca authored Jan 2, 2025
2 parents 7a32a57 + c7d2e9b commit cfd465e
Show file tree
Hide file tree
Showing 38 changed files with 1,271 additions and 123 deletions.
13 changes: 13 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
FROM openjdk:17-jdk-slim AS build
WORKDIR /app
COPY . /app
RUN apt-get update && apt-get install -y curl unzip
RUN ./gradlew build

FROM openjdk:17-jdk-slim AS production
WORKDIR /app

# Install Chrome and dependencies
RUN apt-get update && apt-get install -y \
chromium \
chromium-driver \
xvfb \
&& rm -rf /var/lib/apt/lists/*

# Set Chrome environment variables
ENV CHROME_BIN=/usr/bin/chromium
ENV CHROMEDRIVER_BIN=/usr/bin/chromedriver

COPY --from=build /app/build/libs/*.jar app.jar

ENTRYPOINT ["java","-jar","/app/app.jar"]
14 changes: 14 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ dependencies {
// Caffeine cache
implementation 'com.github.ben-manes.caffeine:caffeine'

// Jsoup for HTML parsing
implementation 'org.jsoup:jsoup:1.15.4'

// Selenium
implementation 'org.seleniumhq.selenium:selenium-java:4.8.1'
implementation 'org.seleniumhq.selenium:selenium-chrome-driver:4.8.1'
implementation 'io.github.bonigarcia:webdrivermanager:5.3.2'

runtimeOnly 'com.h2database:h2'
runtimeOnly 'org.postgresql:postgresql'
}
Expand All @@ -77,3 +85,9 @@ dependencyManagement {
tasks.named('test') {
useJUnitPlatform()
}

def querydslDir = "$buildDir/generated/querydsl"

sourceSets {
main.java.srcDir querydslDir
}
2 changes: 2 additions & 0 deletions src/main/java/sopt/org/homepage/HomepageApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@EnableJpaAuditing
@SpringBootApplication
public class HomepageApplication {

Expand Down
36 changes: 30 additions & 6 deletions src/main/java/sopt/org/homepage/aboutsopt/AboutSoptService.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,31 @@
import sopt.org.homepage.exception.NotFoundException;
import sopt.org.homepage.internal.crew.CrewService;
import sopt.org.homepage.internal.playground.PlaygroundService;
import sopt.org.homepage.main.entity.MainEntity;
import sopt.org.homepage.main.repository.MainRepository;
import sopt.org.homepage.main.service.MainService;
import sopt.org.homepage.project.ProjectService;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class AboutSoptService {
private static final int MINIMUM_PROJECT_COUNT = 10;
private final AboutSoptRepository aboutSoptRepository;
private final MainService mainService;
private final CrewService crewService;
private final PlaygroundService playgroundService;
private final ProjectService projectService;

public GetAboutSoptResponseDto getAboutSopt(Integer generation) {
AboutSoptEntity aboutSopt = generation != null ?
aboutSoptRepository.findByIdAndIsPublishedTrue(Long.valueOf(generation))
.orElseThrow(() -> new NotFoundException("Not found Published about sopt with id: " + generation))
: aboutSoptRepository.findTopByIsPublishedTrueOrderByIdDesc()
.orElseThrow(() -> new NotFoundException("Not found any published AboutSopt"));
int targetGeneration = 33; // TODO: 현재 34기 데이터가 모이지 않은 관계로 추후 돌려놓아야 함

int currentGeneration = generation != null ? generation : mainService.getLatestGeneration();


AboutSoptEntity aboutSopt = aboutSoptRepository.findByIdAndIsPublishedTrue(Long.valueOf(currentGeneration))
.orElseThrow(() -> new NotFoundException("Not found Published about sopt with id: " + currentGeneration));

int targetGeneration = determineTargetGeneration(currentGeneration);

var members = playgroundService.getAllMembers(targetGeneration);
var projects = projectService.findByGeneration(targetGeneration);
Expand All @@ -46,6 +53,23 @@ public GetAboutSoptResponseDto getAboutSopt(Integer generation) {
.build();
}

private int determineTargetGeneration(int currentGeneration) {
return findGenerationWithMinimumProjects(currentGeneration, currentGeneration - 5); // 5기수 전까지(무한 루프 방지)
}

private int findGenerationWithMinimumProjects(int currentGeneration, int minGeneration) {
if (currentGeneration < minGeneration) {
return minGeneration; // 최소 기수보다 작아지면 최소 기수 반환
}

var projects = projectService.findByGeneration(currentGeneration);
if (projects.size() >= MINIMUM_PROJECT_COUNT) {
return currentGeneration;
}

return findGenerationWithMinimumProjects(currentGeneration - 1, minGeneration);
}

private AboutSoptResponseDto convertToResponseDto(AboutSoptEntity entity) {
return AboutSoptResponseDto.builder()
.id((long) entity.getId())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,27 @@ public class CoreValueEntity {
@Id
@Column(name = "\"id\"", nullable = false)
private int id;

@Basic
@Column(name = "\"title\"", nullable = false, length = 100)
private String title;

@Basic
@Column(name = "\"subTitle\"", nullable = false, length = 100)
private String subTitle;

@Basic
@Column(name = "\"imageUrl\"", nullable = false, length = 400)
private String imageUrl;
@Basic
@Column(name = "\"createdAt\"", nullable = false)
private Timestamp createdAt;

@Basic
@Column(name = "\"updatedAt\"", nullable = false)
private Timestamp updatedAt;
@Basic
@Column(name = "\"aboutSoptId\"", nullable = true)
private Integer aboutSoptId;

@ManyToOne
@JoinColumn(name = "\"aboutSoptId\"", insertable = false, updatable = false)
private AboutSoptEntity aboutSopt;

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
@RequiredArgsConstructor
public enum CacheType {
MAIN_ENTITY("mainEntityCache", 10, 5),
PROJECT_LIST("projectListCache", 100, 24 * 60); // 24시간 캐시

PROJECT_LIST("projectListCache", 100, 24 * 60),
VISITOR("visitorCache", 10000, 24 * 60);

private final String cacheName;
private final int maxSize;
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/sopt/org/homepage/config/AuthConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,7 @@ public class AuthConfig {
@Value("${internal.playground.token}")
private String playgroundToken;

@Value("${internal.crew.token}")
private String crewApiToken;

}
2 changes: 2 additions & 0 deletions src/main/java/sopt/org/homepage/config/CacheConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import sopt.org.homepage.common.constants.CacheType;

import java.time.Duration;
Expand All @@ -18,6 +19,7 @@
@Configuration
@EnableCaching
@Getter
@EnableScheduling
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
Expand Down
33 changes: 0 additions & 33 deletions src/main/java/sopt/org/homepage/entity/SopticleAuthorEntity.java

This file was deleted.

52 changes: 0 additions & 52 deletions src/main/java/sopt/org/homepage/entity/SopticleEntity.java

This file was deleted.

25 changes: 0 additions & 25 deletions src/main/java/sopt/org/homepage/entity/SopticleLikeEntity.java

This file was deleted.

3 changes: 3 additions & 0 deletions src/main/java/sopt/org/homepage/internal/crew/CrewClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import sopt.org.homepage.internal.crew.dto.CrewMeetingResponse;

@FeignClient(value = "CrewClient", url = "${internal.crew.url}")
public interface CrewClient {
//@GetMapping("/meeting/v2")
@GetMapping("/meeting")
CrewMeetingResponse getAllStudy(
//ㅈ@RequestHeader("Authorization") String authToken,
@RequestParam("page") Integer page,
@RequestParam("take") Integer take,
@RequestParam("createdGenerations") Integer generation,
Expand Down
22 changes: 21 additions & 1 deletion src/main/java/sopt/org/homepage/internal/crew/CrewService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.stereotype.Service;
import sopt.org.homepage.config.AuthConfig;
import sopt.org.homepage.internal.crew.dto.StudyResponse;
import sopt.org.homepage.common.mapper.ResponseMapper;

Expand All @@ -18,16 +19,19 @@
public class CrewService {
private final CrewClient crewClient;
private final ResponseMapper responseMapper;
private final AuthConfig authConfig;
private final String studyCategory = URLEncoder.encode("스터디", StandardCharsets.UTF_8);
private final Integer PREV_GEN = 33;

public List<StudyResponse> getAllStudy(Integer generation){
val MAX_TAKE_COUNT = 50;
val activeGen = (generation != null) ? generation : PREV_GEN;
val activeGen = (generation != null) ? generation : PREV_GEN;
val active = !activeGen.equals(PREV_GEN);

val crewApiResponse = crewClient.getAllStudy(1, MAX_TAKE_COUNT, activeGen, active, studyCategory);

// val crewApiResponse = crewClient.getAllStudy(authConfig.getCrewApiToken(),1, MAX_TAKE_COUNT, activeGen, active, studyCategory);

return crewApiResponse.data().meetings().stream().map(responseMapper::toStudyResponse).toList();
}

Expand All @@ -38,6 +42,22 @@ public Integer getStudyCount(Integer generation) {
val crewApiResponse = crewClient.getAllStudy(1, 1, activeGen, active, studyCategory);

return crewApiResponse.data().meta().itemCount();
// try {
// val activeGen = (generation != null) ? generation : PREV_GEN;
// val active = !activeGen.equals(PREV_GEN);
//
// val crewApiResponse = crewClient.getAllStudy(authConfig.getCrewApiToken(), 1, 1, activeGen, active, studyCategory);
//
// if (crewApiResponse == null || crewApiResponse.data() == null || crewApiResponse.data().meta() == null) {
// return 0; // 또는 다른 기본값
// }
//
// return crewApiResponse.data().meta().itemCount();
// } catch (Exception e) {
// log.error("Failed to get study count", e);
// return 0; // 또는 다른 기본값
// }

}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ public interface MainService {
GetMainPageResponseDto getMainPageData();
GetAboutPageResponseDto getAboutPageData();
GetRecruitingPageResponseDto getRecruitingPageData();
int getLatestGeneration();
}
Original file line number Diff line number Diff line change
Expand Up @@ -444,4 +444,11 @@ public GetRecruitingPageResponseDto getRecruitingPageData() {
)
.build();
}


@Override
public int getLatestGeneration() {
MainEntity mainEntity = mainRepository.findFirstByOrderByGenerationDesc();
return mainEntity.getGeneration();
}
}
Loading

0 comments on commit cfd465e

Please sign in to comment.