-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: 기관 보고용 사용자 데이터 제공 API 개발 완료 (#107)
- Loading branch information
Showing
99 changed files
with
3,494 additions
and
717 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
stempo-api/src/main/java/com/stempo/config/CustomPathResourceResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.stempo.config; | ||
|
||
import jakarta.validation.constraints.NotNull; | ||
import java.io.FileNotFoundException; | ||
import java.io.IOException; | ||
import org.springframework.core.io.Resource; | ||
import org.springframework.web.servlet.resource.PathResourceResolver; | ||
|
||
public class CustomPathResourceResolver extends PathResourceResolver { | ||
|
||
@Override | ||
protected Resource getResource(@NotNull String resourcePath, @NotNull Resource location) | ||
throws IOException { | ||
Resource resource = location.createRelative(resourcePath); | ||
if (resource.exists() && resource.isReadable()) { | ||
return resource; | ||
} | ||
throw new FileNotFoundException("Resource not found: " + resourcePath); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
stempo-api/src/main/java/com/stempo/controller/AdminReportController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package com.stempo.controller; | ||
|
||
import com.stempo.dto.ApiResponse; | ||
import com.stempo.dto.response.PersonalRhythmSettingsResponseDto; | ||
import com.stempo.dto.response.PersonalTrainingSettingsResponseDto; | ||
import com.stempo.dto.response.RecordReportResponseDto; | ||
import com.stempo.dto.response.RhythmReportResponseDto; | ||
import com.stempo.dto.response.UserDataResponseDto; | ||
import com.stempo.service.RecordReportService; | ||
import com.stempo.service.UserDataAggregationService; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import java.time.LocalDate; | ||
import java.util.List; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.security.access.prepost.PreAuthorize; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@Tag(name = "Admin Report", description = "사용자 활동 데이터 집계 및 분석") | ||
public class AdminReportController { | ||
|
||
private final UserDataAggregationService userDataAggregationService; | ||
private final RecordReportService recordReportService; | ||
|
||
@Operation(summary = "[A] 사용자 전체 이용 데이터 조회", description = "ROLE_ADMIN 이상의 권한이 필요함<br>" | ||
+ "사용자의 보행 훈련 및 과제 데이터를 조회함") | ||
@PreAuthorize("hasRole('ADMIN')") | ||
@GetMapping("/api/v1/admin/report/user-data") | ||
public ApiResponse<List<UserDataResponseDto>> getUserData( | ||
@RequestParam(name = "deviceTags") List<String> deviceTags | ||
) { | ||
List<UserDataResponseDto> userData = userDataAggregationService.getUserData(deviceTags); | ||
return ApiResponse.success(userData); | ||
} | ||
|
||
@Operation(summary = "[A] 사용자 보행 훈련 기록 조회", description = "ROLE_ADMIN 이상의 권한이 필요함") | ||
@PreAuthorize("hasRole('ADMIN')") | ||
@GetMapping("/api/v1/admin/report/user-data/training") | ||
public ApiResponse<List<RecordReportResponseDto>> getRecordReport( | ||
@RequestParam(name = "deviceTags") List<String> deviceTags, | ||
@RequestParam(name = "startDate", required = false) LocalDate startDate, | ||
@RequestParam(name = "endDate", required = false) LocalDate endDate | ||
) { | ||
List<RecordReportResponseDto> recordReport = | ||
recordReportService.getRecordReport(deviceTags, startDate, endDate); | ||
return ApiResponse.success(recordReport); | ||
} | ||
|
||
@Operation(summary = "[A] 사용자 보행 분석 지표 설정값 조회", description = "ROLE_ADMIN 이상의 권한이 필요함<br>" | ||
+ "사용자의 첫 번째 보행 훈련 데이터와 과제 데이터를 조회함") | ||
@PreAuthorize("hasRole('ADMIN')") | ||
@GetMapping("/api/v1/admin/report/user-data/training-setting") | ||
public ApiResponse<List<PersonalTrainingSettingsResponseDto>> getPersonalTrainingSettings( | ||
@RequestParam(name = "deviceTags") List<String> deviceTags | ||
) { | ||
List<PersonalTrainingSettingsResponseDto> personalTrainingSettings = | ||
userDataAggregationService.getPersonalTrainingSettings(deviceTags); | ||
return ApiResponse.success(personalTrainingSettings); | ||
} | ||
|
||
@Operation(summary = "[A] 사용자 보행 훈련에 사용된 리듬 데이터 조회", description = "ROLE_ADMIN 이상의 권한이 필요함") | ||
@PreAuthorize("hasRole('ADMIN')") | ||
@GetMapping("/api/v1/admin/report/user-data/rhythm") | ||
public ApiResponse<List<RhythmReportResponseDto>> getRhythmReport( | ||
@RequestParam(name = "deviceTags") List<String> deviceTags, | ||
@RequestParam(name = "startDate", required = false) LocalDate startDate, | ||
@RequestParam(name = "endDate", required = false) LocalDate endDate | ||
) { | ||
List<RhythmReportResponseDto> recordReport = | ||
recordReportService.getRhythmReport(deviceTags, startDate, endDate); | ||
return ApiResponse.success(recordReport); | ||
} | ||
|
||
@Operation(summary = "[A] 사용자 맞춤형 리듬 설정값 조회", description = "ROLE_ADMIN 이상의 권한이 필요함<br>" | ||
+ "사용자가 처음 애플리케이션을 실행할 때 온보딩 과정에서 추천받은 리듬 설정값과 마지막으로 실행한 보행 훈련에서 설정한 리듬 설정값을 조회함") | ||
@PreAuthorize("hasRole('ADMIN')") | ||
@GetMapping("/api/v1/admin/report/user-data/rhythm-setting") | ||
public ApiResponse<List<PersonalRhythmSettingsResponseDto>> getPersonalRhythmSettings( | ||
@RequestParam(name = "deviceTags") List<String> deviceTags | ||
) { | ||
List<PersonalRhythmSettingsResponseDto> personalRhythmSettings = | ||
recordReportService.getPersonalRhythmSettings(deviceTags); | ||
return ApiResponse.success(personalRhythmSettings); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
stempo-api/src/test/java/com/stempo/config/CustomPathResourceResolverTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package com.stempo.config; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertSame; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.when; | ||
|
||
import java.io.FileNotFoundException; | ||
import java.io.IOException; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.core.io.Resource; | ||
|
||
class CustomPathResourceResolverTest { | ||
|
||
@Test | ||
void 존재하는_리소스를_반환한다() throws IOException { | ||
// given | ||
CustomPathResourceResolver resolver = new CustomPathResourceResolver(); | ||
String resourcePath = "test.txt"; | ||
Resource location = mock(Resource.class); | ||
Resource relativeResource = mock(Resource.class); | ||
when(location.createRelative(resourcePath)).thenReturn(relativeResource); | ||
when(relativeResource.exists()).thenReturn(true); | ||
when(relativeResource.isReadable()).thenReturn(true); | ||
|
||
// when | ||
Resource result = resolver.getResource(resourcePath, location); | ||
|
||
// then | ||
assertSame(relativeResource, result, "존재하고 읽을 수 있는 리소스가 반환되어야 한다."); | ||
} | ||
|
||
@Test | ||
void 존재하지_않는_리소스인_경우_예외를_던진다() throws IOException { | ||
// given | ||
CustomPathResourceResolver resolver = new CustomPathResourceResolver(); | ||
String resourcePath = "nonexistent.txt"; | ||
Resource location = mock(Resource.class); | ||
Resource relativeResource = mock(Resource.class); | ||
when(location.createRelative(resourcePath)).thenReturn(relativeResource); | ||
when(relativeResource.exists()).thenReturn(false); | ||
when(relativeResource.isReadable()).thenReturn(false); | ||
|
||
// when, then | ||
FileNotFoundException exception = assertThrows( | ||
FileNotFoundException.class, | ||
() -> resolver.getResource(resourcePath, location), | ||
"존재하지 않는 리소스 호출 시 FileNotFoundException이 발생해야 한다." | ||
); | ||
assertTrue(exception.getMessage().contains("Resource not found: " + resourcePath)); | ||
} | ||
} |
Oops, something went wrong.