Skip to content
Snippets Groups Projects
Commit 26fd2fb5 authored by OZGCloud's avatar OZGCloud
Browse files

Merge pull request 'OZG-3034-Mailtext-fuer-Benachrichtigung' (#760) from...

Merge pull request 'OZG-3034-Mailtext-fuer-Benachrichtigung' (#760) from OZG-3034-Mailtext-fuer-Benachrichtigung into master

Reviewed-on: https://git.ozg-sh.de/ozgcloud-app/alfa/pulls/760


Reviewed-by: default avatarOZGCloud <ozgcloud@mgm-tp.com>
parents 76cdfbed c0b7d481
No related branches found
No related tags found
No related merge requests found
Showing
with 591 additions and 0 deletions
package de.ozgcloud.alfa.resource;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown=true)
public class OzgcloudResource {
}
package de.ozgcloud.alfa.resource;
import java.util.Collection;
import java.util.Optional;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import de.ozgcloud.alfa.common.errorhandling.ResourceNotFoundException;
import de.ozgcloud.common.errorhandling.TechnicalException;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping(OzgcloudResourceController.PATH)
@RequiredArgsConstructor
public class OzgcloudResourceController {
static final String PATH = "/api/resources";
static final String PARAM_URI = "uri";
private final Collection<OzgcloudResourceURIResolver> resolvers;
private final OzgcloudResourceModelAssembler assembler;
@GetMapping(params = PARAM_URI)
public RepresentationModel<EntityModel<OzgcloudResource>> getOzgcloudResource(@RequestParam @NotBlank String uri) {
var resourceLink = resolveUri(uri);
if (resourceLink.isEmpty()) {
throw new ResourceNotFoundException(OzgcloudResource.class, uri);
}
return assembler.toModel(new OzgcloudResourceURIResolveResult(uri, resourceLink.get()));
}
private Optional<Link> resolveUri(String uri) {
return resolvers.stream()
.map(resolver -> resolver.resolve(uri))
.flatMap(Optional::stream)
.reduce((r1, r2) -> {
throw new TechnicalException("Multiple resolvers accepted uri " + uri);
});
}
}
package de.ozgcloud.alfa.resource;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.server.RepresentationModelAssembler;
import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
class OzgcloudResourceModelAssembler implements RepresentationModelAssembler<OzgcloudResourceURIResolveResult, EntityModel<OzgcloudResource>> {
@Override
public EntityModel<OzgcloudResource> toModel(OzgcloudResourceURIResolveResult uriResolveResult) {
return EntityModel.of(new OzgcloudResource()).add(getSelfLink(uriResolveResult.getResourceURI())).add(uriResolveResult.getResourceLink());
}
private Link getSelfLink(String uri) {
return linkTo(methodOn(OzgcloudResourceController.class).getOzgcloudResource(uri)).withSelfRel();
}
}
package de.ozgcloud.alfa.resource;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.server.RepresentationModelProcessor;
import org.springframework.stereotype.Component;
import de.ozgcloud.alfa.Root;
@Component
class OzgcloudResourceRootProcessor implements RepresentationModelProcessor<EntityModel<Root>> {
static final String REL_RESOURCE = "resource";
@Override
public EntityModel<Root> process(EntityModel<Root> model) {
return model.add(linkTo(methodOn(OzgcloudResourceController.class).getOzgcloudResource(null)).withRel(REL_RESOURCE));
}
}
package de.ozgcloud.alfa.resource;
import org.springframework.hateoas.Link;
import lombok.Builder;
import lombok.Getter;
import lombok.ToString;
@Builder
@Getter
@ToString
public class OzgcloudResourceURIResolveResult {
private final String resourceURI;
private final Link resourceLink;
}
package de.ozgcloud.alfa.resource;
import java.util.Optional;
import org.springframework.hateoas.Link;
public interface OzgcloudResourceURIResolver {
Optional<Link> resolve(String uri);
}
package de.ozgcloud.alfa.vorgang;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
import java.util.Optional;
import java.util.regex.Pattern;
import org.springframework.hateoas.Link;
import org.springframework.stereotype.Component;
import de.ozgcloud.alfa.resource.OzgcloudResourceURIResolver;
@Component
class VorgangURIResolver implements OzgcloudResourceURIResolver {
static final String REL_NAME = "vorgang";
private final Pattern pattern = Pattern.compile("ozgcloud://[^/]+/vorgangs/([0-9a-fA-F]+)");
@Override
public Optional<Link> resolve(String uri) {
var matcher = pattern.matcher(uri);
if (!matcher.matches()) {
return Optional.empty();
}
var vorgangId = matcher.group(1);
return Optional.of(linkTo(VorgangController.class).slash(vorgangId).withRel(REL_NAME));
}
}
package de.ozgcloud.alfa;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import org.hamcrest.core.StringEndsWith;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import de.ozgcloud.alfa.common.user.CurrentUserService;
import de.ozgcloud.alfa.common.user.UserProfileTestFactory;
@AutoConfigureMockMvc
@SpringBootTest
@WithMockUser
class RootControllerITCase {
@MockBean
private CurrentUserService currentUserService;
@Autowired
private MockMvc mockMvc;
@BeforeEach
void init() {
when(currentUserService.getUser()).thenReturn(UserProfileTestFactory.create());
}
@Nested
class TestProcess {
@Test
void shouldAddResourceLink() throws Exception {
var response = doRequest();
response.andExpect(jsonPath("$._links.resource.href").value(StringEndsWith.endsWith("/api/resources?uri={uri}")));
}
}
private ResultActions doRequest() throws Exception {
return mockMvc.perform(get(RootController.PATH)).andExpect(status().isOk());
}
}
package de.ozgcloud.alfa.resource;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import org.hamcrest.core.StringEndsWith;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import de.ozgcloud.alfa.common.AlfaTestUtils;
import lombok.SneakyThrows;
@AutoConfigureMockMvc
@SpringBootTest
@WithMockUser
class OzgcloudResourceControllerITCase {
@Autowired
private MockMvc mockMvc;
@Nested
class TestGetOzgcloudResource {
private static final String VORGANG_ID = AlfaTestUtils.createMongoDbObjectId();
@Test
void shouldReturnStatusOk() throws Exception {
var response = doRequest("ozgcloud://test.de/vorgangs/" + VORGANG_ID);
response.andExpect(status().isOk());
}
@Test
void shouldHaveVorgangLink() throws Exception {
var response = doRequest("ozgcloud://test.de/vorgangs/" + VORGANG_ID);
response.andExpect(jsonPath("$._links.vorgang.href").value(StringEndsWith.endsWith("/api/vorgangs/" + VORGANG_ID)));
}
@Test
void shouldHaveSelfLink() throws Exception {
var uri = "ozgcloud://test.de/vorgangs/" + VORGANG_ID;
var encodedUri = URLEncoder.encode(uri, StandardCharsets.UTF_8);
var response = doRequest(uri);
response.andExpect(jsonPath("$._links.self.href").value(StringEndsWith.endsWith(OzgcloudResourceController.PATH + "?uri=" + encodedUri)));
}
@Test
void shouldReturnStatusNotFound() throws Exception {
var response = doRequest("dummy://test.de");
response.andExpect(status().isNotFound());
}
@Test
void shouldReturnBadRequestOnNoRequestParam() throws Exception {
var response = doRequestWithQueryString("");
response.andExpect(status().isBadRequest());
}
@Test
void shouldReturnBadRequestOnEmptyUri() throws Exception {
var response = doRequestWithQueryString("?uri=");
response.andExpect(status().isBadRequest());
}
@SneakyThrows
private ResultActions doRequest(String uri) {
return doRequestWithQueryString("?uri=" + uri);
}
@SneakyThrows
private ResultActions doRequestWithQueryString(String queryString) {
return mockMvc.perform(get(OzgcloudResourceController.PATH + queryString));
}
}
}
package de.ozgcloud.alfa.resource;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatcher;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.RepresentationModel;
import de.ozgcloud.alfa.common.errorhandling.ResourceNotFoundException;
import de.ozgcloud.common.errorhandling.TechnicalException;
import lombok.SneakyThrows;
class OzgcloudResourceControllerTest {
@Mock
private OzgcloudResourceURIResolver resourceAResolver;
@Mock
private OzgcloudResourceURIResolver resourceBResolver;
@Spy
private Collection<OzgcloudResourceURIResolver> resourceResolvers = new ArrayList<>();
@Mock
private OzgcloudResourceModelAssembler assembler;
@InjectMocks
private OzgcloudResourceController controller;
@BeforeEach
void init() {
resourceResolvers.add(resourceAResolver);
resourceResolvers.add(resourceBResolver);
}
@Nested
class TestGetOzgcloudResource {
@Nested
class OnUriCouldBeResolved {
private final ArgumentMatcher<OzgcloudResourceURIResolveResult> HAS_MATCHING_RESOURCE_URI = mapping -> mapping.getResourceURI().equals(
OzgcloudResourceURIResolveResultTestFactory.RESOURCE_URI);
private final ArgumentMatcher<OzgcloudResourceURIResolveResult> HAS_MATCHING_RESOURCE_LINK = mapping -> mapping.getResourceLink().equals(
OzgcloudResourceURIResolveResultTestFactory.RESOURCE_LINK);
@BeforeEach
void init() {
when(resourceBResolver.resolve(OzgcloudResourceURIResolveResultTestFactory.RESOURCE_URI)).thenReturn(Optional.of(
OzgcloudResourceURIResolveResultTestFactory.RESOURCE_LINK));
}
@Test
void shouldCallResolver() {
callController();
verify(resourceBResolver).resolve(OzgcloudResourceURIResolveResultTestFactory.RESOURCE_URI);
}
@Test
void shouldCallAssemblerWithUri() {
callController();
verify(assembler).toModel(argThat(HAS_MATCHING_RESOURCE_URI));
}
@Test
void shouldCallAssemblerWithResourceLink() {
callController();
verify(assembler).toModel(argThat(HAS_MATCHING_RESOURCE_LINK));
}
@Test
void shouldReturnModelFromAssembler() {
EntityModel<OzgcloudResource> modelFromAssembler = EntityModel.of(new OzgcloudResource());
when(assembler.toModel(argThat(mapping -> HAS_MATCHING_RESOURCE_URI.matches(mapping) && HAS_MATCHING_RESOURCE_LINK.matches(mapping))))
.thenReturn(modelFromAssembler);
var model = callController();
assertThat(model).isEqualTo(modelFromAssembler);
}
}
@Nested
class OnUriCouldNotBeResolved {
@BeforeEach
void init() {
when(resourceAResolver.resolve(OzgcloudResourceURIResolveResultTestFactory.RESOURCE_URI)).thenReturn(Optional.empty());
when(resourceBResolver.resolve(OzgcloudResourceURIResolveResultTestFactory.RESOURCE_URI)).thenReturn(Optional.empty());
}
@Test
void shouldThrowResourceNotFoundException() {
assertThatThrownBy(TestGetOzgcloudResource.this::callController).isInstanceOf(ResourceNotFoundException.class);
}
}
@Nested
class OnMultipleResolveResults {
@BeforeEach
void init() {
when(resourceAResolver.resolve(OzgcloudResourceURIResolveResultTestFactory.RESOURCE_URI)).thenReturn(Optional.of(
OzgcloudResourceURIResolveResultTestFactory.RESOURCE_LINK));
when(resourceBResolver.resolve(OzgcloudResourceURIResolveResultTestFactory.RESOURCE_URI)).thenReturn(Optional.of(
OzgcloudResourceURIResolveResultTestFactory.RESOURCE_LINK));
}
@Test
void shouldThrowTechnicalException() {
assertThatThrownBy(TestGetOzgcloudResource.this::callController).isInstanceOf(TechnicalException.class);
}
}
@SneakyThrows
private RepresentationModel<EntityModel<OzgcloudResource>> callController() {
return controller.getOzgcloudResource(OzgcloudResourceURIResolveResultTestFactory.RESOURCE_URI);
}
}
}
package de.ozgcloud.alfa.resource;
import static de.ozgcloud.alfa.resource.OzgcloudResourceController.*;
import static org.assertj.core.api.Assertions.*;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
class OzgcloudResourceModelAssemblerTest {
@InjectMocks
private OzgcloudResourceModelAssembler assembler;
@Nested
class TestToModel {
private final OzgcloudResourceURIResolveResult uriResolveResult = OzgcloudResourceURIResolveResultTestFactory.create();
@Test
void shouldHaveSelfLink() {
var model = callAssembler();
assertThat(model.getLink(IanaLinkRelations.SELF_VALUE)).isPresent().get().extracting(Link::getHref)
.isEqualTo(OzgcloudResourceController.PATH + "?" + PARAM_URI + "=" + OzgcloudResourceURIResolveResultTestFactory.ENCODED_RESOURCE_URI);
}
@Test
void shouldHaveResourceLink() {
var model = callAssembler();
assertThat(model.getLink(OzgcloudResourceURIResolveResultTestFactory.RESOURCE_LINK.getRel())).isPresent().get().isEqualTo(
OzgcloudResourceURIResolveResultTestFactory.RESOURCE_LINK);
}
private EntityModel<OzgcloudResource> callAssembler() {
return assembler.toModel(uriResolveResult);
}
}
}
package de.ozgcloud.alfa.resource;
import static org.assertj.core.api.Assertions.*;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import de.ozgcloud.alfa.Root;
import de.ozgcloud.alfa.RootTestFactory;
class OzgcloudResourceRootProcessorTest {
private final OzgcloudResourceRootProcessor processor = new OzgcloudResourceRootProcessor();
@Nested
class TestProcess {
private final EntityModel<Root> model = EntityModel.of(RootTestFactory.create());
@Test
void shouldReturnOriginalModel() {
var result = processor.process(model);
assertThat(result).isEqualTo(model);
}
@Test
void shouldAddResourceLink() {
processor.process(model);
assertThat(model.getLink(OzgcloudResourceRootProcessor.REL_RESOURCE)).isPresent().get().extracting(Link::getHref)
.isEqualTo(OzgcloudResourceController.PATH + "?uri={uri}");
}
}
}
package de.ozgcloud.alfa.resource;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import org.springframework.hateoas.Link;
import com.thedeanda.lorem.LoremIpsum;
class OzgcloudResourceURIResolveResultTestFactory {
public static final String RESOURCE_URI = String.format("%s://%s.%s/%s", (Object[]) LoremIpsum.getInstance().getWords(4).split("\\s"));
public static final String ENCODED_RESOURCE_URI = URLEncoder.encode(RESOURCE_URI, StandardCharsets.UTF_8);
public static final Link RESOURCE_LINK = Link.of(LoremIpsum.getInstance().getUrl()).withRel(LoremIpsum.getInstance().getWords(1));
public static OzgcloudResourceURIResolveResult create() {
return createBuilder().build();
}
public static OzgcloudResourceURIResolveResult.OzgcloudResourceURIResolveResultBuilder createBuilder() {
return OzgcloudResourceURIResolveResult.builder().resourceURI(RESOURCE_URI).resourceLink(RESOURCE_LINK);
}
}
package de.ozgcloud.alfa.vorgang;
import static org.assertj.core.api.Assertions.*;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkRelation;
import de.ozgcloud.alfa.common.AlfaTestUtils;
class VorgangURIResolverTest {
private VorgangURIResolver resolver = new VorgangURIResolver();
@Nested
class TestResolve {
private final String VORGANG_ID = AlfaTestUtils.createMongoDbObjectId();
private final String VORGANG_URI = "ozgcloud://dummy.de/vorgangs/" + VORGANG_ID;
@ParameterizedTest
@ValueSource(strings = {
"http://dummy.de/vorgangs/123",
"ozgcloud://dummy.de/res-a/123",
"ozgcloud://dummy.de/xyz/vorgangs/123",
"ozgcloud://dummy.de/vorgangs/xyz/123" })
void shouldReturnEmptyIfUriIsNotRecognized(String uri) {
var result = resolver.resolve(uri);
assertThat(result).isEmpty();
}
@Test
void shouldReturnLink() {
var result = resolver.resolve(VORGANG_URI);
assertThat(result).isPresent();
}
@Nested
class TestVorgangLink {
@Test
void shouldHaveCorrectRelValue() {
var result = resolver.resolve(VORGANG_URI);
assertThat(result).get().extracting(Link::getRel).extracting(LinkRelation::value).isEqualTo(VorgangURIResolver.REL_NAME);
}
@Test
void shouldHaveHrefOfVorgang() {
var result = resolver.resolve(VORGANG_URI);
assertThat(result).get().extracting(Link::getHref).isEqualTo("/api/vorgangs/" + VORGANG_ID);
}
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment