MemberExportService.java

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

  2. import lombok.RequiredArgsConstructor;
  3. import no.nav.data.common.export.ExcelBuilder;
  4. import no.nav.data.common.utils.DateUtil;
  5. import no.nav.data.common.utils.StreamUtils;
  6. import no.nav.data.common.utils.StringUtils;
  7. import no.nav.data.team.cluster.ClusterService;
  8. import no.nav.data.team.cluster.domain.Cluster;
  9. import no.nav.data.team.member.MemberExportService.Member.Relation;
  10. import no.nav.data.team.member.dto.MemberResponse;
  11. import no.nav.data.team.po.ProductAreaService;
  12. import no.nav.data.team.po.domain.ProductArea;
  13. import no.nav.data.team.resource.NomGraphClient;
  14. import no.nav.data.team.shared.Lang;
  15. import no.nav.data.team.shared.domain.Membered;
  16. import no.nav.data.team.team.TeamService;
  17. import no.nav.data.team.team.domain.Team;
  18. import org.springframework.stereotype.Service;

  19. import java.time.LocalDate;
  20. import java.util.Comparator;
  21. import java.util.List;
  22. import java.util.UUID;
  23. import java.util.stream.Stream;

  24. import static java.util.Comparator.comparing;
  25. import static java.util.Objects.isNull;
  26. import static java.util.Optional.ofNullable;
  27. import static java.util.stream.Collectors.toList;
  28. import static no.nav.data.common.utils.StreamUtils.convert;
  29. import static no.nav.data.common.utils.StreamUtils.filter;
  30. import static no.nav.data.common.utils.StreamUtils.tryFind;
  31. import static org.apache.commons.lang3.StringUtils.EMPTY;

  32. @Service
  33. @RequiredArgsConstructor
  34. public class MemberExportService {

  35.     public enum SpreadsheetType {
  36.         ALL,
  37.         AREA,
  38.         CLUSTER,
  39.         TEAM,
  40.         ROLE,
  41.         LEADER
  42.     }

  43.     private final TeamService teamService;
  44.     private final ProductAreaService productAreaService;
  45.     private final ClusterService clusterService;
  46.     private final NomGraphClient nomGraphClient;

  47.     public byte[] generateSpreadsheet(SpreadsheetType type, String filter) {
  48.         var pas = productAreaService.getAll();
  49.         var clusters = clusterService.getAll();
  50.         var members = switch (type) {
  51.             case ALL -> getAll(pas, clusters);
  52.             case AREA -> getForProductArea(StringUtils.toUUID(filter), pas, clusters);
  53.             case CLUSTER -> getForCluster(StringUtils.toUUID(filter), pas, clusters);
  54.             case TEAM -> mapTeamMembers(List.of(teamService.get(StringUtils.toUUID(filter))), pas, clusters).collect(toList());
  55.             case ROLE -> filter(getAll(pas, clusters), m -> convert(m.member().getRoles(), Enum::name).contains(filter));
  56.             case LEADER -> filter(getAll(pas, clusters), m -> {
  57.                 var leaderMembers = nomGraphClient.getLeaderMembersActiveOnly(filter);
  58.                 return leaderMembers.contains(m.member().getNavIdent());
  59.             });
  60.         };
  61.         return generateFor(members);
  62.     }

  63.     private List<Member> getAll(List<ProductArea> pas, List<Cluster> clusters) {
  64.         return Stream.concat(
  65.                 Stream.concat(
  66.                         mapTeamMembers(teamService.getAll(), pas, clusters),
  67.                         mapPaMembers(pas)
  68.                 ),
  69.                 mapClusterMembers(clusters, pas)
  70.         ).collect(toList());
  71.     }

  72.     private List<Member> getForProductArea(UUID id, List<ProductArea> pas, List<Cluster> clusters) {
  73.         ProductArea productArea = productAreaService.get(id);
  74.         return Stream.concat(Stream.concat(
  75.                 mapPaMembers(List.of(productArea)),
  76.                 mapTeamMembers(teamService.findByProductArea(id).stream().filter(team -> team.getStatus().isActive()).toList(), pas, clusters))
  77.                 , mapClusterMembers(filter(clusters, cl -> productArea.getId().equals(cl.getProductAreaId())), pas)
  78.         ).collect(toList());
  79.     }

  80.     private List<Member> getForCluster(UUID id, List<ProductArea> pas, List<Cluster> clusters) {
  81.         return Stream.concat(
  82.                 mapClusterMembers(List.of(clusterService.get(id)), pas),
  83.                 mapTeamMembers(teamService.findByCluster(id), pas, clusters)
  84.         ).collect(toList());
  85.     }

  86.     private Stream<Member> mapPaMembers(List<ProductArea> productAreas) {
  87.         return productAreas.stream().flatMap(pa -> pa.getMembers().stream().map(m -> new Member(Relation.PA, m.convertToResponse(), null, pa, List.of())));
  88.     }

  89.     private Stream<Member> mapClusterMembers(List<Cluster> clusters, List<ProductArea> productAreas) {
  90.         return clusters.stream().flatMap(cluster -> cluster.getMembers().stream()
  91.                 .map(m -> new Member(Relation.CLUSTER, m.convertToResponse(), null, tryFind(productAreas, pa -> pa.getId().equals(cluster.getProductAreaId())).orElse(null),
  92.                         List.of(cluster))));
  93.     }

  94.     private Stream<Member> mapTeamMembers(List<Team> teams, List<ProductArea> pas, List<Cluster> clusters) {
  95.         return teams.stream().flatMap(t -> t.getMembers().stream().map(m -> {
  96.             ProductArea productArea = t.getProductAreaId() != null ? StreamUtils.find(pas, pa -> pa.getId().equals(t.getProductAreaId())) : null;
  97.             List<Cluster> clustersForTeam = filter(clusters, cluster -> t.getClusterIds().contains(cluster.getId()));
  98.             return new Member(Relation.TEAM, m.convertToResponse(), t, productArea, clustersForTeam);
  99.         }));
  100.     }

  101.     private byte[] generateFor(List<Member> members) {
  102.         var doc = new ExcelBuilder(Lang.MEMBERS);
  103.         doc.addRow()
  104.                 .addCell(Lang.RELATION)
  105.                 .addCell(Lang.AREA)
  106.                 .addCell(Lang.CLUSTER)
  107.                 .addCell(Lang.TEAM)
  108.                 .addCell(Lang.IDENT)
  109.                 .addCell(Lang.GIVEN_NAME)
  110.                 .addCell(Lang.FAMILY_NAME)
  111.                 .addCell(Lang.RESOURCE_TYPE)
  112.                 .addCell(Lang.ROLES)
  113.                 .addCell(Lang.OTHER)
  114.                 .addCell(Lang.EMAIL)
  115.                 .addCell(Lang.START_DATE)
  116.                 .addCell(Lang.END_DATE);

  117.         Comparator<Member> c1 = comparing(m -> ofNullable(m.member.getResource().getFamilyName()).orElse(""));
  118.         Comparator<Member> c2 = c1.thenComparing(m -> ofNullable(m.member.getResource().getGivenName()).orElse(""));
  119.         members.sort(c2);
  120.         members.forEach(m -> add(doc, m));

  121.         return doc.build();
  122.     }

  123.     private void add(ExcelBuilder doc, Member member) {
  124.         doc.addRow()
  125.                 .addCell(member.relationType())
  126.                 .addCell(member.productAreaName())
  127.                 .addCell(member.clusterName())
  128.                 .addCell(member.teamName())
  129.                 .addCell(member.member.getNavIdent())
  130.                 .addCell(member.member.getResource().getGivenName())
  131.                 .addCell(member.member.getResource().getFamilyName())
  132.                 .addCell(member.memberType())
  133.                 .addCell(member.roles())
  134.                 .addCell(member.member.getDescription())
  135.                 .addCell(member.member.getResource().getEmail())
  136.                 .addCell(DateUtil.formatDate(member.member.getResource().getStartDate()))
  137.                 .addCell(shouldHideEndDateIfBeforeNow(member.member.getResource().getEndDate()))
  138.         ;
  139.     }

  140.     private String shouldHideEndDateIfBeforeNow(LocalDate endDate) {
  141.         if (isNull(endDate) || endDate.isAfter(LocalDate.now())) return null;
  142.         else return DateUtil.formatDate(endDate);
  143.     }

  144.     record Member(Relation relation, MemberResponse member, Team team, ProductArea pa, List<Cluster> clusters) {

  145.         enum Relation {
  146.             TEAM(Team.class),
  147.             PA(ProductArea.class),
  148.             CLUSTER(Cluster.class);

  149.             private final Class<? extends Membered> type;

  150.             Relation(Class<? extends Membered> type) {
  151.                 this.type = type;
  152.             }
  153.         }

  154.         public String relationType() {
  155.             return Lang.objectType(relation.type);
  156.         }

  157.         public String productAreaName() {
  158.             return pa != null ? pa.getName() : EMPTY;
  159.         }

  160.         public String clusterName() {
  161.             return clusters.isEmpty() ? EMPTY : String.join(", ", convert(clusters, Cluster::getName));
  162.         }

  163.         public String teamName() {
  164.             return switch (relation) {
  165.                 case TEAM -> team.getName();
  166.                 case PA, CLUSTER -> EMPTY;
  167.             };
  168.         }

  169.         public String memberType() {
  170.             if (member.getResource().getResourceType() == null) {
  171.                 return EMPTY;
  172.             }
  173.             return Lang.memberType(member.getResource().getResourceType());
  174.         }

  175.         public String roles() {
  176.             return String.join(", ", convert(member.getRoles(), Lang::roleName));
  177.         }
  178.     }
  179. }