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

Merge branch 'master' into remove-todo-use-new-statistic-dsl

parents cc6caced de589e86
No related branches found
No related tags found
No related merge requests found
Showing
with 278 additions and 69 deletions
pipeline {
agent {
node {
label 'jenkins-build-agent-nodejs-18'
label 'ozgcloud-jenkins-build-agent'
}
}
environment {
BLUE_OCEAN_URL = "https://jenkins.ozg-sh.de/job/goofy/job/${env.BRANCH_NAME}/${env.BUILD_NUMBER}/"
BLUE_OCEAN_URL = "https://jenkins.infra.ozg-cloud.systems/job/goofy/job/${env.BRANCH_NAME}/${env.BUILD_NUMBER}/"
RELEASE_REGEX = /\d+.\d+.\d+/
SNAPSHOT_REGEX = /\d+.\d+.\d+-SNAPSHOT/
FAILED_STAGE = ""
......@@ -212,6 +212,23 @@ pipeline {
}
}
}
stage ('OWASP Dependency-Check Vulnerabilities') {
steps {
dependencyCheck additionalArguments: '''
-o "./"
-s "./"
-f "ALL"
-d /dependency-check-data
--suppression dependency-check-supressions.xml
--disableKnownExploited
--noupdate
--disableArchive
--prettyPrint''', odcInstallation: 'dependency-check-owasp'
dependencyCheckPublisher pattern: 'dependency-check-report.xml'
}
}
}
post {
failure {
......
......@@ -32,7 +32,7 @@
<parent>
<groupId>de.itvsh.ozg</groupId>
<artifactId>goofy</artifactId>
<version>1.17.0-SNAPSHOT</version>
<version>1.18.0-SNAPSHOT</version>
</parent>
<artifactId>alfa-service</artifactId>
......
......@@ -26,29 +26,36 @@ package de.ozgcloud.alfa;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import de.ozgcloud.alfa.vorgang.VorgangProcessorProperties;
@RestController
@RequestMapping("/api/environment")
@RequestMapping(EnvironmentController.BASE_PATH)
public class EnvironmentController {
static final String BASE_PATH = "/api/environment";
@Autowired
private OAuth2Properties oAuth2Properties;
@Value("${goofy.production}")
private boolean production = true;
@Autowired
private GoofyProperties goofyProperties;
@Autowired
private VorgangProcessorProperties vorgangProcessorProperties;
@GetMapping
public FrontendEnvironment getFrontendEnvironment() {
return FrontendEnvironment.builder()
.production(production)
.production(goofyProperties.isProduction())
.remoteHost(linkTo(RootController.class).toUri().toString())
.authServer(oAuth2Properties.getAuthServerUrl())
.clientId(oAuth2Properties.getResource())
.realm(oAuth2Properties.getRealm())
.processorNames(vorgangProcessorProperties.getProcessorNames())
.build();
}
}
\ No newline at end of file
......@@ -23,6 +23,8 @@
*/
package de.ozgcloud.alfa;
import java.util.List;
import lombok.Builder;
import lombok.Getter;
......@@ -35,4 +37,5 @@ public class FrontendEnvironment {
private String authServer;
private String realm;
private String clientId;
private List<String> processorNames;
}
package de.ozgcloud.alfa;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = GoofyProperties.PREFIX)
class GoofyProperties {
static final String PREFIX = "goofy";
/**
* Production mode.
*/
private boolean production = true;
}
......@@ -9,18 +9,16 @@ import lombok.Setter;
@Setter
@Getter
@Configuration
@ConfigurationProperties(prefix = FeatureToggleProperties.PREFIX)
@ConfigurationProperties(prefix = "ozgcloud.feature")
public class FeatureToggleProperties {
static final String PREFIX = "ozgcloud.feature";
/**
* Enable Vorgang Export(XDomea).
* Enable vorgang export(XDomea) feature.
*/
private boolean vorgangExport = false;
/**
* Enable/Disable Bescheid creation feature.
* Enable/Disable bescheid creation feature.
*/
private boolean createBescheid = false;
}
......@@ -31,6 +31,7 @@ import de.ozgcloud.alfa.loeschanforderung.DeleteLoeschAnforderung;
import de.ozgcloud.alfa.loeschanforderung.LoeschAnforderung;
import de.ozgcloud.alfa.postfach.PostfachMail;
import de.ozgcloud.alfa.vorgang.AssignUserCommandBody;
import de.ozgcloud.alfa.vorgang.ProcessVorgangBody;
import de.ozgcloud.alfa.vorgang.forwarding.RedirectRequest;
import de.ozgcloud.alfa.wiedervorlage.Wiedervorlage;
......@@ -44,7 +45,8 @@ import de.ozgcloud.alfa.wiedervorlage.Wiedervorlage;
@Type(value = Kommentar.class, name = "KOMMENTAR"),
@Type(value = LoeschAnforderung.class, name = "LOESCH_ANFORDERUNG"),
@Type(value = DeleteLoeschAnforderung.class, name = "DELETE_LOESCH_ANFORDERUNG"),
@Type(value = GenericCommandBody.class, name = "CREATE_BESCHEID")
@Type(value = GenericCommandBody.class, name = "CREATE_BESCHEID"),
@Type(value = ProcessVorgangBody.class, name = "PROCESS_VORGANG")
})
public interface CommandBody {
}
......@@ -79,7 +79,7 @@ public class CommandController {
@RequestMapping(CommandByRelationController.COMMAND_BY_RELATION_PATH)
public static class CommandByRelationController {
static final String COMMAND_BY_RELATION_PATH = "/api/vorgangs/{vorgangId}/relations/{relationId}/{relationVersion}/commands"; // NOSONAR
public static final String COMMAND_BY_RELATION_PATH = "/api/vorgangs/{vorgangId}/relations/{relationId}/{relationVersion}/commands"; // NOSONAR
@Autowired
private CommandService service;
......
......@@ -69,7 +69,9 @@ public enum CommandOrder {
PATCH_ATTACHED_ITEM(false, Type.VORGANG),
DELETE_ATTACHED_ITEM(false, Type.VORGANG),
CREATE_BESCHEID(false, Type.VORGANG);
CREATE_BESCHEID(false, Type.VORGANG),
PROCESS_VORGANG(false, Type.VORGANG);
enum Type {
VORGANG, VORGANG_LIST, WIEDERVORLAGE, KOMMENTAR, FORWARDING, POSTFACH
......
......@@ -12,6 +12,13 @@ import lombok.Setter;
@ConfigurationProperties(prefix = "grpc.client.user-manager")
public class UserManagerClientProperties {
/**
* UserManager grpc adress.
*/
private String address;
/**
* UserManager grpc negotiationType.
*/
private String negotiationType;
}
package de.ozgcloud.alfa.vorgang;
import java.util.ArrayList;
import de.ozgcloud.alfa.common.command.CommandBody;
import lombok.Getter;
@Getter
public class ProcessVorgangBody implements CommandBody {
private ArrayList<String> processorNames;
}
\ No newline at end of file
package de.ozgcloud.alfa.vorgang;
import java.util.Collections;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import de.ozgcloud.alfa.vorgang.VorgangProperties.VorgangProperty;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = "ozgcloud.vorgang")
public class VorgangProcessorProperties {
/**
* Matching condition for processing based on vorgang#formId and vorgang#formEngineName.
*/
private List<VorgangProperty> processor = Collections.emptyList();
/**
* Name of used processor.
*/
private List<String> processorNames = Collections.emptyList();
}
......@@ -13,10 +13,8 @@ import lombok.Setter;
@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = VorgangProperties.PREFIX)
class VorgangProperties {
public static final String PREFIX = "ozgcloud.vorgang";
@ConfigurationProperties(prefix = "ozgcloud.vorgang")
public class VorgangProperties {
/**
* List of Vorgänge for which notices can be issued.
......@@ -26,7 +24,7 @@ class VorgangProperties {
@Builder
@Setter
@Getter
static class VorgangProperty {
public static class VorgangProperty {
/**
* ID of the received formular
......@@ -36,6 +34,5 @@ class VorgangProperties {
* Name of the form engine providing the used formular
*/
private String formEngineName;
}
}
\ No newline at end of file
......@@ -26,6 +26,7 @@ package de.ozgcloud.alfa.vorgang;
import static java.util.Optional.*;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
......@@ -61,6 +62,7 @@ class VorgangWithEingangProzessor implements RepresentationModelProcessor<Entity
static final LinkRelation REL_VORGANG_FORWARDING = LinkRelation.of("forwarding");
static final LinkRelation REL_HISTORIE = LinkRelation.of("historie");
static final LinkRelation REL_BESCHEID = LinkRelation.of("createBescheid");
static final LinkRelation REL_PROCESS_VORGANG = LinkRelation.of("processVorgang");
static final String REL_SEARCH_USER = "search-user-profiles";
static final String USER_PROFILE_SEARCH_DELETED_PARAM = "deleted";
......@@ -77,6 +79,8 @@ class VorgangWithEingangProzessor implements RepresentationModelProcessor<Entity
private FeatureToggleProperties featureToggleProperties;
@Autowired
private VorgangProperties vorgangProperties;
@Autowired
private VorgangProcessorProperties vorgangProcessorProperties;
private static final Predicate<VorgangWithEingang> HAS_ATTACHMENTS = vorgangWithEingang -> vorgangWithEingang.getEingang()
.getNumberOfAttachments() > 0;
......@@ -111,6 +115,9 @@ class VorgangWithEingangProzessor implements RepresentationModelProcessor<Entity
.ifMatch(() -> isCreateBescheidEnabled(vorgang))
.addLink(linkTo(methodOn(CommandByRelationController.class).createCommand(vorgang.getId(), vorgang.getId(), vorgang.getVersion(),
null)).withRel(REL_BESCHEID))
.ifMatch(this::isProcessable)
.addLink(() -> linkTo(methodOn(CommandByRelationController.class).createCommand(vorgang.getId(), vorgang.getId(), vorgang.getVersion(),
null)).withRel(REL_PROCESS_VORGANG))
.buildModel();
}
......@@ -152,6 +159,14 @@ class VorgangWithEingangProzessor implements RepresentationModelProcessor<Entity
return vorgangProperties.getBescheid().stream().anyMatch(prop -> isFormIdAndFormEngineNameMatching(eingangHeader, prop));
}
private boolean isProcessable(VorgangWithEingang vorgang) {
return isAnyFormIdAndFormEngineNameMatching(vorgang.getEingang().getHeader(), vorgangProcessorProperties.getProcessor());
}
private boolean isAnyFormIdAndFormEngineNameMatching(EingangHeader eingangHeader, List<VorgangProperty> properties) {
return properties.stream().anyMatch(prop -> isFormIdAndFormEngineNameMatching(eingangHeader, prop));
}
private boolean isFormIdAndFormEngineNameMatching(EingangHeader eingangHeader, VorgangProperty property) {
return property.getFormId().equals(eingangHeader.getFormId()) && property.getFormEngineName().equals(eingangHeader.getFormEngineName());
}
......
......@@ -38,5 +38,8 @@ public class LandesnetzInfoProperties {
static final String LNINFO_CONFIG_PREFIX = "kop.forwarding.lninfo";
/**
* Url of LandesnetzInfo html/file location.
*/
private Resource url;
}
......@@ -27,7 +27,11 @@ import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
......@@ -35,16 +39,19 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import de.ozgcloud.alfa.vorgang.VorgangProcessorProperties;
import lombok.SneakyThrows;
class EnvironmentControllerTest {
private final String PATH = "/api/environment";
@InjectMocks
private EnvironmentController controller;
@Mock
private OAuth2Properties oAuth2Properties;
@Mock
private GoofyProperties goofyProperties;
@Mock
private VorgangProcessorProperties vorgangProcessorProperties;
private MockMvc mockMvc;
......@@ -53,31 +60,56 @@ class EnvironmentControllerTest {
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
@DisplayName("Get frontend environment")
@Nested
class TestGetFrontendEnvironment {
private static final String CLIENT = "goofy";
private static final boolean PRODUCTION = true;
private static final String PROCESSOR_NAME = "dummyProcessorName";
@BeforeEach
void init() {
when(goofyProperties.isProduction()).thenReturn(PRODUCTION);
when(oAuth2Properties.getResource()).thenReturn(CLIENT);
when(vorgangProcessorProperties.getProcessorNames()).thenReturn(List.of(PROCESSOR_NAME));
}
@SneakyThrows
@Test
void shouldReturnOk() throws Exception {
void shouldReturnOk() {
var response = doRequest();
response.andExpect(status().isOk());
}
@SneakyThrows
@Test
void shouldHaveProductionTrueAsDefault() throws Exception {
void shouldHaveProductionTrueAsDefault() {
var response = doRequest();
response.andExpect(jsonPath("$.production").value(true));
response.andExpect(jsonPath("$.production").value(PRODUCTION));
}
@SneakyThrows
@Test
void shouldHaveClientId() throws Exception {
var client = "goofy";
when(oAuth2Properties.getResource()).thenReturn(client);
void shouldHaveClientId() {
var response = doRequest();
response.andExpect(jsonPath("$.clientId").value(client));
response.andExpect(jsonPath("$.clientId").value(CLIENT));
}
@SneakyThrows
@Test
void shouldHaveProcessorNames() {
var response = doRequest();
response.andExpect(jsonPath("$.processorNames").value(PROCESSOR_NAME));
}
@SneakyThrows
private ResultActions doRequest() {
return mockMvc.perform(get(PATH));
return mockMvc.perform(get(EnvironmentController.BASE_PATH));
}
}
}
\ No newline at end of file
......@@ -46,8 +46,6 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.itvsh.kop.common.test.TestUtils;
import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController;
import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
......@@ -107,8 +105,6 @@ class CommandByRelationControllerTest {
@Test
void shouldFillGenericBody() throws Exception {
var oj = new ObjectMapper();
var content = TestUtils.loadTextFile("jsonTemplates/command/createCommandWithBody.json.tmpl", CommandOrder.CREATE_BESCHEID.name(),
"{\"bescheidVom\":\"2023-06-26\"}");
......@@ -117,7 +113,6 @@ class CommandByRelationControllerTest {
verify(service).createCommand(createCommandCaptor.capture(), anyLong());
var body = (GenericCommandBody) createCommandCaptor.getValue().getBody();
assertThat(body).isNotNull().contains(entry("bescheidVom", "2023-06-26"));
System.out.println(body);
}
private ResultActions doRequest() throws Exception {
......
......@@ -184,7 +184,7 @@ class CommandModelAssemblerTest {
"WIEDERVORLAGE_WIEDEREROEFFNEN", "CREATE_KOMMENTAR", "EDIT_KOMMENTAR", "REDIRECT_VORGANG", "FORWARD_SUCCESSFULL",
"FORWARD_FAILED", "ASSIGN_USER", "SEND_POSTFACH_MAIL", "SEND_POSTFACH_NACHRICHT", "RESEND_POSTFACH_MAIL", "CREATE_ATTACHED_ITEM",
"UPDATE_ATTACHED_ITEM", "PATCH_ATTACHED_ITEM", "RECEIVE_POSTFACH_NACHRICHT", "VORGANG_LOESCHEN", "DELETE_ATTACHED_ITEM",
"VORGANG_ZUM_LOESCHEN_MARKIEREN", "LOESCH_ANFORDERUNG_ZURUECKNEHMEN", "CREATE_BESCHEID" })
"VORGANG_ZUM_LOESCHEN_MARKIEREN", "LOESCH_ANFORDERUNG_ZURUECKNEHMEN", "CREATE_BESCHEID", "PROCESS_VORGANG" })
void shouldBePresentOnOrder(CommandOrder order) {
var model = toModelWithOrder(order);
......
......@@ -83,10 +83,7 @@ class PostfachMailCommandControllerTest {
void init() {
when(service.findById(any())).thenReturn(PostfachMailTestFactory.create());
when(commandByRelationController.createCommand(any()))
.thenAnswer((i) -> {
System.out.println("Order: " + ((CreateCommand) i.getArgument(0)).getOrder());
return CommandTestFactory.createBuilder().order(((CreateCommand) i.getArgument(0)).getOrder()).build();
});
.thenAnswer((i) -> CommandTestFactory.createBuilder().order(((CreateCommand) i.getArgument(0)).getOrder()).build());
}
@Test
......
......@@ -43,9 +43,11 @@ import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkRelation;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriTemplate;
import de.ozgcloud.alfa.common.FeatureToggleProperties;
import de.ozgcloud.alfa.common.UserProfileUrlProvider;
import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController;
import de.ozgcloud.alfa.common.user.CurrentUserService;
import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
import de.ozgcloud.alfa.common.user.UserRole;
......@@ -70,6 +72,9 @@ class VorgangWithEingangProzessorTest {
@Mock
private VorgangProperties vorgangProperties;
@Mock
private VorgangProcessorProperties vorgangProcessorProperties;
private UserProfileUrlProvider urlProvider = new UserProfileUrlProvider();
@Nested
......@@ -78,6 +83,11 @@ class VorgangWithEingangProzessorTest {
private final LinkRelation linkRel = VorgangWithEingangProzessor.REL_ATTACHMENTS;
private final String PATH = "/api/attachments?eingangId=" + EingangTestFactory.ID;
@BeforeEach
void init() {
initUserProfileUrlProvider(urlProvider);
}
@DisplayName("should be present on numberOfAttachments > 0")
@Test
void shouldBePresentByAttachments() {
......@@ -481,9 +491,9 @@ class VorgangWithEingangProzessorTest {
void shouldHaveCreateBescheidLink() {
doReturn(true).when(processor).isCreateBescheidEnabled(vorgang);
var processed = processor.process(vorgangEntityModel);
var model = processor.process(vorgangEntityModel);
assertThat(processed.getLink(VorgangWithEingangProzessor.REL_BESCHEID)).isPresent().get()
assertThat(model.getLink(VorgangWithEingangProzessor.REL_BESCHEID)).isPresent().get()
.extracting(Link::getHref)
.isEqualTo("/api/vorgangs/" + VorgangHeaderTestFactory.ID + "/relations/" + VorgangHeaderTestFactory.ID + "/"
+ VorgangHeaderTestFactory.VERSION + "/commands");
......@@ -493,10 +503,70 @@ class VorgangWithEingangProzessorTest {
void shouldHaveNoLinkIfDisabled() {
doReturn(false).when(processor).isCreateBescheidEnabled(vorgang);
var processed = processor.process(vorgangEntityModel);
var model = processor.process(vorgangEntityModel);
assertThat(processed.getLink(VorgangWithEingangProzessor.REL_BESCHEID)).isEmpty();
assertThat(model.getLink(VorgangWithEingangProzessor.REL_BESCHEID)).isEmpty();
}
}
@DisplayName("Process vorgang")
@Nested
class TestProcessVorgang {
private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create();
private final EntityModel<VorgangWithEingang> vorgangEntityModel = EntityModel.of(vorgang);
@BeforeEach
void init() {
initUserProfileUrlProvider(urlProvider);
}
@DisplayName("on matching configuration")
@Nested
class TestOnMatchingConfiguration {
@BeforeEach
void init() {
when(vorgangProcessorProperties.getProcessor()).thenReturn(List.of(VorgangPropertyTestFactory.create()));
}
@Test
void shouldBeVisible() {
var entityModel = processor.process(vorgangEntityModel);
assertThat(entityModel.getLink(VorgangWithEingangProzessor.REL_PROCESS_VORGANG))
.isPresent().get().extracting(Link::getHref).isEqualTo(buildExpectedLink());
}
private String buildExpectedLink() {
return new UriTemplate(CommandByRelationController.COMMAND_BY_RELATION_PATH)
.expand(VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.VERSION).toString();
}
}
@DisplayName("on non matching configuration")
@Nested
class TestOnNonMatchingConfiguration {
@Test
void shouldNotBeVisibleOnWrongFormId() {
var properties = List.of(VorgangPropertyTestFactory.createBuilder().formId("quatsch").build());
when(vorgangProcessorProperties.getProcessor()).thenReturn(properties);
var model = processor.process(vorgangEntityModel);
assertThat(model.getLink(VorgangWithEingangProzessor.REL_PROCESS_VORGANG)).isNotPresent();
}
@Test
void shouldNotBeVisibleOnWrongFormEngineName() {
var properties = List.of(VorgangPropertyTestFactory.createBuilder().formEngineName("quatsch").build());
when(vorgangProcessorProperties.getProcessor()).thenReturn(properties);
var model = processor.process(vorgangEntityModel);
assertThat(model.getLink(VorgangWithEingangProzessor.REL_PROCESS_VORGANG)).isNotPresent();
}
}
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment