diff --git a/pom.xml b/pom.xml
index 4c9c1ef..2842d5a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,177 +1,182 @@
-
-
- 4.0.0
-
- com.baloise.azure
- functional-org-baloise
- 1.0-SNAPSHOT
- jar
-
- Baloise Functional Organisation API
-
-
- Baloise
- https://github.com/baloise/
-
-
-
-
- Apache-2.0
- https://www.apache.org/licenses/LICENSE-2.0.txt
- repo
- A business-friendly OSS license
-
-
-
-
- Github
- https://github.com/baloise/functional-org-baloise/issues
-
-
-
- UTF-8
- 17
- 1.27.0
- 3.0.0
- functional-org-baloise
-
-
-
-
-
- org.junit
- junit-bom
- 5.10.1
- pom
- import
-
-
-
-
-
-
-
- com.microsoft.graph
- microsoft-graph
- 5.77.0
-
-
- com.microsoft.azure.functions
- azure-functions-java-library
- ${azure.functions.java.library.version}
-
-
- com.microsoft.azure
- msal4j
- 1.14.1
-
-
- com.azure
- azure-security-keyvault-secrets
- 4.7.3
-
-
- com.azure
- azure-identity
- 1.11.1
-
-
- com.fasterxml.jackson.core
- jackson-databind
- 2.16.1
-
-
-
- org.junit.jupiter
- junit-jupiter
- test
-
-
-
- org.mockito
- mockito-core
- 2.23.4
- test
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.8.1
-
-
- ${java.version}
- ${project.build.sourceEncoding}
-
-
-
- com.microsoft.azure
- azure-functions-maven-plugin
- ${azure.functions.maven.plugin.version}
-
-
- ${functionAppName}
-
- deop-rg-prod-euw-git-ps-funorg
-
-
- westeurope
-
-
-
-
-
- true
-
-
- linux
- 17
-
-
-
- FUNCTIONS_EXTENSION_VERSION
- ~4
-
-
-
-
-
- package-functions
-
- package
-
-
-
-
-
- maven-surefire-plugin
- 3.2.1
-
-
-
- maven-clean-plugin
- 3.1.0
-
-
-
- obj
-
-
-
-
-
-
-
+
+
+ 4.0.0
+
+ com.baloise.azure
+ functional-org-baloise
+ 1.0-SNAPSHOT
+ jar
+
+ Baloise Functional Organisation API
+
+
+ Baloise
+ https://github.com/baloise/
+
+
+
+
+ Apache-2.0
+ https://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+ A business-friendly OSS license
+
+
+
+
+ Github
+ https://github.com/baloise/functional-org-baloise/issues
+
+
+
+ UTF-8
+ 17
+ 1.27.0
+ 3.1.0
+ functional-org-baloise
+
+
+
+
+
+ org.junit
+ junit-bom
+ 5.10.1
+ pom
+ import
+
+
+ com.azure
+ azure-sdk-bom
+ 1.2.22
+ pom
+ import
+
+
+
+
+
+
+
+ com.microsoft.azure
+ msal4j
+ 1.14.3
+
+
+ com.microsoft.graph
+ microsoft-graph
+ 6.5.1
+
+
+ com.microsoft.azure.functions
+ azure-functions-java-library
+ ${azure.functions.java.library.version}
+
+
+ com.azure
+ azure-security-keyvault-secrets
+
+
+ com.azure
+ azure-identity
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.16.1
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+
+ org.mockito
+ mockito-core
+ 2.23.4
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+ com.microsoft.azure
+ azure-functions-maven-plugin
+ ${azure.functions.maven.plugin.version}
+
+
+ ${functionAppName}
+
+ deop-rg-prod-euw-git-ps-funorg
+
+
+ westeurope
+
+
+
+
+
+ true
+
+
+ linux
+ 17
+
+
+
+ FUNCTIONS_EXTENSION_VERSION
+ ~4
+
+
+
+
+
+ package-functions
+
+ package
+
+
+
+
+
+ maven-surefire-plugin
+ 3.2.1
+
+
+
+ maven-clean-plugin
+ 3.1.0
+
+
+
+ obj
+
+
+
+
+
+
+
diff --git a/src/main/java/com/baloise/azure/FunctionalOrgEndpoint.java b/src/main/java/com/baloise/azure/FunctionalOrgEndpoint.java
index 661653c..bbbd3be 100644
--- a/src/main/java/com/baloise/azure/FunctionalOrgEndpoint.java
+++ b/src/main/java/com/baloise/azure/FunctionalOrgEndpoint.java
@@ -1,297 +1,215 @@
-package com.baloise.azure;
-
-import static java.lang.String.format;
-import static java.util.Arrays.stream;
-import static java.util.function.Predicate.not;
-import static java.util.stream.Collectors.joining;
-
-import java.io.IOException;
-import java.text.ParseException;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.stream.Collectors;
-
-import com.azure.identity.ClientSecretCredentialBuilder;
-import com.baloise.funorg.Role;
-import com.baloise.funorg.Team;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.microsoft.azure.functions.ExecutionContext;
-import com.microsoft.azure.functions.HttpMethod;
-import com.microsoft.azure.functions.HttpRequestMessage;
-import com.microsoft.azure.functions.HttpResponseMessage;
-import com.microsoft.azure.functions.HttpResponseMessage.Builder;
-import com.microsoft.azure.functions.HttpStatus;
-import com.microsoft.azure.functions.annotation.AuthorizationLevel;
-import com.microsoft.azure.functions.annotation.BindingName;
-import com.microsoft.azure.functions.annotation.FunctionName;
-import com.microsoft.azure.functions.annotation.HttpTrigger;
-import com.microsoft.graph.authentication.TokenCredentialAuthProvider;
-import com.microsoft.graph.models.Group;
-import com.microsoft.graph.models.User;
-
-/**
- * Azure Functions with HTTP Trigger.
- */
-public class FunctionalOrgEndpoint {
- /**
- * This function listens at endpoint "/api/Hello". Two ways to invoke it using
- * "curl" command in bash: 1. curl -d "HTTP Body" {your host}/api/Hello 2. curl
- * "{your host}/api/Hello?name=HTTP%20Query"
- */
-
- Vault lazyVault = null;
- Graph lazygraph = null;
- ObjectMapper objectMapper = new ObjectMapper();
-
- Vault vault() {
- if(lazyVault == null) {
- lazyVault = new Vault();
- }
- return lazyVault;
- }
-
- Graph graph() {
- if(lazygraph == null) {
- lazygraph = new Graph(new TokenCredentialAuthProvider( new ClientSecretCredentialBuilder()
- .authorityHost(AzureProperties.authority())
- .tenantId(AzureProperties.tenantId()).clientId(AzureProperties.clientId())
- .clientSecret(vault().getSecret(AzureProperties.clientSecretName(), true)).build()));
- }
- return lazygraph;
- }
-
- @FunctionName("V1")
- public HttpResponseMessage v1(
- @HttpTrigger(
- name = "req",
- methods = { HttpMethod.GET, HttpMethod.POST },
- authLevel = AuthorizationLevel.ANONYMOUS,
- route = "V1/{unit=null}/{team=null}"
- )
- HttpRequestMessage> request,
- final ExecutionContext context,
- @BindingName("unit") String unit,
- @BindingName("team") String team
- ) {
- try {
-
-
- if(!"null".equals(team) && "avatar".equals(unit)) {
- return createAvatarResponse(request, team);
- }
- if(!"null".equals(team)) {
- return createTeamResponse(request, context, unit, team);
- }
-
- if(!"null".equals(unit)) {
- return createUnitResponse(request, context, unit);
- }
-
- return createRootResponse(request, context);
-
- } catch (IOException e) {
- context.getLogger().warning(e.getLocalizedMessage());
- return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getLocalizedMessage()).build();
- } catch (Throwable t) {
- context.getLogger().log(Level.WARNING, t.getLocalizedMessage(), t);
- throw t;
- }
- }
-
- private HttpResponseMessage createAvatarResponse(HttpRequestMessage> request, String id) throws IOException {
- byte[] avatar = graph().avatar(id);
- String myETag = String.valueOf(Arrays.hashCode(avatar));
- String theirETag = ignoreKeyCase(request.getHeaders()).get("If-None-Match");
- boolean sameEtag = Objects.equals(myETag, theirETag);
- Builder response = request
- .createResponseBuilder(sameEtag? HttpStatus.NOT_MODIFIED : HttpStatus.OK)
- .header("Content-Type","image/jpeg")
- .header("ETag",myETag);
- if(!sameEtag) {
- response = response
- .header("Content-Length",String.valueOf(avatar.length))
- .body(avatar);
- }
- return response.build();
- }
-
- private Map ignoreKeyCase(Map mixedMap) {
- Map lowMap = new HashMap<>() {
- @Override
- public String get(Object key) {
- return super.get(key.toString().toLowerCase());
- }
- };
- mixedMap.entrySet().stream().forEach(e->lowMap.put(e.getKey().toLowerCase(), e.getValue()));
- return lowMap;
- }
-
- private HttpResponseMessage createRootResponse(HttpRequestMessage> request, ExecutionContext context)
- throws JsonProcessingException {
- return request.createResponseBuilder(HttpStatus.OK)
- .header("Content-Type","application/json; charset=UTF-8")
- .body(
- objectMapper.writeValueAsString(
- Map.of("units",
- graph().getTeams().stream()
- .map(g -> Team.parse(context.getLogger(), g.displayName))
- .filter(Objects::nonNull)
- .map(t ->
- Map.of(
- "name", t.unit(),
- "url", getCleanUri(request)+"/"+ t.unit()
- )
- )
- .distinct()
- .collect(Collectors.toList())
- ))
- ).build();
- }
-
- private HttpResponseMessage createUnitResponse(HttpRequestMessage> request, ExecutionContext context, String unit) throws JsonProcessingException {
- return request.createResponseBuilder(HttpStatus.OK)
- .header("Content-Type","application/json; charset=UTF-8")
- .body(
- objectMapper.writeValueAsString(
- Map.of("teams",
- graph().getTeams(unit+"-").stream()
- .map(g -> Team.parse(context.getLogger(), g.displayName))
- .filter(Objects::nonNull)
- .map(t ->
- Map.of(
- "name", t.name(),
- "unit", t.unit(),
- "url", format("%s/%s/%s", getPath(request), t.unit(),t.name())
- )
- )
- .distinct()
- .collect(Collectors.toList())
- ))
- ).build();
- }
-
- private HttpResponseMessage createTeamResponse(HttpRequestMessage> request, ExecutionContext context, String unit, String team) throws JsonProcessingException {
- Map> name2team = new HashMap<>();
-
- for (Group group : graph().getTeams(unit+"-"+team)) {
- try {
- Team t = Team.parse(group.displayName);
- Map tmp = name2team.get(t.name());
- if(tmp== null) {
- tmp = Map.of(
- "name", t.name(),
- "unit", t.unit(),
- "url", getPath(request)+"/"+t.name(),
- "members" , loadAndMapMembers(group, t.internal(), request.getQueryParameters().get("expand"))
- );
- name2team.put(t.name(), tmp);
- } else {
- @SuppressWarnings("unchecked")
- List