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.errors.NoLinkedOrganizationException;
9
import edu.ucsb.cs156.frontiers.models.CourseWarning;
10
import java.security.NoSuchAlgorithmException;
11
import java.security.spec.InvalidKeySpecException;
12
import java.time.ZonedDateTime;
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,
90
          InvalidKeySpecException,
91
          JsonProcessingException,
92
          NoLinkedOrganizationException {
93
94 2 1. checkCourseWarnings : negated conditional → KILLED
2. checkCourseWarnings : negated conditional → KILLED
    if (course.getOrgName() == null || course.getInstallationId() == null) {
95 1 1. checkCourseWarnings : replaced return value with null for edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::checkCourseWarnings → KILLED
      return new CourseWarning(false, false);
96
    }
97
98
    String ENDPOINT = "https://api.github.com/orgs/" + course.getOrgName();
99
    HttpHeaders headers = new HttpHeaders();
100
    String token = jwtService.getInstallationToken(course);
101 1 1. checkCourseWarnings : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("Authorization", "Bearer " + token);
102 1 1. checkCourseWarnings : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("Accept", "application/vnd.github+json");
103 1 1. checkCourseWarnings : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("X-GitHub-Api-Version", "2022-11-28");
104
    HttpEntity<String> entity = new HttpEntity<>(headers);
105
    ResponseEntity<JsonNode> response =
106
        restTemplate.exchange(ENDPOINT, HttpMethod.GET, entity, JsonNode.class);
107
    JsonNode responseJson = response.getBody();
108
    ZonedDateTime creationDate = ZonedDateTime.parse(responseJson.get("created_at").asText());
109
    ZonedDateTime now = ZonedDateTime.from(provider.getNow().get());
110
    boolean showOrganizationAgeWarning = creationDate.isAfter(now.minusMonths(1));
111
    String defaultRepositoryPermission = getDefaultRepositoryPermission(course);
112 1 1. checkCourseWarnings : negated conditional → KILLED
    boolean showDefaultBasePermissions = !"none".equals(defaultRepositoryPermission);
113 1 1. checkCourseWarnings : replaced return value with null for edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::checkCourseWarnings → KILLED
    return new CourseWarning(showOrganizationAgeWarning, showDefaultBasePermissions);
114
  }
115
116
  /**
117
   * Retrieves the default repository permission for the GitHub organization linked to a course.
118
   *
119
   * @param course The course whose linked organization is queried.
120
   * @return The organization's default repository permission (e.g. {@code none}, {@code read}).
121
   */
122
  public String getDefaultRepositoryPermission(Course course)
123
      throws NoSuchAlgorithmException,
124
          InvalidKeySpecException,
125
          JsonProcessingException,
126
          NoLinkedOrganizationException {
127
    String ENDPOINT = "https://api.github.com/orgs/" + course.getOrgName();
128
    HttpHeaders headers = new HttpHeaders();
129
    String token = jwtService.getInstallationToken(course);
130 1 1. getDefaultRepositoryPermission : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("Authorization", "Bearer " + token);
131 1 1. getDefaultRepositoryPermission : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("Accept", "application/vnd.github+json");
132 1 1. getDefaultRepositoryPermission : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("X-GitHub-Api-Version", "2022-11-28");
133
    HttpEntity<String> entity = new HttpEntity<>(headers);
134
    ResponseEntity<JsonNode> response =
135
        restTemplate.exchange(ENDPOINT, HttpMethod.GET, entity, JsonNode.class);
136 1 1. getDefaultRepositoryPermission : replaced return value with "" for edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::getDefaultRepositoryPermission → KILLED
    return response.getBody().get("default_repository_permission").asText();
137
  }
138
139
  /**
140
   * Removes the Frontiers installation from the linked GitHub org
141
   *
142
   * @param course The entity for the course about to be deleted
143
   */
144
  public void unenrollOrganization(Course course)
145
      throws NoSuchAlgorithmException, InvalidKeySpecException {
146 2 1. unenrollOrganization : negated conditional → KILLED
2. unenrollOrganization : negated conditional → KILLED
    if (course.getOrgName() == null || course.getInstallationId() == null) {
147
      return;
148
    }
149
    String token = jwtService.getJwt();
150
    String ENDPOINT = "https://api.github.com/app/installations/" + course.getInstallationId();
151
    HttpHeaders headers = new HttpHeaders();
152 1 1. unenrollOrganization : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("Authorization", "Bearer " + token);
153 1 1. unenrollOrganization : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("Accept", "application/vnd.github+json");
154 1 1. unenrollOrganization : removed call to org/springframework/http/HttpHeaders::add → KILLED
    headers.add("X-GitHub-Api-Version", "2022-11-28");
155
    HttpEntity<String> entity = new HttpEntity<>(headers);
156
    try {
157
      ResponseEntity<String> response =
158
          restTemplate.exchange(ENDPOINT, HttpMethod.DELETE, entity, String.class);
159
    } catch (HttpClientErrorException ignored) {
160
161
    }
162
  }
163
}

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

94

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

95

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

101

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()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

102

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()]
removed call to org/springframework/http/HttpHeaders::add → KILLED

103

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()]
removed call to org/springframework/http/HttpHeaders::add → 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_warning_when_new()]
negated conditional → KILLED

113

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()]
replaced return value with null for edu/ucsb/cs156/frontiers/services/OrganizationLinkerService::checkCourseWarnings → KILLED

130

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

131

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

132

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

136

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

146

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

152

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

153

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

154

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