OrganizationLinkerService.java

1
package edu.ucsb.cs156.frontiers.services;
2
3
import com.fasterxml.jackson.core.JsonProcessingException;
4
import com.fasterxml.jackson.databind.JsonNode;
5
import com.fasterxml.jackson.databind.ObjectMapper;
6
import edu.ucsb.cs156.frontiers.entities.Course;
7
import edu.ucsb.cs156.frontiers.errors.InvalidInstallationTypeException;
8
import edu.ucsb.cs156.frontiers.models.CourseWarning;
9
import java.security.NoSuchAlgorithmException;
10
import java.security.spec.InvalidKeySpecException;
11
import java.time.ZonedDateTime;
12
import org.springframework.beans.factory.annotation.Autowired;
13
import org.springframework.boot.web.client.RestTemplateBuilder;
14
import org.springframework.data.auditing.DateTimeProvider;
15
import org.springframework.http.HttpEntity;
16
import org.springframework.http.HttpHeaders;
17
import org.springframework.http.HttpMethod;
18
import org.springframework.http.ResponseEntity;
19
import org.springframework.stereotype.Service;
20
import org.springframework.web.client.HttpClientErrorException;
21
import org.springframework.web.client.RestTemplate;
22
23
@Service
24
public class OrganizationLinkerService {
25
  private RestTemplate restTemplate;
26
27
  @Autowired JwtService jwtService;
28
29
  @Autowired ObjectMapper objectMapper;
30
31
  @Autowired DateTimeProvider provider;
32
33
  public OrganizationLinkerService(RestTemplateBuilder restTemplateBuilder) {
34
    restTemplate = restTemplateBuilder.build();
35
  }
36
37
  /**
38
   * Returns the URL for a redirect to install Frontiers
39
   *
40
   * @return URL to install Frontiers to an organization
41
   */
42
  public String getRedirectUrl()
43
      throws NoSuchAlgorithmException, InvalidKeySpecException, JsonProcessingException {
44
    String token = jwtService.getJwt();
45
    HttpHeaders requestHeaders = new HttpHeaders();
46 1 1. getRedirectUrl : removed call to org/springframework/http/HttpHeaders::add → KILLED
    requestHeaders.add("Authorization", "Bearer " + token);
47 1 1. getRedirectUrl : removed call to org/springframework/http/HttpHeaders::add → KILLED
    requestHeaders.add("Accept", "application/vnd.github+json");
48 1 1. getRedirectUrl : removed call to org/springframework/http/HttpHeaders::add → KILLED
    requestHeaders.add("X-GitHub-Api-Version", "2022-11-28");
49
    String ENDPOINT = "https://api.github.com/app";
50
    HttpEntity<String> newEntity = new HttpEntity<>(requestHeaders);
51
    ResponseEntity<String> response =
52
        restTemplate.exchange(ENDPOINT, HttpMethod.GET, newEntity, String.class);
53
54
    JsonNode responseJson = objectMapper.readTree(response.getBody());
55
56
    String newUrl = responseJson.get("html_url").toString().replaceAll("\"", "");
57 1 1. getRedirectUrl : replaced return value with "" for edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::getRedirectUrl → KILLED
    return newUrl;
58
  }
59
60
  /**
61
   * Provides the name of the organization attached to a particular installation ID
62
   *
63
   * @param installation_id ID of the app installation
64
   * @return name of the organization attached to the installation
65
   */
66
  public String getOrgName(String installation_id)
67
      throws NoSuchAlgorithmException, InvalidKeySpecException, JsonProcessingException {
68
    String token = jwtService.getJwt();
69
    String ENDPOINT = "https://api.github.com/app/installations/" + installation_id;
70
71
    HttpHeaders headers = new HttpHeaders();
72 1 1. getOrgName : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("Authorization", "Bearer " + token);
73 1 1. getOrgName : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("Accept", "application/vnd.github+json");
74 1 1. getOrgName : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("X-GitHub-Api-Version", "2022-11-28");
75
    HttpEntity<String> entity = new HttpEntity<>(headers);
76
    ResponseEntity<String> response =
77
        restTemplate.exchange(ENDPOINT, HttpMethod.GET, entity, String.class);
78
    JsonNode responseJson = objectMapper.readTree(response.getBody());
79
    String type = responseJson.get("account").get("type").asText();
80 1 1. getOrgName : negated conditional → KILLED
    if (!type.equals("Organization")) {
81
      throw new InvalidInstallationTypeException(type);
82
    }
83
    String orgName = responseJson.get("account").get("login").asText();
84 1 1. getOrgName : replaced return value with "" for edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::getOrgName → KILLED
    return orgName;
85
  }
86
87
  public CourseWarning checkCourseWarnings(Course course)
88
      throws NoSuchAlgorithmException, InvalidKeySpecException, JsonProcessingException {
89
90 2 1. checkCourseWarnings : negated conditional → KILLED
2. checkCourseWarnings : negated conditional → KILLED
    if (course.getOrgName() == null || course.getInstallationId() == null) {
91 1 1. checkCourseWarnings : replaced return value with null for edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::checkCourseWarnings → KILLED
      return new CourseWarning(false, false);
92
    }
93
94
    String ENDPOINT = "https://api.github.com/orgs/" + course.getOrgName();
95
    HttpHeaders headers = new HttpHeaders();
96
    String token = jwtService.getInstallationToken(course);
97 1 1. checkCourseWarnings : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("Authorization", "Bearer " + token);
98 1 1. checkCourseWarnings : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("Accept", "application/vnd.github+json");
99 1 1. checkCourseWarnings : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("X-GitHub-Api-Version", "2022-11-28");
100
    HttpEntity<String> entity = new HttpEntity<>(headers);
101
    ResponseEntity<JsonNode> response =
102
        restTemplate.exchange(ENDPOINT, HttpMethod.GET, entity, JsonNode.class);
103
    JsonNode responseJson = response.getBody();
104
    ZonedDateTime creationDate = ZonedDateTime.parse(responseJson.get("created_at").asText());
105
    ZonedDateTime now = ZonedDateTime.from(provider.getNow().get());
106
    boolean showOrganizationAgeWarning = creationDate.isAfter(now.minusMonths(1));
107
    String defaultPermission = responseJson.get("default_repository_permission").asText();
108 1 1. checkCourseWarnings : negated conditional → KILLED
    boolean showDefaultBasePermissions = !defaultPermission.equals("none");
109 1 1. checkCourseWarnings : replaced return value with null for edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::checkCourseWarnings → KILLED
    return new CourseWarning(showOrganizationAgeWarning, showDefaultBasePermissions);
110
  }
111
112
  /**
113
   * Returns the default base permission for the organization linked to a course. Uses the GitHub
114
   * REST API since this field is not available in the GraphQL API.
115
   *
116
   * @param course The course whose linked organization is being queried
117
   * @return The default repository permission string (e.g. "none", "read", "write", "admin")
118
   */
119
  public String getDefaultBasePermission(Course course)
120
      throws NoSuchAlgorithmException, InvalidKeySpecException, JsonProcessingException {
121
    String ENDPOINT = "https://api.github.com/orgs/" + course.getOrgName();
122
    HttpHeaders headers = new HttpHeaders();
123
    String token = jwtService.getInstallationToken(course);
124 1 1. getDefaultBasePermission : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("Authorization", "Bearer " + token);
125 1 1. getDefaultBasePermission : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("Accept", "application/vnd.github+json");
126 1 1. getDefaultBasePermission : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("X-GitHub-Api-Version", "2022-11-28");
127
    HttpEntity<String> entity = new HttpEntity<>(headers);
128
    ResponseEntity<JsonNode> response =
129
        restTemplate.exchange(ENDPOINT, HttpMethod.GET, entity, JsonNode.class);
130
    JsonNode responseJson = response.getBody();
131 1 1. getDefaultBasePermission : replaced return value with "" for edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::getDefaultBasePermission → KILLED
    return responseJson.get("default_repository_permission").asText();
132
  }
133
134
  /**
135
   * Removes the Frontiers installation from the linked GitHub org
136
   *
137
   * @param course The entity for the course about to be deleted
138
   */
139
  public void unenrollOrganization(Course course)
140
      throws NoSuchAlgorithmException, InvalidKeySpecException {
141 2 1. unenrollOrganization : negated conditional → KILLED
2. unenrollOrganization : negated conditional → KILLED
    if (course.getOrgName() == null || course.getInstallationId() == null) {
142
      return;
143
    }
144
    String token = jwtService.getJwt();
145
    String ENDPOINT = "https://api.github.com/app/installations/" + course.getInstallationId();
146
    HttpHeaders headers = new HttpHeaders();
147 1 1. unenrollOrganization : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("Authorization", "Bearer " + token);
148 1 1. unenrollOrganization : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("Accept", "application/vnd.github+json");
149 1 1. unenrollOrganization : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("X-GitHub-Api-Version", "2022-11-28");
150
    HttpEntity<String> entity = new HttpEntity<>(headers);
151
    try {
152
      ResponseEntity<String> response =
153
          restTemplate.exchange(ENDPOINT, HttpMethod.DELETE, entity, String.class);
154
    } catch (HttpClientErrorException ignored) {
155
156
    }
157
  }
158
}

Mutations

46

1.1
Location : getRedirectUrl
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:testRedirectUrl()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

47

1.1
Location : getRedirectUrl
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:testRedirectUrl()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

48

1.1
Location : getRedirectUrl
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:testRedirectUrl()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

57

1.1
Location : getRedirectUrl
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:testRedirectUrl()]
replaced return value with "" for edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::getRedirectUrl → KILLED

72

1.1
Location : getOrgName
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:testGetOrgName()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

73

1.1
Location : getOrgName
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:testGetOrgName()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

74

1.1
Location : getOrgName
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:testGetOrgName()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

80

1.1
Location : getOrgName
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:testGetOrgName()]
negated conditional → KILLED

84

1.1
Location : getOrgName
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:testGetOrgName()]
replaced return value with "" for edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::getOrgName → KILLED

90

1.1
Location : checkCourseWarnings
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:no_rest_service_calls_when_not_installed()]
negated conditional → KILLED

2.2
Location : checkCourseWarnings
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:test_showDefaultBasePermissions_true_when_read()]
negated conditional → KILLED

91

1.1
Location : checkCourseWarnings
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:no_rest_service_calls_when_not_installed_blank()]
replaced return value with null for edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::checkCourseWarnings → KILLED

97

1.1
Location : checkCourseWarnings
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:test_showDefaultBasePermissions_true_when_read()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

98

1.1
Location : checkCourseWarnings
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:test_showDefaultBasePermissions_true_when_read()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

99

1.1
Location : checkCourseWarnings
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:test_showDefaultBasePermissions_true_when_read()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

108

1.1
Location : checkCourseWarnings
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:test_showDefaultBasePermissions_true_when_read()]
negated conditional → KILLED

109

1.1
Location : checkCourseWarnings
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:test_showDefaultBasePermissions_true_when_read()]
replaced return value with null for edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::checkCourseWarnings → KILLED

124

1.1
Location : getDefaultBasePermission
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:test_getDefaultBasePermission_usesOrgNameInUrl()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

125

1.1
Location : getDefaultBasePermission
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:test_getDefaultBasePermission_usesOrgNameInUrl()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

126

1.1
Location : getDefaultBasePermission
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:test_getDefaultBasePermission_usesOrgNameInUrl()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

131

1.1
Location : getDefaultBasePermission
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:test_getDefaultBasePermission_usesOrgNameInUrl()]
replaced return value with "" for edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::getDefaultBasePermission → KILLED

141

1.1
Location : unenrollOrganization
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:testNotInstalled()]
negated conditional → KILLED

2.2
Location : unenrollOrganization
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:earlyReturnOnNoInstallationId()]
negated conditional → KILLED

147

1.1
Location : unenrollOrganization
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:testNotInstalled()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

148

1.1
Location : unenrollOrganization
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:testNotInstalled()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

149

1.1
Location : unenrollOrganization
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:testNotInstalled()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0