Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
5fc62fc
[Hotfix] 활동 기수여도 솝탬프 조회 안하도록 주석처리
geniusYoo Mar 30, 2025
f7bda25
[Hotfix] 무조건 솝트와 N개월로 리턴되게 수정
geniusYoo Mar 30, 2025
e4d7935
[Deploy] 병합 충돌 해결
geniusYoo Mar 31, 2025
c0acb1a
[DEPLOY] QA 변경사항 Prod 배포 (#526)
hyerinhwang-sailin Apr 4, 2025
a62777a
[DEPLOY] QA 반영사항 Prod 배포 (#532)
hyerinhwang-sailin Apr 10, 2025
d94334d
[DEPLOY] QA 변경사항 Prod 배포 (#547)
hyerinhwang-sailin Apr 20, 2025
1e28875
Hotfix ios 강제 업데이트 반영
geniusYoo Apr 25, 2025
58ada8e
Merge branch 'main' into feat/#551-fab-api
geniusYoo May 19, 2025
f3ea071
[Feat] 운영 관련 테이블 구축 (#551)
geniusYoo May 19, 2025
c45c768
[Feat] 플로팅 버튼이 비활동 기수인 경우에도 요청은 할 수 있도록 whiteList에 추가 (#551)
geniusYoo May 19, 2025
28b9f91
[Feat] 플로팅 버튼 정보 조회 api controller (#551)
geniusYoo May 19, 2025
a7fd68d
[Feat] 플로팅 버튼 정보 조회 api facade (#551)
geniusYoo May 19, 2025
e4364e5
[Feat] OperationConfig에서 플로팅 버튼 관련 정보 가져오는 DB Query(#551)
geniusYoo May 19, 2025
ad6bc62
[Feat] 플로팅 버튼은 앱 서비스 진입 여부 조회에서 제외되도록 필터 추가 (#551)
geniusYoo May 19, 2025
5f9ed2e
[Feat] app-service에서 AppServiceName을 가져와야 하므로 플로팅 버튼 추가 (#551)
geniusYoo May 19, 2025
f3c8a6c
[Feat] 플로팅 버튼 정보 조회 api 응답 dto (#551)
geniusYoo May 19, 2025
d67aa35
[Refactor] isActive로 응답 내리기 위해 reference 타입으로 변경 (#551)
geniusYoo May 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ public enum AppServiceName {
POKE("콕찌르기", "POKE","pokeBadgeManager"),
SOPTAMP("솝탬프", "SOPTAMP","soptampBadgeManager"),
FORTUNE("솝마디", "FORTUNE","fortuneBadgeManager"),
OTHERS("", "OTHERS","defaultBadgeManager");
OTHERS("", "OTHERS","defaultBadgeManager"),
FLOATING_BUTTON("FAB", "FLOATING_BUTTON", "floatingButtonBadgeManager");

private final String exposedName;
private final String serviceName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,15 @@ public class AppServiceService {

public List<AppServiceInfo> getAllAppService() {
return appServiceRepository.findAll().stream()
.filter(appService -> !AppServiceName.of(appService.getServiceName()).equals(AppServiceName.OTHERS))
.filter(appService -> !(
AppServiceName.of(appService.getServiceName()).equals(AppServiceName.OTHERS) ||
AppServiceName.of(appService.getServiceName()).equals(AppServiceName.FLOATING_BUTTON)))
.sorted(Comparator.comparing(AppService::getCreatedAt).reversed())
.map(AppServiceInfo::of)
.toList();
}

public AppServiceInfo getAppService(String serviceName) {
return AppServiceInfo.of(appServiceRepository.findByServiceName(serviceName));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.sopt.app.application.app_service;

import lombok.RequiredArgsConstructor;
import org.sopt.app.common.config.OperationConfig;
import org.sopt.app.common.config.OperationConfigCategory;
import org.sopt.app.common.exception.NotFoundException;
import org.sopt.app.common.response.ErrorCode;
import org.sopt.app.interfaces.postgres.OperationConfigRepository;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
public class OperationConfigService {

private final OperationConfigRepository operationConfigRepository;

public List<OperationConfig> getOperationConfigByOperationConfigType(OperationConfigCategory operationConfigCategory) {
return operationConfigRepository.findByOperationConfigCategory(operationConfigCategory).orElseThrow(
() -> new NotFoundException(ErrorCode.ENTITY_NOT_FOUND));
}
}
41 changes: 41 additions & 0 deletions src/main/java/org/sopt/app/common/config/OperationConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.sopt.app.common.config;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.sopt.app.domain.entity.BaseEntity;

@Entity
@Getter
@NoArgsConstructor
@Table(name = "operation_configs" ,
uniqueConstraints = {
@UniqueConstraint(
name = "uk_operation_config_category_key",
columnNames = {"operation_config_category", "key"}
)
})

public class OperationConfig extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false)
private String key;

@Column(nullable = false)
private String value;

@Column(nullable = false)
@Enumerated(EnumType.STRING)
private OperationConfigType operationConfigType;

@Column(nullable = false)
@Enumerated(EnumType.STRING)
private OperationConfigCategory operationConfigCategory;

@Column(nullable = false)
private String description;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.sopt.app.common.config;

public enum OperationConfigCategory {
FLOATING_BUTTON
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.sopt.app.common.config;

public enum OperationConfigType {
DEEP_LINK,
WEB_LINK,
TEXT,
IMAGE_URL
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public class WebSecurityConfig {
"/api/v2/firebase/**",
"/api/v2/notification/**",
"/api/v2/user/main",
"/api/v2/home/app-service"
"/api/v2/home/app-service",
"/api/v2/home/floating-button",
};

private final JwtExceptionFilter jwtExceptionFilter;
Expand Down
41 changes: 40 additions & 1 deletion src/main/java/org/sopt/app/facade/HomeFacade.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@

import static org.sopt.app.common.utils.HtmlTagWrapper.wrapWithTag;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;
import lombok.val;
import org.sopt.app.application.app_service.*;
import org.sopt.app.application.app_service.dto.*;
import org.sopt.app.application.description.DescriptionInfo.MainDescription;
import org.sopt.app.application.description.DescriptionService;
import org.sopt.app.common.config.OperationConfig;
import org.sopt.app.common.config.OperationConfigCategory;
import org.sopt.app.common.utils.ActivityDurationCalculator;
import org.sopt.app.application.meeting.*;
import org.sopt.app.application.playground.PlaygroundAuthService;
Expand All @@ -28,6 +34,7 @@ public class HomeFacade {
private final AppServiceService appServiceService;
private final AppServiceBadgeService appServiceBadgeService;
private final MeetingService meetingService;
private final OperationConfigService operationConfigService;

@Transactional(readOnly = true)
@Deprecated
Expand All @@ -52,11 +59,13 @@ public List<AppServiceEntryStatusResponse> checkAppServiceEntryStatus(User user)
if(user == null){
return this.getOnlyAppServiceInfo();
}

return appServiceService.getAllAppService().stream()
.filter(appServiceInfo -> isServiceVisibleToUser(appServiceInfo, user))
.map(appServiceInfo -> appServiceBadgeService.getAppServiceEntryStatusResponse(
appServiceInfo, user.getId()
)).toList();
))
.toList();
}

private List<AppServiceEntryStatusResponse> getOnlyAppServiceInfo() {
Expand Down Expand Up @@ -100,4 +109,34 @@ public List<MeetingResponse> getAllMeetings(MeetingParamRequest request) {
.map(MeetingResponse::of)
.toList();
}

@Transactional(readOnly = true)
public FloatingButtonResponse getFloatingButtonInfo(User user) {
boolean isActive = false;
if (user != null) {
UserStatus userStatus = playgroundAuthService.getPlaygroundUserActiveInfo(
user.getPlaygroundToken(),
user.getPlaygroundId()
).status();

isActive = userStatus == UserStatus.ACTIVE ?
appServiceService.getAppService(AppServiceName.FLOATING_BUTTON.getServiceName()).getActiveUser() :
appServiceService.getAppService(AppServiceName.FLOATING_BUTTON.getServiceName()).getInactiveUser();
}


Map<String, String> operationConfigMap = operationConfigService.getOperationConfigByOperationConfigType(OperationConfigCategory.FLOATING_BUTTON).stream()
.collect(Collectors.toMap(OperationConfig::getKey, OperationConfig::getValue));

return FloatingButtonResponse.of(
operationConfigMap.get("imageUrl"),
operationConfigMap.get("title"),
operationConfigMap.get("expandedSubTitle"),
operationConfigMap.get("collapsedSubtitle"),
operationConfigMap.get("actionButtonName"),
operationConfigMap.get("linkUrl"),
isActive
);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
import org.springframework.data.jpa.repository.JpaRepository;

public interface AppServiceRepository extends JpaRepository<AppService, Long> {

AppService findByServiceName(String serviceName);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.sopt.app.interfaces.postgres;

import org.sopt.app.common.config.OperationConfig;
import org.sopt.app.common.config.OperationConfigCategory;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
import java.util.Optional;

public interface OperationConfigRepository extends JpaRepository<OperationConfig, Long> {
Optional<List<OperationConfig>> findByOperationConfigCategory(OperationConfigCategory operationConfigCategory);
}
15 changes: 15 additions & 0 deletions src/main/java/org/sopt/app/presentation/home/HomeController.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,19 @@ public ResponseEntity<List<MeetingResponse>> getAllMeeting(
homeFacade.getAllMeetings(new MeetingParamRequest(user.getPlaygroundId(), page, take, category))
);
}

@Operation(summary = "플로팅 버튼 정보 조회")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "success"),
@ApiResponse(responseCode = "401", description = "token error", content = @Content),
@ApiResponse(responseCode = "500", description = "server error", content = @Content)
})
@GetMapping("/floating-button")
public ResponseEntity<FloatingButtonResponse> getFloatingButtonInfo(
@AuthenticationPrincipal User user
) {
return ResponseEntity.ok(
homeFacade.getFloatingButtonInfo(user)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.sopt.app.presentation.home.response;

import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class FloatingButtonResponse {
private String imageUrl;
private String title;
private String expandedSubTitle;
private String collapsedSubtitle;
private String actionButtonName;
private String linkUrl;
private boolean isActive;

public static FloatingButtonResponse of(String imageUrl, String title, String expandedSubTitle,
String collapsedSubtitle, String actionButtonName, String linkUrl,
boolean isActive) {
return FloatingButtonResponse.builder()
.imageUrl(imageUrl)
.title(title)
.expandedSubTitle(expandedSubTitle)
.collapsedSubtitle(collapsedSubtitle)
.actionButtonName(actionButtonName)
.linkUrl(linkUrl)
.isActive(isActive)
.build();
}
}