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

Mutations

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

49

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

58

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

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

75

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

81

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

85

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

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()]
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_warning_when_new()]
negated conditional → KILLED

92

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()]
replaced return value with null for edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::checkCourseWarnings → 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_no_default_base_permission_warning_when_permission_is_null()]
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_no_default_base_permission_warning_when_permission_is_null()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

100

1.1
Location : checkCourseWarnings
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:test_no_default_base_permission_warning_when_permission_is_null()]
removed call to org/springframework/http/HttpHeaders::add → 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_no_default_base_permission_warning_when_hidden()]
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_no_default_base_permission_warning_when_permission_is_null()]
negated conditional → KILLED

111

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

112

1.1
Location : checkCourseWarnings
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:test_no_default_base_permission_warning_when_permission_is_null()]
replaced return value with null for edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::checkCourseWarnings → 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:testGetDefaultBasePermission_whenPermissionIsNull()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

127

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

128

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

132

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

137

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

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

138

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

140

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

150

1.1
Location : unenrollOrganization
Killed by : edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.services.OrganizationLinkerServiceTests]/[method:testUnenrollOrganization()]
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

156

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

157

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

158

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

Active mutators

Tests examined


Report generated by PIT 1.17.0