다음을 만족 시키는 코드를 작성하시오.
- 깃헙 이슈 1번부터 18번까지 댓글을 순회하며 댓글을 남긴 사용자를 체크 할 것.
- 참여율을 계산하세요. 총 18회에 중에 몇 %를 참여했는지 소숫점 두자리가지 보여줄 것.
제출 코드는 다음을 통해서 자세히 볼 수 있다.
준비물
먼저, 깃허브 이슈를 코드로 접근하려면 관련 dependency 와 깃허브 접근 수단이 있어야 한다.
필자는 maven을 사용하기 때문에 pom.xml 에 다음과 같이 적는다.
<dependency>
<groupId>org.kohsuke</groupId>
<artifactId>github-api</artifactId>
<version>1.117</version>
</dependency>
깃허브 접근 수단
다음 링크에서 자세히 설명 하고 있다.
도메인
준비가 끝났으면 도메인에 대해서 정리를 해보자.
github api 에서의 이슈를 우리는 과제로 이해 하고 있고
이슈의 댓글을 단 유저는 우리는 과제제출자로 이해를 할 것이다.
live-study 대시 보드를 만들기 위해 우리의 도메인을 먼저 정의 해보자.
필자는 모든 참석자와 과제별 참석자 정보를 도메인으로 정의 해보았다.
반복문을 최대한 조금 쓰려다 보니까 도메인이 Collection 만으로 구성된 것 같다..
@Getter
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Participation {
// 모든 참석자
private Set<String> allUserNames;
// 과제 이름, 참석자들
private Map<Integer, Set<String>> taskInfoMap;
}
변역 (translate)
github api 에서 주는 데이터들은 우리의 도메인 다르기 때문에
우리의 도메인으로 변역을 해주는 과정을 거쳐보자.
@Log
@Repository
public class TranslateGithubAPI {
@Value("${oauthToken}")
private String oauthToken;
public Optional<Participation> translate() throws IOException {
log.info("github api 접속 요청");
final GitHub gitHub = new GitHubBuilder().withOAuthToken(oauthToken).build();
log.info("github api 접속 완료");
final String repositoryName = "whiteship/live-study";
log.info("github repository 접속 요청");
final GHRepository repository = gitHub.getRepository(repositoryName);
log.info("github repository 접속 완료");
log.info("github 이슈 조회 요청");
final List<GHIssue> allIssues = repository.getIssues(GHIssueState.ALL);
log.info("github 이슈 조회 완료");
// 모든 참가자
// 중복제거
// 자동으로 정렬
final Set<String> allUserIds = new TreeSet<>();
// 과제 별 제출 정보
final Map<Integer, Set<String>> taskInfoMap = new HashMap<>();
final String TASK_MANGER_NAME = "Keesun Baik";
final String COMMON_TITLE_WORD = "주";
log.info("github translate 시작");
for (GHIssue issue : allIssues) {
// 백기선님 글만 담기
final String issueWriterName = issue.getUser().getName();
if (!issueWriterName.equals(TASK_MANGER_NAME)) continue;
// "주" 앞의 숫자 가져오기
String issueTitle = issue.getTitle();
issueTitle = issueTitle.substring(0, issueTitle.indexOf(COMMON_TITLE_WORD));
final int taskWeekNumber = Integer.parseInt(issueTitle);
final Set<String> userIds = new HashSet<>();
for (GHIssueComment comment : issue.getComments()) {
final String commentUserId = comment.getUser().getLogin();
allUserIds.add(commentUserId);
userIds.add(commentUserId);
}
// 과제 별 제출자
taskInfoMap.put(taskWeekNumber, userIds);
}
log.info("github translate 완료");
return Optional.of(Participation.builder().
allUserNames(allUserIds)
.taskInfoMap(taskInfoMap)
.build());
}
}
participation service
외부 github api 에서 가져온 데이터를 도메인인 Participation 으로 바꿨다면,
대시보드를 만들 때 쓸 수 있도록 participation service 를 만들어보자.
@Log
@Service
@RequiredArgsConstructor
public class ParticipationService {
private final TranslateGithubAPI translateGithub;
public Optional<Participation> findParticipationAll() {
try {
final Participation participation = translateGithub.translate().orElseThrow(() -> new IllegalAccessError("번역을 잘못했어영"));
log.info("github api 변역 완료");
return Optional.of(participation);
} catch (IOException e) {
e.printStackTrace();
}
return Optional.empty();
}
}
대시보드 VIEW
그렇다면 이제 대시보드를 그리는 코드를 작성해보자.
대시보드는 Application 이 실행되면 바로 실행 할 수 있도록 설정 했다.
그리고 대시보드는 markdown 형태의 글들로 작성하였고
작성된 내용은 프로젝트 README.md 파일로 생성 되도록 만들었다.
@Log
@Service
@RequiredArgsConstructor
public class DashBoardService {
private final ParticipationService participationService;
@EventListener(ApplicationReadyEvent.class)
public void createViewFromParticipation() {
final Participation participation = participationService.findParticipationAll().orElseThrow(() -> new IllegalArgumentException("findParticipationAll error"));
final String contents = getContents(participation);
try {
log.info("README 작성 시작");
final String path = System.getProperty("user.dir");
File file = new File(path + "/README.md");
FileOutputStream fos = new FileOutputStream(file);
fos.write(contents.getBytes());
log.info("README 작성 완료");
} catch (Exception e) {
e.printStackTrace();
}
}
private String getContents(Participation participation) {
final Map<Integer, Set<String>> taskInfoMap = participation.getTaskInfoMap();
final List<Map.Entry<Integer, Set<String>>> sortedTaskInfoMap = taskInfoMap.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toList());
final Set<String> allUserNames = participation.getAllUserNames();
// 총 과제 수
final double totalTaskCount = taskInfoMap.keySet().size();
// 제목
String subject = "### 스터디 참여 현황 \n";
log.info("테이블 제목 작성 시작");
StringBuilder tableHeading = new StringBuilder("| 참여자 ");
StringBuilder tableLine = new StringBuilder("|---|:");
for (Map.Entry<Integer, Set<String>> entry : sortedTaskInfoMap) {
String ISSUE_TITLE_SUFFIX = "주차";
final String issueTitle = String.format("| %s ", entry.getKey() + ISSUE_TITLE_SUFFIX);
tableHeading.append(issueTitle);
tableLine.append("---:|");
}
tableHeading.append(" | 참여율 | \n");
tableLine.append("---:| \n");
log.info("테이블 제목 작성 완료");
log.info("테이블 컨텐츠 작성 시작");
StringBuilder tableRows = new StringBuilder();
for (String userName : allUserNames) {
tableRows.append("| ").append(userName);
double submittedCount = 0;
for (Map.Entry<Integer, Set<String>> entry : sortedTaskInfoMap) {
if (entry.getValue().contains(userName)) {
tableRows.append("| ✅ ");
submittedCount += 1;
continue;
}
tableRows.append("| ");
}
double taskRate = (submittedCount * 100) / totalTaskCount;
tableRows.append(" | ` ").append(String.format("%.2f", taskRate)).append("% ` | \n");
}
log.info("테이블 컨텐츠 작성 종료");
return subject +
tableHeading +
tableLine +
tableRows;
}
}
이제 어플리케이션을 작동 시켜보면 README.md 파일이 생성된 것 을 볼 수 있다.
'스터디 > [white-ship] 자바 스터디(study hale)' 카테고리의 다른 글
3주차 과제: 연산자 (0) | 2021.01.02 |
---|---|
4주차 과제: 제어문 (0) | 2021.01.02 |
4주차 과제 LinkedList (0) | 2021.01.02 |
4주차 과제: Stack (0) | 2021.01.02 |
4주차 과제: Queue (0) | 2021.01.02 |
댓글