ResourceController.java

package no.nav.data.team.resource;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import no.nav.data.common.exceptions.ValidationException;
import no.nav.data.common.rest.RestResponsePage;
import no.nav.data.common.security.SecurityUtils;
import no.nav.data.common.validator.Validator;
import no.nav.data.team.resource.domain.Resource;
import no.nav.data.team.resource.dto.ResourceResponse;
import no.nav.data.team.resource.dto.ResourceUnitsResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;

@Slf4j
@RestController
@RequestMapping("/resource")
@Tag(name = "Resource")
public class ResourceController {

    private final NomClient nomClient;
    private final NomGraphClient nomGraphClient;
    private final NomAzurePictureService nomAzurePictureService;
    private final SecurityUtils securityUtils;

    public ResourceController(NomClient nomClient, NomGraphClient nomGraphClient, NomAzurePictureService nomAzurePictureService, SecurityUtils securityUtils) {
        this.nomClient = nomClient;
        this.nomGraphClient = nomGraphClient;
        this.nomAzurePictureService = nomAzurePictureService;
        this.securityUtils = securityUtils;
    }

    @Operation(summary = "Search resources")
    @ApiResponse(description = "Resources fetched")
    @GetMapping("/search/{name}")
    public ResponseEntity<RestResponsePage<ResourceResponse>> searchResourceName(@PathVariable String name) {
        log.debug("Resource search '{}'", name);
        if (Stream.of(name.split(" ")).sorted().distinct().collect(Collectors.joining("")).length() < 3) {
            throw new ValidationException("Search resource must be at least 3 characters");
        }

        var navidentSearchlist = nomGraphClient.searchForNavidentByName(name);
        var ressurserStream = navidentSearchlist.stream().map(nomClient::getByNavIdent).filter(Optional::isPresent).map(Optional::get);

        var ressursSearchlist = ressurserStream.map(Resource::convertToResponse).toList();
        var responsePage = new RestResponsePage<>(ressursSearchlist, ressursSearchlist.size());

        return new ResponseEntity<>(responsePage, HttpStatus.OK);
    }


    @Operation(summary = "Get Resource")
    @ApiResponse(description = "ok")
    @GetMapping("/{id}")
    public ResponseEntity<ResourceResponse> getById(@PathVariable String id) {
        log.info("Resource get id={}", id);
        var resource = nomClient.getByNavIdent(id);
        return resource.map(value -> ResponseEntity.ok(value.convertToResponse())).orElseGet(() -> ResponseEntity.notFound().build());
    }

    @Operation(summary = "Get Resource Units", description = "Only for team-catalog-frackend")
    @ApiResponse(description = "ok")
    @GetMapping("/{id}/units")
    public ResponseEntity<ResourceUnitsResponse> getUnitsById(@PathVariable String id) {
        securityUtils.assertAuthIsPermittedApp("org","team-catalog-frackend");
        log.info("Resource get units id={}", id);

        try {
            var units = nomGraphClient.getUnits(id);
            return units.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
        } catch (Exception e) {
            log.error("Failed to get units for " + id, e);
            return ResponseEntity.ok(null);
        }
    }

    @Operation(summary = "Get all underlying Ressurser Units for leader", description = "Only for team-catalog-frackend")
    @ApiResponse(description = "OK")
    @GetMapping("/{id}/all-underlying-units")
    public ResponseEntity<ResourceUnitsResponse> allUnderlyingUnits(@PathVariable String id, @RequestParam boolean includeMembers) {
        securityUtils.assertAuthIsPermittedApp("org","team-catalog-frackend");
        try {
            var units = nomGraphClient.getLeaderMembersActiveOnlyV2(id, includeMembers);
            return units.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
        } catch (Exception e) {
            log.error("Failed to get units for leader", e);
            return ResponseEntity.ok(null);
        }
    }

    @Operation(summary = "Get Resources")
    @ApiResponse(description = "ok")
    @PostMapping("/multi")
    public ResponseEntity<RestResponsePage<ResourceResponse>> getById(@RequestBody List<String> ids) {
        log.info("Resource get ids={}", ids);

        var resources = ids.stream()
                .map(nomClient::getByNavIdent)
                .filter(Optional::isPresent)
                .map(Optional::get)
                .map(Resource::convertToResponse)
                .collect(toList());
        return ResponseEntity.ok(new RestResponsePage<>(resources));
    }

    @Operation(summary = "Get Resource Photo")
    @ApiResponse(description = "ok")
    @GetMapping(value = "/{id}/photo", produces = MediaType.IMAGE_JPEG_VALUE)
    public ResponseEntity<byte[]> getPhoto(
            @PathVariable String id,
            @RequestParam(name = "forceUpdate", required = false, defaultValue = "false") boolean forceUpdate
    ) {
        id = StringUtils.upperCase(id);
        if (!Validator.NAV_IDENT_PATTERN.matcher(id).matches()) {
            log.info("Resource get photo id={} invalid id", id);
            return ResponseEntity.notFound().build();
        }
        var photo = nomAzurePictureService.getPhoto(id, forceUpdate);

        if (photo.isEmpty()) {
            log.info("Resource get photo id={} not found", id);
            return ResponseEntity.notFound().build();
        }
        log.info("Resource get photo id={}", id);
        return ResponseEntity.ok(photo.get());
    }


    static class ResourcePageResponse extends RestResponsePage<ResourceResponse> {
    }

}