UCSBGradeHistoryServiceImpl.java
package edu.ucsb.cs156.courses.services;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.opencsv.CSVReader;
import edu.ucsb.cs156.courses.entities.GradeHistory;
import edu.ucsb.cs156.courses.models.ApiResult;
import edu.ucsb.cs156.courses.models.Quarter;
import edu.ucsb.cs156.courses.models.TreeElement;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service("UCSBGradeHistoryService")
@Slf4j
public class UCSBGradeHistoryServiceImpl implements UCSBGradeHistoryService {
private final RestTemplate restTemplate;
public UCSBGradeHistoryServiceImpl(RestTemplateBuilder restTemplateBuilder) {
restTemplate = restTemplateBuilder.build();
}
@Autowired ObjectMapper mapper;
public static final String REPO_OWNER_AND_NAME = "ucsb-cs156/UCSB_Grades";
public static final String API_ENDPOINT =
"https://api.github.com/repos/" + REPO_OWNER_AND_NAME + "/git/trees/main?recursive=1";
@Override
public List<String> getUrls() throws Exception {
log.info("getting data from {}", API_ENDPOINT);
HttpHeaders headers = new HttpHeaders();
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(headers);
Map<String, String> uriVariables = Map.of("recursive", "1");
ResponseEntity<String> re =
restTemplate.exchange(API_ENDPOINT, HttpMethod.GET, entity, String.class, uriVariables);
ApiResult apiResult = mapper.readValue(re.getBody(), ApiResult.class);
List<TreeElement> treeElements = apiResult.getTree();
List<String> urls =
treeElements.stream()
.map(treeElement -> treeElement.getPath())
.filter(path -> (path.startsWith("quarters/") && path.endsWith(".csv")))
.collect(Collectors.toList());
List<String> rawUrls =
urls.stream()
.map(url -> "https://raw.githubusercontent.com/" + REPO_OWNER_AND_NAME + "/main/" + url)
.collect(Collectors.toList());
return rawUrls;
}
@Override
public List<GradeHistory> getGradeData(String url) throws Exception {
log.info("getting data from {}", url);
HttpHeaders headers = new HttpHeaders();
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<String> re = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
String csvData = re.getBody();
return parse(new StringReader(csvData));
}
@Override
public List<GradeHistory> parse(Reader reader) throws Exception {
List<GradeHistory> gradeHistoryList = new ArrayList<GradeHistory>();
log.info("Parsing CSV file with grade history... ");
CSVReader csvReader = new CSVReader(reader);
csvReader.skip(1);
List<String[]> myEntries = csvReader.readAll();
for (String[] row : myEntries) {
String yyyyq = Integer.toString(Quarter.qyyToyyyyQ(row[0]));
GradeHistory gradeHistory =
GradeHistory.builder()
.yyyyq(yyyyq)
.course(row[2])
.instructor(row[3])
.grade(row[4])
.count(Integer.parseInt(row[5]))
.build();
log.info("Parsed: " + gradeHistory.toString());
gradeHistoryList.add(gradeHistory);
}
csvReader.close();
return gradeHistoryList;
}
}