CSVDownloadsController.java

1
package edu.ucsb.cs156.frontiers.controllers;
2
3
import com.opencsv.bean.StatefulBeanToCsv;
4
import com.opencsv.exceptions.CsvDataTypeMismatchException;
5
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
6
import edu.ucsb.cs156.frontiers.entities.Course;
7
import edu.ucsb.cs156.frontiers.entities.RosterStudent;
8
import edu.ucsb.cs156.frontiers.enums.RosterStatus;
9
import edu.ucsb.cs156.frontiers.errors.EntityNotFoundException;
10
import edu.ucsb.cs156.frontiers.models.RosterStudentDTO;
11
import edu.ucsb.cs156.frontiers.repositories.CourseRepository;
12
import edu.ucsb.cs156.frontiers.repositories.RosterStudentRepository;
13
import edu.ucsb.cs156.frontiers.services.RosterStudentDTOService;
14
import io.swagger.v3.oas.annotations.Operation;
15
import io.swagger.v3.oas.annotations.Parameter;
16
import io.swagger.v3.oas.annotations.media.Content;
17
import io.swagger.v3.oas.annotations.media.Schema;
18
import io.swagger.v3.oas.annotations.responses.ApiResponse;
19
import io.swagger.v3.oas.annotations.tags.Tag;
20
import java.io.IOException;
21
import java.io.OutputStreamWriter;
22
import java.io.Writer;
23
import java.nio.charset.StandardCharsets;
24
import java.util.List;
25
import lombok.extern.slf4j.Slf4j;
26
import org.apache.commons.csv.CSVFormat;
27
import org.apache.commons.csv.CSVPrinter;
28
import org.springframework.beans.factory.annotation.Autowired;
29
import org.springframework.http.HttpHeaders;
30
import org.springframework.http.MediaType;
31
import org.springframework.http.ResponseEntity;
32
import org.springframework.security.access.prepost.PreAuthorize;
33
import org.springframework.web.bind.annotation.GetMapping;
34
import org.springframework.web.bind.annotation.RequestMapping;
35
import org.springframework.web.bind.annotation.RequestParam;
36
import org.springframework.web.bind.annotation.RestController;
37
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
38
39
@Tag(name = "CSV Downloads")
40
@RequestMapping("/api/csv")
41
@RestController
42
@Slf4j
43
public class CSVDownloadsController extends ApiController {
44
45
  @Autowired private CourseRepository courseRepository;
46
47
  @Autowired private RosterStudentDTOService rosterStudentDTOService;
48
49
  @Autowired private RosterStudentRepository rosterStudentRepository;
50
51
  @Operation(
52
      summary = "Download CSV File of Roster Students",
53
      description = "Returns a CSV file as a response",
54
      responses = {
55
        @ApiResponse(
56
            responseCode = "200",
57
            description = "CSV file",
58
            content =
59
                @Content(
60
                    mediaType = "text/csv",
61
                    schema = @Schema(type = "string", format = "binary"))),
62
        @ApiResponse(responseCode = "500", description = "Internal Server Error")
63
      })
64
  @GetMapping(value = "/rosterstudents", produces = "text/csv")
65
  @PreAuthorize("@CourseSecurity.hasManagePermissions(#root, #courseId)")
66
  public ResponseEntity<StreamingResponseBody> csvForQuarter(
67
      @Parameter(name = "courseId", description = "course id", example = "1") @RequestParam
68
          Long courseId)
69
      throws EntityNotFoundException, Exception, IOException {
70
    Course course =
71
        courseRepository
72
            .findById(courseId)
73 1 1. lambda$csvForQuarter$0 : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CSVDownloadsController::lambda$csvForQuarter$0 → KILLED
            .orElseThrow(() -> new EntityNotFoundException(Course.class, courseId));
74
    StreamingResponseBody stream =
75
        (outputStream) -> {
76
          List<RosterStudentDTO> list = rosterStudentDTOService.getRosterStudentDTOs(courseId);
77
          try (Writer writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) {
78
            try {
79
              StatefulBeanToCsv<RosterStudentDTO> beanToCsvWriter =
80
                  rosterStudentDTOService.getStatefulBeanToCSV(writer);
81 1 1. lambda$csvForQuarter$1 : removed call to com/opencsv/bean/StatefulBeanToCsv::write → KILLED
              beanToCsvWriter.write(list);
82
            } catch (CsvDataTypeMismatchException | CsvRequiredFieldEmptyException e) {
83
              log.error("Error writing CSV file", e);
84
              throw new IOException("Error writing CSV file: " + e.getMessage());
85
            }
86
          }
87
        };
88
89 1 1. csvForQuarter : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CSVDownloadsController::csvForQuarter → KILLED
    return ResponseEntity.ok()
90
        .contentType(MediaType.parseMediaType("text/csv; charset=UTF-8"))
91
        .header(
92
            HttpHeaders.CONTENT_DISPOSITION,
93
            String.format("attachment;filename=%s_roster.csv", course.getCourseName()))
94
        .header(HttpHeaders.CONTENT_TYPE, "text/csv; charset=UTF-8")
95
        .header(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION)
96
        .body(stream);
97
  }
98
99
  @Operation(
100
      summary = "Download CATME CSV File of Roster Students",
101
      description = "Returns a CSV file as a response",
102
      responses = {
103
        @ApiResponse(
104
            responseCode = "200",
105
            description = "CSV file",
106
            content =
107
                @Content(
108
                    mediaType = "text/csv",
109
                    schema = @Schema(type = "string", format = "binary"))),
110
        @ApiResponse(responseCode = "500", description = "Internal Server Error")
111
      })
112
  @GetMapping(value = "/catme", produces = "text/csv")
113
  @PreAuthorize("@CourseSecurity.hasManagePermissions(#root, #courseId)")
114
  public ResponseEntity<StreamingResponseBody> catmeCsv(
115
      @Parameter(name = "courseId", description = "course id", example = "1") @RequestParam
116
          Long courseId)
117
      throws EntityNotFoundException {
118
    Course course =
119
        courseRepository
120
            .findById(courseId)
121 1 1. lambda$catmeCsv$2 : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CSVDownloadsController::lambda$catmeCsv$2 → KILLED
            .orElseThrow(() -> new EntityNotFoundException(Course.class, courseId));
122
    StreamingResponseBody stream =
123
        (outputStream) -> {
124
          List<RosterStudent> rosterStudents =
125
              rosterStudentRepository
126
                  .findByCourseIdAndRosterStatusInOrderByFirstNameAscLastNameAscIgnoreCase(
127
                      courseId, List.of(RosterStatus.ROSTER, RosterStatus.MANUAL));
128
          try (Writer writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
129
              CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT)) {
130 1 1. lambda$catmeCsv$3 : removed call to org/apache/commons/csv/CSVPrinter::printRecord → KILLED
            csvPrinter.printRecord("first", "last", "email", "id", "team");
131
            for (RosterStudent student : rosterStudents) {
132
              List<String> teams = student.getTeams();
133 2 1. lambda$catmeCsv$3 : negated conditional → KILLED
2. lambda$catmeCsv$3 : negated conditional → KILLED
              String team = teams != null && !teams.isEmpty() ? teams.get(0) : "";
134 1 1. lambda$catmeCsv$3 : removed call to org/apache/commons/csv/CSVPrinter::printRecord → KILLED
              csvPrinter.printRecord(
135
                  student.getFirstName(),
136
                  student.getLastName(),
137
                  student.getEmail(),
138
                  student.getStudentId(),
139
                  team);
140
            }
141
          }
142
        };
143
144 1 1. catmeCsv : replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CSVDownloadsController::catmeCsv → KILLED
    return ResponseEntity.ok()
145
        .contentType(MediaType.parseMediaType("text/csv; charset=UTF-8"))
146
        .header(
147
            HttpHeaders.CONTENT_DISPOSITION,
148
            String.format("attachment;filename=%s_catme.csv", course.getCourseName()))
149
        .header(HttpHeaders.CONTENT_TYPE, "text/csv; charset=UTF-8")
150
        .header(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION)
151
        .body(stream);
152
  }
153
}

Mutations

73

1.1
Location : lambda$csvForQuarter$0
Killed by : edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests]/[method:test_no_such_course()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CSVDownloadsController::lambda$csvForQuarter$0 → KILLED

81

1.1
Location : lambda$csvForQuarter$1
Killed by : edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests]/[method:mockMvcSRBTest()]
removed call to com/opencsv/bean/StatefulBeanToCsv::write → KILLED

89

1.1
Location : csvForQuarter
Killed by : edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests]/[method:test_csv_exception()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CSVDownloadsController::csvForQuarter → KILLED

121

1.1
Location : lambda$catmeCsv$2
Killed by : edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests]/[method:test_catme_no_such_course()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CSVDownloadsController::lambda$catmeCsv$2 → KILLED

130

1.1
Location : lambda$catmeCsv$3
Killed by : edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests]/[method:test_catme_csv_filters_to_roster_and_manual()]
removed call to org/apache/commons/csv/CSVPrinter::printRecord → KILLED

133

1.1
Location : lambda$catmeCsv$3
Killed by : edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests]/[method:test_catme_csv_filters_to_roster_and_manual()]
negated conditional → KILLED

2.2
Location : lambda$catmeCsv$3
Killed by : edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests]/[method:test_catme_csv_filters_to_roster_and_manual()]
negated conditional → KILLED

134

1.1
Location : lambda$catmeCsv$3
Killed by : edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests]/[method:test_catme_csv_filters_to_roster_and_manual()]
removed call to org/apache/commons/csv/CSVPrinter::printRecord → KILLED

144

1.1
Location : catmeCsv
Killed by : edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.frontiers.controllers.CSVDownloadsControllerTests]/[method:test_catme_csv_filters_to_roster_and_manual()]
replaced return value with null for edu/ucsb/cs156/frontiers/controllers/CSVDownloadsController::catmeCsv → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0