MemberController.java
package no.nav.data.team.member;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import no.nav.data.common.TeamCatalogProps;
import no.nav.data.common.exceptions.TechnicalException;
import no.nav.data.common.exceptions.ValidationException;
import no.nav.data.team.cluster.domain.Cluster;
import no.nav.data.team.cluster.dto.ClusterResponse;
import no.nav.data.team.member.MemberExportService.SpreadsheetType;
import no.nav.data.team.member.dto.MembershipResponse;
import no.nav.data.team.po.ProductAreaService;
import no.nav.data.team.po.domain.ProductArea;
import no.nav.data.team.po.dto.ProductAreaResponse;
import no.nav.data.team.resource.NomClient;
import no.nav.data.team.resource.NomGraphClient;
import no.nav.data.team.resource.domain.ResourceRepository;
import no.nav.data.team.team.domain.Team;
import no.nav.data.team.team.dto.TeamResponse;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.util.Objects.isNull;
import static no.nav.data.common.export.ExcelBuilder.SPREADSHEETML_SHEET_MIME;
import static no.nav.data.common.utils.StreamUtils.convert;
@Slf4j
@RestController
@RequestMapping("/member")
@Tag(name = "Member", description = "Member endpoint")
public class MemberController {
private final ResourceRepository resourceRepository;
private final MemberExportService memberExportService;
private final TeamCatalogProps teamCatalogProps;
private final NomGraphClient nomGraphClient;
private final ProductAreaService productAreaService;
private final NomClient nomClient;
public MemberController(ResourceRepository resourceRepository,
MemberExportService memberExportService,
TeamCatalogProps teamCatalogProps,
NomGraphClient nomGraphClient,
ProductAreaService productAreaService, NomClient nomClient) {
this.resourceRepository = resourceRepository;
this.memberExportService = memberExportService;
this.teamCatalogProps = teamCatalogProps;
this.nomGraphClient = nomGraphClient;
this.productAreaService = productAreaService;
this.nomClient = nomClient;
}
@Operation(summary = "Get Membership")
@ApiResponse(description = "ok")
@GetMapping("/membership/{id}")
public ResponseEntity<MembershipResponse> getMembership(@PathVariable String id) {
log.info("Get memberships for navident {}",id);
var memberships = resourceRepository.findByMemberIdent(id);
return ResponseEntity.ok(new MembershipResponse(
convert(memberships.teams(), Team::convertToResponse),
convert(memberships.productAreas(), this::convertProductAreaToReponse),
convert(memberships.clusters(), Cluster::convertToResponse)
));
}
@Operation(summary = "Get Membership basert på ressurs sin epost")
@ApiResponse(description = "ok")
@GetMapping("/membership/byUserEmail")
public ResponseEntity<MembershipResponse> getMembershipForUserByEmail(@RequestParam String email) {
log.info("Get memberships for bruker med epost {}", email);
var user = nomClient.getByEmail(email);
if (user.isEmpty()) {
return ResponseEntity.notFound().build();
}
return getMembership(user.get().getNavIdent());
}
@Operation(summary = "Get Memberships")
@ApiResponse(description = "ok")
@PostMapping("/memberships")
public ResponseEntity<Map<String, MembershipResponse>> getAllMemberships(@RequestBody List<String> navidenter) {
var memberships = resourceRepository.findAllByMemberIdents(navidenter);
Map<String, MembershipResponse> membershipResponseMap = memberships.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey, membership -> new MembershipResponse(
convert(membership.getValue().teams(), Team::convertToResponse),
convert(membership.getValue().productAreas(), this::convertProductAreaToReponse),
convert(membership.getValue().clusters(), Cluster::convertToResponse))));
Map<UUID, Map<String, String>> productAreaToAvdelingMap = membershipResponseMap.values().stream()
.flatMap(membership -> {
var clusterPAs = membership.getClusters().stream()
.map(ClusterResponse::getProductAreaId)
.filter(Objects::nonNull);
var teamPAs = membership.getTeams().stream()
.map(TeamResponse::getProductAreaId)
.filter(Objects::nonNull);
var paPAs = membership.getProductAreas().stream()
.map(ProductAreaResponse::getId)
.filter(Objects::nonNull);
return Stream.of(clusterPAs, teamPAs, paPAs).flatMap(s -> s);
})
.distinct()
.map(productAreaService::get)
.filter(Objects::nonNull)
.filter(pa -> pa.getAvdelingNomId() != null)
.collect(Collectors.toMap(
ProductArea::getId,
pa -> {
var orgEnhet = nomGraphClient.getOrgEnhet(pa.getAvdelingNomId());
return orgEnhet.map(oe -> Map.of(
"avdelingNomId", oe.getId(),
"avdelingNavn", oe.getNavn()
)).orElse(Map.of());
},
(existing, replacement) -> existing
));
membershipResponseMap.values().forEach(response -> {
log.info("Getting clusters");
response.getClusters().forEach(cluster -> {
var productAreaId = cluster.getProductAreaId();
if (isNull(productAreaId)) return;
var nomAvdeling = productAreaToAvdelingMap.getOrDefault(productAreaId, Map.of());
var avdelingNomId = nomAvdeling.get("avdelingNomId");
var avdelingNavn = nomAvdeling.get("avdelingNavn");
cluster.setAvdelingNavn(avdelingNavn);
cluster.setAvdelingNomId(avdelingNomId);
});
log.info("Getting teams");
response.getTeams().forEach(team -> {
var productAreaId = team.getProductAreaId();
if (isNull(team.getProductAreaId())) return;
var nomAvdeling = productAreaToAvdelingMap.getOrDefault(productAreaId, Map.of());
var avdelingNomId = nomAvdeling.get("avdelingNomId");
var avdelingNavn = nomAvdeling.get("avdelingNavn");
team.setAvdelingNomId(avdelingNomId);
team.setAvdelingNavn(avdelingNavn);
});
log.info("Getting productAreas");
response.getProductAreas().forEach(productArea -> {
log.info("Found product area {}", productArea);
var nomAvdeling = productAreaToAvdelingMap.getOrDefault(productArea.getId(), Map.of());
productArea.setAvdelingNavn(nomAvdeling.get("avdelingNavn"));
});
});
return ResponseEntity.ok(membershipResponseMap);
}
@Operation(summary = "Get export for members")
@ApiResponse(description = "Doc fetched", content = @Content(schema = @Schema(implementation = byte[].class)))
@Transactional(readOnly = true)
@GetMapping(value = "/export/{type}", produces = SPREADSHEETML_SHEET_MIME)
public void getExport(
HttpServletResponse response,
@PathVariable("type") SpreadsheetType type,
@RequestParam(name = "id", required = false) String id
) {
log.info("Export spreadsheet {}, {}", type, id);
if (type != SpreadsheetType.ALL && id == null) {
throw new ValidationException("missing id for spreadsheet type " + type);
}
byte[] doc = memberExportService.generateSpreadsheet(type, id);
String filename = "resources_" + type + Optional.ofNullable(id).map(s -> "_" + s).orElse("") + ".xlsx";
response.setContentType(SPREADSHEETML_SHEET_MIME);
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename);
writeDoc(response, doc);
}
private void writeDoc(HttpServletResponse response, byte[] doc) {
try {
StreamUtils.copy(doc, response.getOutputStream());
response.flushBuffer();
} catch (Exception e) {
throw new TechnicalException("io error", e);
}
}
private ProductAreaResponse convertProductAreaToReponse(ProductArea pa){
return pa.convertToResponse(teamCatalogProps.getDefaultProductareaUuid());
}
}