Skip to content

Commit 75b65ce

Browse files
committed
feature: Implement user retrieval and enhance organization status in Dashboard #deploy-test-dolly-backend #deploy-dolly-backend
1 parent 51d837a commit 75b65ce

7 files changed

Lines changed: 130 additions & 7 deletions

File tree

apps/dolly-backend/src/main/java/no/nav/dolly/consumer/brukerservice/BrukerServiceConsumer.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22

33
import lombok.extern.slf4j.Slf4j;
44
import no.nav.dolly.config.Consumers;
5+
import no.nav.dolly.consumer.brukerservice.command.BrukerServiceGetAlleCommand;
56
import no.nav.dolly.consumer.brukerservice.command.BrukerServiceGetTilgangCommand;
7+
import no.nav.dolly.consumer.brukerservice.dto.BrukerDTO;
68
import no.nav.dolly.consumer.brukerservice.dto.TilgangDTO;
79
import no.nav.testnav.libs.securitycore.domain.ServerProperties;
810
import no.nav.testnav.libs.standalone.reactivesecurity.exchange.TokenExchange;
911
import org.springframework.stereotype.Service;
1012
import org.springframework.web.reactive.function.client.WebClient;
13+
import reactor.core.publisher.Flux;
1114
import reactor.core.publisher.Mono;
1215

1316
@Service
@@ -37,4 +40,11 @@ public Mono<TilgangDTO> getKollegaerIOrganisasjon(String brukerId) {
3740
.flatMap(token ->
3841
new BrukerServiceGetTilgangCommand(webClient, brukerId, token.getTokenValue()).call());
3942
}
43+
44+
public Flux<BrukerDTO> getAlleBrukere() {
45+
46+
return tokenService.exchange(serverProperties)
47+
.flatMapMany(token ->
48+
new BrukerServiceGetAlleCommand(webClient, token.getTokenValue()).call());
49+
}
4050
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package no.nav.dolly.consumer.brukerservice.command;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import lombok.extern.slf4j.Slf4j;
5+
import no.nav.dolly.consumer.brukerservice.dto.BrukerDTO;
6+
import no.nav.testnav.libs.reactivecore.web.WebClientError;
7+
import no.nav.testnav.libs.reactivecore.web.WebClientHeader;
8+
import org.springframework.web.reactive.function.client.WebClient;
9+
import reactor.core.publisher.Flux;
10+
11+
import java.util.concurrent.Callable;
12+
13+
@RequiredArgsConstructor
14+
@Slf4j
15+
public class BrukerServiceGetAlleCommand implements Callable<Flux<BrukerDTO>> {
16+
17+
private static final String BRUKEROVERSIKT_URL = "/api/v2/brukere/alle";
18+
19+
private final WebClient webClient;
20+
private final String token;
21+
22+
@Override
23+
public Flux<BrukerDTO> call() {
24+
return webClient.get()
25+
.uri(uriBuilder -> uriBuilder
26+
.path(BRUKEROVERSIKT_URL)
27+
.build())
28+
.headers(WebClientHeader.bearer(token))
29+
.retrieve()
30+
.bodyToFlux(BrukerDTO.class)
31+
.doOnError(WebClientError.logTo(log))
32+
.retryWhen(WebClientError.is5xxException());
33+
}
34+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package no.nav.dolly.consumer.brukerservice.dto;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Builder;
5+
import lombok.Data;
6+
import lombok.NoArgsConstructor;
7+
8+
@Data
9+
@Builder
10+
@NoArgsConstructor
11+
@AllArgsConstructor
12+
public class BrukerDTO {
13+
14+
private String id;
15+
private String brukernavn;
16+
private String organisasjonsnummer;
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package no.nav.dolly.domain.projection;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Builder;
5+
import lombok.Data;
6+
import lombok.NoArgsConstructor;
7+
8+
@Data
9+
@Builder
10+
@NoArgsConstructor
11+
@AllArgsConstructor
12+
public class OrganisasjonFragment {
13+
14+
private Long antall;
15+
private String interval;
16+
private String brukerId;
17+
}

apps/dolly-backend/src/main/java/no/nav/dolly/provider/DashboardController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import io.swagger.v3.oas.annotations.Operation;
44
import lombok.RequiredArgsConstructor;
5-
import no.nav.dolly.consumer.altinn3.dto.Altinn3TilgangDTO;
5+
import no.nav.dolly.domain.dto.DashboardOrganisasjonerDTO;
66
import no.nav.dolly.domain.dto.DashboardPersonerDTO;
77
import no.nav.dolly.domain.dto.DashboardTeamsDTO;
88
import no.nav.dolly.service.DashboardService;
@@ -34,7 +34,7 @@ public Flux<DashboardTeamsDTO> getDashboardTeams() {
3434

3535
@GetMapping(value = "/organisasjoner")
3636
@Operation(description = "Henter status for organisasjoner fra Altinn, og antall unike personer som har bestilt")
37-
public Flux<Altinn3TilgangDTO> getDashboardOrganisasjoner() {
37+
public Flux<DashboardOrganisasjonerDTO> getDashboardOrganisasjoner() {
3838

3939
return dashboardService.getOrganisasjonerStatus();
4040
}

apps/dolly-backend/src/main/java/no/nav/dolly/repository/BestillingRepository.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import no.nav.dolly.domain.jpa.Bestilling;
44
import no.nav.dolly.domain.projection.BestillingerFragment;
5+
import no.nav.dolly.domain.projection.OrganisasjonFragment;
56
import no.nav.dolly.domain.projection.RsBestillingFragment;
67
import no.nav.dolly.domain.projection.TeamFragment;
78
import org.springframework.data.domain.Pageable;
@@ -179,4 +180,14 @@ select count(*) antall, to_char(b.sist_oppdatert, 'YYYY-MM') interval, br.epost
179180
order by interval desc;
180181
""")
181182
Flux<TeamFragment> findBestillingerForTeamsOrderBySistOppdatert();
183+
184+
@Query("""
185+
select count(*) antall, to_char(b.sist_oppdatert, 'YYYY-MM') interval, br.bruker_id brukerId
186+
from bestilling b
187+
join bruker br on br.id = b.bruker_id
188+
and br.brukertype = 'BANKID'
189+
group by interval, brukerId
190+
order by interval desc;
191+
""")
192+
Flux<OrganisasjonFragment> findBestillingerForOrganisasjonerOrderBySistOppdatert();
182193
}

apps/dolly-backend/src/main/java/no/nav/dolly/service/DashboardService.java

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
import lombok.extern.slf4j.Slf4j;
55
import no.nav.dolly.consumer.altinn3.Altinn3TilgangServiceConsumer;
66
import no.nav.dolly.consumer.altinn3.dto.Altinn3TilgangDTO;
7+
import no.nav.dolly.consumer.brukerservice.BrukerServiceConsumer;
8+
import no.nav.dolly.consumer.brukerservice.dto.BrukerDTO;
79
import no.nav.dolly.consumer.teamkatalog.TeamkatalogConsumer;
810
import no.nav.dolly.consumer.teamkatalog.dto.TeamkatalogDTO;
911
import no.nav.dolly.domain.dto.DashboardOrganisasjonerDTO;
1012
import no.nav.dolly.domain.dto.DashboardPersonerDTO;
1113
import no.nav.dolly.domain.dto.DashboardTeamsDTO;
1214
import no.nav.dolly.domain.jpa.Bruker;
1315
import no.nav.dolly.domain.projection.BestillingerFragment;
16+
import no.nav.dolly.domain.projection.OrganisasjonFragment;
1417
import no.nav.dolly.domain.projection.TeamFragment;
1518
import no.nav.dolly.repository.BestillingRepository;
1619
import no.nav.dolly.repository.BrukerRepository;
@@ -37,10 +40,11 @@ public class DashboardService {
3740

3841
private static final String INGEN_TEAM = "Tilhører ikke noe team";
3942

43+
private final Altinn3TilgangServiceConsumer altinn3TilgangServiceConsumer;
4044
private final BestillingRepository bestillingRepository;
4145
private final BrukerRepository brukerRepository;
46+
private final BrukerServiceConsumer brukerServiceConsumer;
4247
private final TeamkatalogConsumer teamkatalogConsumer;
43-
private final Altinn3TilgangServiceConsumer altinn3TilgangServiceConsumer;
4448

4549
public Flux<DashboardPersonerDTO> getPersonerStatus() {
4650

@@ -100,7 +104,7 @@ private static long sumByStatus(List<BestillingerFragment> fragments,
100104
}
101105

102106
private static Map<String, Set<String>> groupFragmentsByTeam(List<TeamFragment> fragments,
103-
Map<String, List<String>> teams) {
107+
Map<String, List<String>> teams) {
104108

105109
var grouped = new HashMap<String, Set<String>>();
106110
fragments.forEach(fragment -> {
@@ -111,9 +115,39 @@ private static Map<String, Set<String>> groupFragmentsByTeam(List<TeamFragment>
111115
return grouped;
112116
}
113117

114-
public Flux<Altinn3TilgangDTO> getOrganisasjonerStatus() {
118+
public Flux<DashboardOrganisasjonerDTO> getOrganisasjonerStatus() {
115119

116-
117-
return altinn3TilgangServiceConsumer.getOrganisasjoner();
120+
return Mono.zip(altinn3TilgangServiceConsumer.getOrganisasjoner()
121+
.collect(Collectors.toMap(Altinn3TilgangDTO::getOrganisasjonsnummer, Altinn3TilgangDTO::getNavn)),
122+
brukerServiceConsumer.getAlleBrukere()
123+
.collect(Collectors.toMap(BrukerDTO::getId, BrukerDTO::getOrganisasjonsnummer)))
124+
.flatMapMany(oppslag -> bestillingRepository.findBestillingerForOrganisasjonerOrderBySistOppdatert()
125+
.groupBy(OrganisasjonFragment::getInterval)
126+
.flatMap(Flux::collectList)
127+
.flatMap(fragments -> {
128+
var organisasjoner = new HashMap<String, Set<String>>();
129+
fragments.forEach(fragment -> {
130+
var orgNummer = oppslag.getT2().get(fragment.getBrukerId());
131+
organisasjoner.computeIfAbsent(orgNummer, _ -> new HashSet<>())
132+
.add(fragment.getBrukerId());
133+
});
134+
return Mono.just(organisasjoner)
135+
.zipWith(Mono.just(fragments.getFirst().getInterval()));
136+
})
137+
.map(organisasjoner -> DashboardOrganisasjonerDTO.builder()
138+
.interval(organisasjoner.getT2())
139+
.organisasjoner(organisasjoner.getT1().entrySet().stream()
140+
.map(entry -> new DashboardOrganisasjonerDTO.Entry(
141+
entry.getKey(),
142+
oppslag.getT1().getOrDefault(entry.getKey(), "Ukjent organisasjon"),
143+
entry.getValue().size()))
144+
.sorted(Comparator.comparing(DashboardOrganisasjonerDTO.Entry::getNavn))
145+
.toList())
146+
.totaltAntallOrganisasjoner(organisasjoner.getT1().size())
147+
.totaltUnikeBrukere((int) organisasjoner.getT1().values().stream()
148+
.distinct()
149+
.count())
150+
.build()))
151+
.sort(Comparator.comparing(DashboardOrganisasjonerDTO::getInterval).reversed());
118152
}
119153
}

0 commit comments

Comments
 (0)