TeamController.java

  1. package no.nav.data.team.team;

  2. import io.swagger.v3.oas.annotations.Operation;
  3. import io.swagger.v3.oas.annotations.media.Content;
  4. import io.swagger.v3.oas.annotations.media.Schema;
  5. import io.swagger.v3.oas.annotations.responses.ApiResponse;
  6. import io.swagger.v3.oas.annotations.tags.Tag;
  7. import jakarta.servlet.http.HttpServletResponse;
  8. import jakarta.validation.Valid;
  9. import lombok.extern.slf4j.Slf4j;
  10. import lombok.val;
  11. import no.nav.data.common.exceptions.TechnicalException;
  12. import no.nav.data.common.exceptions.ValidationException;
  13. import no.nav.data.common.rest.RestResponsePage;
  14. import no.nav.data.team.location.LocationRepository;
  15. import no.nav.data.team.location.domain.Location;
  16. import no.nav.data.team.shared.domain.DomainObjectStatus;
  17. import no.nav.data.team.team.TeamExportService.SpreadsheetType;
  18. import no.nav.data.team.team.domain.Team;
  19. import no.nav.data.team.team.domain.TeamOwnershipType;
  20. import no.nav.data.team.team.dto.TeamRequest;
  21. import no.nav.data.team.team.dto.TeamResponse;
  22. import org.springframework.http.HttpHeaders;
  23. import org.springframework.http.HttpStatus;
  24. import org.springframework.http.ResponseEntity;
  25. import org.springframework.transaction.annotation.Transactional;
  26. import org.springframework.util.StreamUtils;
  27. import org.springframework.web.bind.annotation.DeleteMapping;
  28. import org.springframework.web.bind.annotation.GetMapping;
  29. import org.springframework.web.bind.annotation.PathVariable;
  30. import org.springframework.web.bind.annotation.PostMapping;
  31. import org.springframework.web.bind.annotation.PutMapping;
  32. import org.springframework.web.bind.annotation.RequestBody;
  33. import org.springframework.web.bind.annotation.RequestMapping;
  34. import org.springframework.web.bind.annotation.RequestParam;
  35. import org.springframework.web.bind.annotation.RestController;

  36. import java.util.HashMap;
  37. import java.util.List;
  38. import java.util.Objects;
  39. import java.util.Optional;
  40. import java.util.UUID;

  41. import static no.nav.data.common.export.ExcelBuilder.SPREADSHEETML_SHEET_MIME;
  42. import static no.nav.data.common.utils.StreamUtils.convert;


  43. @Slf4j
  44. @RestController
  45. @RequestMapping("/team")
  46. @Tag(name = "Team", description = "Team endpoint")
  47. public class TeamController {

  48.     private final TeamService service;
  49.     private final TeamExportService teamExportService;
  50.     private final LocationRepository locationRepository;

  51.     public TeamController(TeamService service, TeamExportService teamExportService, LocationRepository locationRepository) {
  52.         this.service = service;
  53.         this.teamExportService = teamExportService;
  54.         this.locationRepository = locationRepository;
  55.     }

  56.     @Operation(summary = "Get All Teams")
  57.     @ApiResponse(description = "ok")
  58.     @GetMapping()
  59.     public ResponseEntity<RestResponsePage<TeamResponse>> getAll(
  60.             @RequestParam(name = "productAreaId", required = false) UUID productAreaId,
  61.             @RequestParam(name = "clusterId", required = false) UUID clusterId,
  62.             @RequestParam(name = "locationCode", required = false) String locationCode,
  63.             @RequestParam(name = "status", required = false, defaultValue = "ACTIVE,PLANNED,INACTIVE") String stringStatus
  64.     ) {
  65.         log.info("Get all Teams");

  66.         var queryStatusList = DomainObjectStatus.fromQueryParameter(stringStatus);

  67.         List<Team> teams;
  68.         if (productAreaId != null) {
  69.             teams = service.findByProductArea(productAreaId);
  70.         } else if (clusterId != null) {
  71.             teams = service.findByCluster(clusterId);
  72.         } else {
  73.             teams = service.getAll();
  74.         }

  75.         if(locationCode != null){
  76.             val location = locationRepository.getLocationByCode(locationCode);
  77.             val locations = location.isPresent() ? location.get().flatMap() : new HashMap<String, Location>();
  78.             teams = teams.stream().filter(t -> locations.containsKey(t.getOfficeHours() != null ? t.getOfficeHours().getLocationCode() : null)).toList();
  79.         }

  80.         teams = teams.stream().filter(t -> queryStatusList.contains(t.getStatus())).toList();

  81.         return ResponseEntity.ok(new RestResponsePage<>(convert(teams, Team::convertToResponse)));
  82.     }

  83.     @Operation(summary = "Get Team")
  84.     @ApiResponse(description = "ok")
  85.     @GetMapping("/{id}")
  86.     public ResponseEntity<TeamResponse> getById(@PathVariable UUID id) {
  87.         log.info("Get Team id={}", id);
  88.         return ResponseEntity.ok(service.get(id).convertToResponse());
  89.     }

  90.     @Operation(summary = "Search teams")
  91.     @ApiResponse(description = "Teams fetched")
  92.     @GetMapping("/search/{name}")
  93.     public ResponseEntity<RestResponsePage<TeamResponse>> searchTeamByName(@PathVariable String name) {
  94.         log.info("Received request for Team with the name like {}", name);
  95.         if (name.length() < 3) {
  96.             throw new ValidationException("Search teams must be at least 3 characters");
  97.         }
  98.         var teams = service.search(name);
  99.         log.info("Returned {} teams", teams.size());
  100.         return new ResponseEntity<>(new RestResponsePage<>(convert(teams, Team::convertToResponse)), HttpStatus.OK);
  101.     }

  102.     @Operation(summary = "Create Team v1")
  103.     @ApiResponse(responseCode = "201", description = "Team created")
  104.     @PostMapping
  105.     public ResponseEntity<TeamResponse> createTeam(@RequestBody TeamRequest request) {
  106.         log.info("Create Team v1");
  107.         if (request.getTeamType() != null) request.setTeamOwnershipType( TeamOwnershipType.valueOf(request.getTeamType().name()) );
  108.         return createTeam_v2(request);
  109.     }

  110.     @Operation(summary = "Create Team v2")
  111.     @ApiResponse(responseCode = "201", description = "Team created")
  112.     @PostMapping("v2")
  113.     public ResponseEntity<TeamResponse> createTeam_v2(@RequestBody TeamRequest request) {
  114.         log.info("Create Team v2");
  115.         var team = service.save(request);
  116.         return new ResponseEntity<>(team.convertToResponse(), HttpStatus.CREATED);
  117.     }

  118.     @Operation(summary = "Create Teams")
  119.     @ApiResponse(responseCode = "201", description = "Teams created")
  120.     @Transactional
  121.     @PostMapping("/batch")
  122.     public ResponseEntity<RestResponsePage<TeamResponse>> createTeams(@RequestBody List<TeamRequest> requests) {
  123.         log.info("Create Teams");
  124.         var teams = convert(requests, service::save);
  125.         return new ResponseEntity<>(new RestResponsePage<>(convert(teams, Team::convertToResponse)), HttpStatus.CREATED);
  126.     }

  127.     @Operation(summary = "Update Team", description = "If members is null members will not be updated")
  128.     @ApiResponse(description = "Team updated")
  129.     @PutMapping("/{id}")
  130.     public ResponseEntity<TeamResponse> updateTeam(@PathVariable UUID id, @Valid @RequestBody TeamRequest request) {
  131.         log.debug("Update Team v1 id={}", id);
  132.         if (request.getTeamType() != null) request.setTeamOwnershipType( TeamOwnershipType.valueOf(request.getTeamType().name()) );
  133.         return updateTeam_v2(id, request);
  134.     }

  135.     @Operation(summary = "Update Team", description = "If members is null members will not be updated")
  136.     @ApiResponse(description = "Team updated")
  137.     @PutMapping("v2/{id}")
  138.     public ResponseEntity<TeamResponse> updateTeam_v2(@PathVariable UUID id, @Valid @RequestBody TeamRequest request) {
  139.         log.debug("Update Team v2 id={}", id);
  140.         if (!Objects.equals(id, request.getIdAsUUID())) {
  141.             throw new ValidationException(String.format("id mismatch in request %s and path %s", request.getId(), id));
  142.         }
  143.         var team = service.save(request);
  144.         return ResponseEntity.ok(team.convertToResponse());
  145.     }

  146.     @Operation(summary = "Delete Team")
  147.     @ApiResponse(description = "Team deleted")
  148.     @DeleteMapping("/{id}")
  149.     public ResponseEntity<TeamResponse> deleteTeamById(@PathVariable UUID id) {
  150.         log.info("Delete Team id={}", id);
  151.         var team = service.delete(id);
  152.         return ResponseEntity.ok(team.convertToResponse());
  153.     }

  154.     @Operation(summary = "Get export for teams")
  155.     @ApiResponse(description = "Doc fetched", content = @Content(schema = @Schema(implementation = byte[].class)))
  156.     @Transactional(readOnly = true)
  157.     @GetMapping(value = "/export/{type}", produces = SPREADSHEETML_SHEET_MIME)
  158.     public void getExport(
  159.             HttpServletResponse response,
  160.             @PathVariable("type") SpreadsheetType type,
  161.             @RequestParam(name = "id", required = false) String id
  162.     ) {
  163.         if (type != SpreadsheetType.ALL && id == null) {
  164.             throw new ValidationException("missing id for spreadsheet type " + type);
  165.         }
  166.         byte[] doc = teamExportService.generate(type, id);
  167.         String filename = "teams_" + type + Optional.ofNullable(id).map(s -> "-" + s).orElse("") + ".xlsx";
  168.         response.setContentType(SPREADSHEETML_SHEET_MIME);
  169.         response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename);
  170.         writeDoc(response, doc);
  171.     }

  172.     private void writeDoc(HttpServletResponse response, byte[] doc) {
  173.         try {
  174.             StreamUtils.copy(doc, response.getOutputStream());
  175.             response.flushBuffer();
  176.         } catch (Exception e) {
  177.             throw new TechnicalException("io error", e);
  178.         }
  179.     }

  180.     static class TeamPageResponse extends RestResponsePage<TeamResponse> {

  181.     }

  182. }