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

OZG-6811 remove bescheid-manager except for bescheid grpc service and add document service

parent fc369fe9
No related branches found
No related tags found
No related merge requests found
Showing
with 0 additions and 1229 deletions
package de.ozgcloud.bescheid;
import java.util.Objects;
import de.ozgcloud.common.datatype.StringBasedValue;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
public class UserId extends StringBasedValue {
UserId(String userId) {
super(userId);
}
public static UserId from(String userId) {
if (Objects.nonNull(userId)) {
return new UserId(userId);
}
return null;
}
}
/*
* Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.bescheid.administration;
import java.util.Optional;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@RefreshScope
@Configuration
@ConfigurationProperties(prefix = "ozgcloud.postfach")
public class AdministrationProperties {
private Optional<String> signatur = Optional.empty();
}
/*
* Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.bescheid.administration;
import java.util.Optional;
import org.springframework.cloud.endpoint.RefreshEndpoint;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class AdministrationService {
private final AdministrationProperties administrationProperties;
private final RefreshEndpoint refreshEndpoint;
public Optional<String> getNachrichtSignature() {
return administrationProperties.getSignatur();
}
public void refreshConfig() {
refreshEndpoint.refresh();
}
}
/*
* Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.bescheid.administration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import lombok.RequiredArgsConstructor;
@Component
@ConditionalOnProperty(value = "ozgcloud.administration.sync.enabled", havingValue = "true", matchIfMissing = true)
@RequiredArgsConstructor
public class AdministrationSyncScheduler {
private final AdministrationService service;
@Scheduled(initialDelayString = "${ozgcloud.administration.sync.delay}", fixedDelayString = "${ozgcloud.administration.sync.delay}")
public void sync() {
service.refreshConfig();
}
}
/*
* Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.bescheid.attributes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import de.ozgcloud.bescheid.BescheidCallContextAttachingInterceptor;
import de.ozgcloud.vorgang.grpc.clientAttribute.ClientAttributeServiceGrpc.ClientAttributeServiceBlockingStub;
import de.ozgcloud.vorgang.grpc.clientAttribute.GrpcAccessPermission;
import de.ozgcloud.vorgang.grpc.clientAttribute.GrpcClientAttribute;
import de.ozgcloud.vorgang.grpc.clientAttribute.GrpcClientAttributeValue;
import de.ozgcloud.vorgang.grpc.clientAttribute.GrpcSetClientAttributeRequest;
import io.grpc.ClientInterceptor;
import net.devh.boot.grpc.client.inject.GrpcClient;
@Service("bescheid_ClientAttributeRemoteService")
class ClientAttributeRemoteService {
@GrpcClient("vorgang-manager")
private ClientAttributeServiceBlockingStub serviceBlockingStub;
@Autowired
private ClientInterceptor bescheidCallContextInterceptor;
public void setBooleanReadOnlyClientAttribute(String vorgangId, String attributeName, boolean value) {
serviceBlockingStub.withInterceptors(bescheidCallContextInterceptor).set(buildRequest(vorgangId, attributeName, value));
}
GrpcSetClientAttributeRequest buildRequest(String vorgangId, String attributeName, boolean value) {
return GrpcSetClientAttributeRequest.newBuilder()
.setVorgangId(vorgangId)
.setAttribute(buildClientAttribute(attributeName, value))
.build();
}
GrpcClientAttribute buildClientAttribute(String attributeName, boolean value) {
return GrpcClientAttribute.newBuilder()
.setClientName(BescheidCallContextAttachingInterceptor.BESCHEID_MANAGER_CLIENT_NAME)
.setAccess(GrpcAccessPermission.READ_ONLY)
.setAttributeName(attributeName)
.setValue(GrpcClientAttributeValue.newBuilder().setBoolValue(value).build())
.build();
}
}
/*
* Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.bescheid.attributes;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
@Service("bescheid_ClientAttributeService")
@RequiredArgsConstructor
public class ClientAttributeService {
public static final String ATTRIBUTE_NAME_ANTRAG_BEWILLIGT = "antragBewilligt";
private final ClientAttributeRemoteService bescheidClientAttributeRemoteService;
public void setAntragResult(String vorgangId, boolean antragResult) {
bescheidClientAttributeRemoteService.setBooleanReadOnlyClientAttribute(vorgangId, ATTRIBUTE_NAME_ANTRAG_BEWILLIGT, antragResult);
}
}
package de.ozgcloud.bescheid.binaryfile;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Service;
import com.google.protobuf.ByteString;
import de.ozgcloud.bescheid.BescheidResponse;
import de.ozgcloud.common.binaryfile.FileId;
import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils;
import de.ozgcloud.common.binaryfile.GrpcFileUploadUtils.FileSender;
import de.ozgcloud.common.errorhandling.TechnicalException;
import de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileServiceGrpc.BinaryFileServiceStub;
import de.ozgcloud.vorgang.grpc.binaryFile.GrpcUploadBinaryFileMetaData;
import de.ozgcloud.vorgang.grpc.binaryFile.GrpcUploadBinaryFileRequest;
import de.ozgcloud.vorgang.grpc.binaryFile.GrpcUploadBinaryFileResponse;
import de.ozgcloud.vorgang.grpc.command.GrpcCallContext;
import io.grpc.stub.CallStreamObserver;
import io.grpc.stub.StreamObserver;
import lombok.NonNull;
import net.devh.boot.grpc.client.inject.GrpcClient;
@Service
class BinaryFileRemoteService {
private static final String CALL_CONTEXT_CLIENT = "bescheid-manager";
private static final String VORGANG_ATTACHMENT_FIELD = "bescheid";
@GrpcClient("vorgang-manager")
private BinaryFileServiceStub binaryFileRemoteStub;
public FileId uploadBescheidFile(@NonNull BescheidResponse bescheid) {
try (var in = openFile(bescheid.getBescheidFile())) {
var resultFuture = GrpcFileUploadUtils.createSender(this::buildChunkRequest, in,
this::buildCallStreamObserver)
.withMetaData(buildMetaDataRequest(bescheid))
.send();
return FileId.from(waitUntilFutureToComplete(resultFuture, in).getFileId());
} catch (IOException e) {
throw new TechnicalException("Error on uploading file.", e);
}
}
private InputStream openFile(File file) {
try {
return new FileInputStream(file);
} catch (FileNotFoundException e) {
throw new TechnicalException("File to upload not found.", e);
}
}
private GrpcUploadBinaryFileRequest buildMetaDataRequest(BescheidResponse bescheid) {
return GrpcUploadBinaryFileRequest.newBuilder()
.setMetadata(GrpcUploadBinaryFileMetaData.newBuilder()
// TODO remove context - check why needed!
.setContext(GrpcCallContext.newBuilder().setClient(CALL_CONTEXT_CLIENT).build())
.setVorgangId(bescheid.getVorgangId().toString())
.setField(VORGANG_ATTACHMENT_FIELD)
.setContentType(bescheid.getContentType())
.setSize(bescheid.getBescheidFile().length())
.setFileName(bescheid.getBescheidFileName())
.build())
.build();
}
private GrpcUploadBinaryFileRequest buildChunkRequest(byte[] bytes, Integer length) {
return GrpcUploadBinaryFileRequest.newBuilder().setFileContent((ByteString.copyFrom(bytes, 0, length))).build();
}
private CallStreamObserver<GrpcUploadBinaryFileRequest> buildCallStreamObserver(
StreamObserver<GrpcUploadBinaryFileResponse> responseObserver) {
return (CallStreamObserver<GrpcUploadBinaryFileRequest>) binaryFileRemoteStub.uploadBinaryFileAsStream(responseObserver);
}
GrpcUploadBinaryFileResponse waitUntilFutureToComplete(FileSender<GrpcUploadBinaryFileRequest, GrpcUploadBinaryFileResponse> fileSender,
InputStream fileContentStream) {
try {
return fileSender.getResultFuture().get(10, TimeUnit.MINUTES);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
fileSender.cancelOnError(e);
throw new TechnicalException("Waiting for finishing upload was interrupted.", e);
} catch (ExecutionException | TimeoutException e) {
fileSender.cancelOnTimeout();
throw new TechnicalException("Error / Timeout on uploading data.", e);
} finally {
IOUtils.closeQuietly(fileContentStream);
}
}
}
package de.ozgcloud.bescheid.binaryfile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import de.ozgcloud.bescheid.BescheidResponse;
import lombok.NonNull;
@Service
public class BinaryFileService {
@Autowired
private BinaryFileRemoteService remoteService;
public BescheidResponse uploadBescheidFile(@NonNull BescheidResponse bescheid) {
var fileId = remoteService.uploadBescheidFile(bescheid);
return bescheid.withBescheidFileId(fileId);
}
}
/*
* Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.bescheid.common.callcontext;
import java.util.Optional;
import org.springframework.stereotype.Component;
import de.ozgcloud.apilib.common.callcontext.CallContext;
import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider;
import de.ozgcloud.apilib.user.OzgCloudUserId;
import de.ozgcloud.bescheid.BescheidCallContextAttachingInterceptor;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
public class BescheidManagerCallContextProvider implements OzgCloudCallContextProvider {
private final CurrentUserService currentUserService;
@Override
public CallContext provideContext() {
var callContextBuilder = CallContext.builder().clientName(BescheidCallContextAttachingInterceptor.BESCHEID_MANAGER_CLIENT_NAME);
getUserId().ifPresent(callContextBuilder::userId);
return callContextBuilder.build();
}
Optional<OzgCloudUserId> getUserId() {
return currentUserService.getUser().getUserId().map(OzgCloudUserId::from);
}
}
/*
* Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.bescheid.common.callcontext;
import java.util.Collection;
import java.util.stream.Collectors;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
public class CallContextAuthenticationToken extends AbstractAuthenticationToken {
private final CallContextUser user;
static CallContextAuthenticationToken authenticate(CallContextUser user) {
return new CallContextAuthenticationToken(user);
}
private CallContextAuthenticationToken(CallContextUser user) {
super(user.getOrganisatorischeEinheitenIds().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet()));
this.user = user;
super.setAuthenticated(true);
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getPrincipal() {
return user;
}
@Override
public Collection<GrantedAuthority> getAuthorities() {
return user.getOrganisatorischeEinheitenIds().stream().map(SimpleGrantedAuthority::new).collect(Collectors.toUnmodifiableSet());
}
}
/*
* Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.bescheid.common.callcontext;
import java.io.Serializable;
import java.util.Collection;
import java.util.Optional;
import org.springframework.security.core.AuthenticatedPrincipal;
import lombok.Builder;
import lombok.Getter;
import lombok.Singular;
@Builder
@Getter
public class CallContextUser implements AuthenticatedPrincipal, Serializable {
private static final long serialVersionUID = 1L;
private final String clientName;
@Builder.Default
private final transient Optional<String> userId = Optional.empty();
@Builder.Default
private final transient Optional<String> userName = Optional.empty();
@Singular
private final Collection<String> organisatorischeEinheitenIds;
@Builder.Default
private final transient boolean organisationEinheitenIdCheckNecessary = false;
@Override
public String getName() {
return clientName;
}
}
/*
* Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.bescheid.common.callcontext;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import de.ozgcloud.command.Command;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Service("bescheid_currentUserService")
public class CurrentUserService {
private final AuthenticationTrustResolver trustResolver;
public CallContextUser getUser() {
return findUser().orElseThrow(() -> new IllegalStateException("No authenticated User found"));
}
public Optional<CallContextUser> findUser() {
return findTrustedAuthentication()
.map(this::mapToCallContextUser)
// remove this filter as soon we have a trusted authentication
.filter(user -> StringUtils.isNotBlank(user.getClientName()));
}
private CallContextUser mapToCallContextUser(Authentication auth) {
if (auth instanceof CallContextAuthenticationToken) {
return (CallContextUser) auth.getPrincipal();
} else {
return CallContextUser.builder()
.clientName(auth.getName())
.organisatorischeEinheitenIds(
auth.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toUnmodifiableSet()))
.build();
}
}
public Optional<Authentication> findAuthentication() {
return findTrustedAuthentication();
}
Optional<Authentication> findTrustedAuthentication() {
return Optional.ofNullable(SecurityContextHolder.getContext())
.map(SecurityContext::getAuthentication)
.filter(auth -> !trustResolver.isAnonymous(auth))
.filter(Authentication::isAuthenticated);
}
public SecurityContext startSecurityContext(Command command) {
var prevContext = SecurityContextHolder.getContext();
SecurityContextHolder.clearContext();
SecurityContextHolder.getContext().setAuthentication(CallContextAuthenticationToken.authenticate(createUser(command)));
return prevContext;
}
CallContextUser createUser(Command command) {
var builder = CallContextUser.builder()
.userId(Optional.ofNullable(command.getCreatedBy()))
.userName(Optional.ofNullable(command.getCreatedByName()))
.clientName("Alfa") // FIXME read client name from command
.organisationEinheitenIdCheckNecessary(false);
return builder.build();
}
public void resetSecurityContext(SecurityContext context) {
SecurityContextHolder.clearContext();
if (Objects.nonNull(context)) {
SecurityContextHolder.setContext(context);
}
}
}
\ No newline at end of file
package de.ozgcloud.bescheid.common.freemarker;
import java.io.IOException;
import java.io.StringWriter;
import org.springframework.stereotype.Component;
import de.ozgcloud.common.errorhandling.TechnicalException;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.RequiredArgsConstructor;
@Component
@RequiredArgsConstructor
public class TemplateHandler {
private final Configuration freemarkerConfig;
public String getRawTemplate(String templateName) {
return getTemplate(templateName).toString();
}
public String fillTemplate(String templateName, Object dataModel) {
try {
var template = getTemplate(templateName);
var stringWriter = new StringWriter();
template.process(dataModel, stringWriter);
return stringWriter.toString();
} catch (IOException | TemplateException e) {
throw new TechnicalException("Error filling template", e);
}
}
private Template getTemplate(String templateName) {
try {
return freemarkerConfig.getTemplate(templateName);
} catch (IOException e) {
throw new TechnicalException("Error loading mail template", e);
}
}
}
/*
* Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.bescheid.common.user;
import de.ozgcloud.bescheid.UserId;
import lombok.Builder;
import lombok.Getter;
@Builder
@Getter
public class UserProfile {
private UserId id;
private String firstName;
private String lastName;
private String email;
}
/*
* Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.bescheid.common.user;
import org.mapstruct.Mapper;
import de.ozgcloud.apilib.user.OzgCloudUserId;
import de.ozgcloud.apilib.user.OzgCloudUserProfile;
import de.ozgcloud.bescheid.UserId;
@Mapper
public interface UserProfileMapper {
UserProfile mapProfile(OzgCloudUserProfile userProfile);
default UserId mapUserId(OzgCloudUserId id) {
return UserId.from(id.toString());
}
}
/*
* Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.bescheid.common.user;
import java.util.Optional;
import org.springframework.stereotype.Service;
import de.ozgcloud.apilib.user.OzgCloudUserId;
import de.ozgcloud.apilib.user.OzgCloudUserProfileService;
import de.ozgcloud.bescheid.common.callcontext.CurrentUserService;
import de.ozgcloud.common.errorhandling.TechnicalException;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class UserProfileService {
private final CurrentUserService currentUserService;
private final Optional<OzgCloudUserProfileService> userProfileService;
private final UserProfileMapper mapper;
public UserProfile getUserProfile() {
var service = userProfileService.orElseThrow(() -> new IllegalStateException("No connection to user-manager configured."));
return currentUserService.getUser().getUserId().map(OzgCloudUserId::from)
.map(service::getById)
.map(mapper::mapProfile).orElseThrow(() -> new TechnicalException("Unknown UserId or cannot load user profile."));
}
}
/*
* Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
package de.ozgcloud.bescheid.common.user;
import java.util.UUID;
import com.thedeanda.lorem.LoremIpsum;
import de.ozgcloud.bescheid.UserId;
public class UserProfileTestFactory {
private static final LoremIpsum LOREM_IPSUM = LoremIpsum.getInstance();
public static final String ID_STR = UUID.randomUUID().toString();
public static final UserId ID = UserId.from(ID_STR);
public static final String FIRST_NAME = LOREM_IPSUM.getFirstName();
public static final String LAST_NAME = LOREM_IPSUM.getLastName();
public static final String EMAIL = "test-email@local";
public static UserProfile create() {
return createBuilder().build();
}
public static UserProfile.UserProfileBuilder createBuilder() {
return UserProfile.builder()
.id(ID)
.firstName(FIRST_NAME)
.lastName(LAST_NAME)
.email(EMAIL);
}
}
package de.ozgcloud.bescheid.dummy;
import java.util.Optional;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import com.google.common.net.MediaType;
import de.ozgcloud.bescheid.BescheidResponse;
import de.ozgcloud.bescheid.BescheidRemoteService;
import de.ozgcloud.bescheid.BescheidRequest;
import de.ozgcloud.bescheid.vorgang.Vorgang;
import de.ozgcloud.common.binaryfile.TempFileUtils;
@Service
@ConditionalOnProperty("ozgcloud.feature.bescheid.enable-dummy-document-processor")
class DummyBescheidRemoteService implements BescheidRemoteService {
private static final String DUMMY_BESCHEID_FILE_NAME = "dummy-bescheid.pdf";
private static final String DUMMY_BESCHEID_CONTENT_TYPE = MediaType.PDF.toString();
@Override
public BescheidResponse create(BescheidRequest request, Vorgang vorgang) {
var file = TempFileUtils.writeTmpFile(this.getClass().getClassLoader().getResourceAsStream(DUMMY_BESCHEID_FILE_NAME));
return BescheidResponse.builder()
.bescheidFile(file)
.bescheidFileName(DUMMY_BESCHEID_FILE_NAME)
.contentType(DUMMY_BESCHEID_CONTENT_TYPE)
.nachrichtText(Optional.of("Dummy Bescheid"))
.nachrichtSubject(Optional.of("Nachricht Subject"))
.size(file.length())
.createdBy(request.getCreateFor().getId())
.build();
}
}
package de.ozgcloud.bescheid.smartdocuments;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Optional;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.BodyExtractors;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import org.w3c.dom.Document;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import de.ozgcloud.bescheid.BescheidResponse;
import de.ozgcloud.bescheid.BescheidRemoteService;
import de.ozgcloud.bescheid.BescheidRequest;
import de.ozgcloud.bescheid.common.user.UserProfile;
import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsBescheidRemoteService.SmartDocumentsResponse.SmartDocumentDocument;
import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsBescheidRemoteService.SmartDocumentsResponse.SmartDocumentFile;
import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsRequest.CustomerData;
import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsRequest.CustomerData.BescheidData;
import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsRequest.CustomerData.UserData;
import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsRequest.SmartDocument.Selection;
import de.ozgcloud.bescheid.vorgang.Vorgang;
import de.ozgcloud.common.binaryfile.FileDataDeserializer;
import de.ozgcloud.common.errorhandling.TechnicalException;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import reactor.core.publisher.Mono;
@Log4j2
@Service
@RequiredArgsConstructor
@ConditionalOnProperty("ozgcloud.bescheid.smart-documents.url")
class SmartDocumentsBescheidRemoteService implements BescheidRemoteService {
private static final String FILE_TYPE_PDF = "PDF";
private static final String FILE_TYPE_XML = "XML";
static final String NACHRICHTEN_TEXT_EXPRESSION = "/root/SmartDocument/Fields/NachrichtenText/text()"; // NOSONAR
static final String FIELD_TEMPLATE_EXPRESSION = "/root/SmartDocument/Fields/Field[@ID=\"Template.56E7AA0956C7486292E9A02114CB231C\"]/text()"; // NOSONAR
@SuppressWarnings("deprecation") // SD requires forced UTF-8 encoding
private static final MediaType JSON_MEDIA_TYPE_FOR_SD = MediaType.APPLICATION_JSON_UTF8;
@Qualifier("smartDocuments")
private final WebClient smartDocumentsWebClient;
private final SmartDocumentsProperties properties;
@Override
public BescheidResponse create(BescheidRequest request, Vorgang vorgang) {
var sdRequest = createRequest(request, vorgang);
LOG.debug(() -> buildLogRequest(sdRequest));
return smartDocumentsWebClient.post().accept(MediaType.APPLICATION_JSON)
.contentType(JSON_MEDIA_TYPE_FOR_SD)
.bodyValue(sdRequest)
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError, this::handleClientError)
.bodyToMono(SmartDocumentsResponse.class)
.map(response -> buildBescheid(request, response))
.block();
}
Mono<Throwable> handleClientError(ClientResponse response) {
return response.body(BodyExtractors.toMono(String.class))
.map(content -> new TechnicalException("Client-Error: " + content));
}
private String buildLogRequest(SmartDocumentsRequest request) {
try {
ObjectMapper oj = new ObjectMapper();
return oj.writerWithDefaultPrettyPrinter().writeValueAsString(request);
} catch (Exception e) {
LOG.warn("Error writing request as json-string for logging.", e);
return "Error generating logging string";
}
}
BescheidResponse buildBescheid(BescheidRequest request, SmartDocumentsResponse smartDocumentsResponse) {
var smartDocumentsFile = getSmartDocumentsFile(smartDocumentsResponse);
return BescheidResponse.builder()
.bescheidFile(smartDocumentsFile.getDocument().getData())
.bescheidFileName(smartDocumentsFile.getFilename())
.size(smartDocumentsFile.getDocument().getData().length())
.contentType(MediaType.APPLICATION_PDF_VALUE)
.nachrichtText(getNachrichtText(smartDocumentsResponse))
.bewilligt(request.isGenehmigt())
.createdBy(request.getCreateFor().getId())
.vorgangId(request.getVorgangId())
.build();
}
private SmartDocumentFile getSmartDocumentsFile(SmartDocumentsResponse response) {
return getSmartDocumentsFile(response, FILE_TYPE_PDF)
.orElseThrow(() -> new IllegalStateException("No PDF File in SmartDocuments Response found."));
}
Optional<String> getNachrichtText(SmartDocumentsResponse response) {
return getXMLFile(response).flatMap(this::extractTextFromXmlFile);
}
Optional<String> extractTextFromXmlFile(File xmlFile) {
try {
var document = parseXml(xmlFile);
if (document.isPresent()) {
return document.flatMap(this::getNachrichtenText).or(() -> getFieldTemplateText(document.get())).map(Text::getTextContent);
}
} catch (RuntimeException e) {
LOG.warn("Unexpected Error on extracting NachrichtText: {}", e.getMessage(), e);
}
return Optional.empty();
}
Optional<Document> parseXml(File xmlFile) {
try {
return Optional.of(DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder().parse(xmlFile));
} catch (SAXException | IOException | ParserConfigurationException e) {
LOG.warn("XML-Parsing error on extracting Nachricht-Text: {}", e.getMessage(), e);
}
return Optional.empty();
}
Optional<Text> getNachrichtenText(Document document) {
return evaluateXPath(document, NACHRICHTEN_TEXT_EXPRESSION);
}
Optional<Text> getFieldTemplateText(Document document) {
return evaluateXPath(document, FIELD_TEMPLATE_EXPRESSION);
}
Optional<Text> evaluateXPath(Document document, String xpathExpression) {
try {
var expr = XPathFactory.newInstance().newXPath().compile(xpathExpression);
return Optional.ofNullable(expr.evaluate(document, XPathConstants.NODE)).map(Text.class::cast);
} catch (ClassCastException e) {
LOG.warn("Error on extraction Nachricht-Text. XPath return unexpected Type.", e);
} catch (XPathExpressionException e) {
LOG.warn("Cannot evaluate XPath: {}", xpathExpression, e);
}
return Optional.empty();
}
Optional<File> getXMLFile(SmartDocumentsResponse response) {
return getSmartDocumentsFile(response, FILE_TYPE_XML)
.map(SmartDocumentFile::getDocument)
.map(SmartDocumentDocument::getData);
}
Optional<SmartDocumentFile> getSmartDocumentsFile(SmartDocumentsResponse response, String fileType) {
return response.getFile().stream()
.filter(file -> file.getOutputFormat().equals(fileType))
.findFirst();
}
SmartDocumentsRequest createRequest(BescheidRequest request, Vorgang vorgang) {
return logRequest(SmartDocumentsRequest.builder()
.smartDocument(buildSDSection(vorgang))
.customerData(
CustomerData.builder()
.vorgang(vorgang)
.userData(buildUserData(request.getCreateFor()))
.bescheid(BescheidData.builder().bescheidVom(request.getBescheidVom()).genehmigt(request.isGenehmigt()).build())
.build())
.build());
}
private UserData buildUserData(UserProfile userProfile) {
return UserData.builder()
.firstName(userProfile.getFirstName())
.lastName(userProfile.getLastName())
.email(userProfile.getEmail())
.build();
}
private SmartDocumentsRequest.SmartDocument buildSDSection(Vorgang vorgang) {
return SmartDocumentsRequest.SmartDocument.builder().selection(Selection.builder()
.templateGroup(properties.getTemplateGroup())
.template(vorgang.getVorgangName())
.build())
.build();
}
private SmartDocumentsRequest logRequest(SmartDocumentsRequest request) {
LOG.debug(() -> {
var ojMapper = new ObjectMapper();
try {
return ojMapper.writeValueAsString(request);
} catch (JsonProcessingException e) {
LOG.warn("Json Processing Exception on logging request.", e);
return request.toString();
}
});
return request;
}
@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
static class SmartDocumentsResponse {
Collection<SmartDocumentFile> file;
@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
static class SmartDocumentFile {
private String filename;
private SmartDocumentDocument document;
private String outputFormat;
}
@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
static class SmartDocumentDocument {
@JsonDeserialize(using = FileDataDeserializer.class)
private File data;
}
}
}
package de.ozgcloud.bescheid.smartdocuments;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.ExchangeFilterFunctions;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import reactor.netty.transport.ProxyProvider;
@Configuration
@ConditionalOnProperty("ozgcloud.bescheid.smart-documents.url")
class SmartDocumentsConfiguration {
@Autowired
private SmartDocumentsProperties properties;
@Bean("smartDocuments")
WebClient smartDocumentsWebClient() {
ReactorClientHttpConnector connector = new ReactorClientHttpConnector(buildHttpClient());
return WebClient.builder()
.baseUrl(properties.getUrl())
.filter(ExchangeFilterFunctions.basicAuthentication(properties.getBasicAuth().getUsername(), properties.getBasicAuth().getPassword()))
.clientConnector(connector)
.build();
}
private HttpClient buildHttpClient() {
if (properties.getProxy() != null) {
return createProxyHttpClient();
} else {
return createNoProxyHttpClient();
}
}
private HttpClient createNoProxyHttpClient() {
return HttpClient.create();
}
private HttpClient createProxyHttpClient() {
return HttpClient.create()
.proxy(proxy -> proxy.type(ProxyProvider.Proxy.HTTP)
.host(properties.getProxy().getHost())
.port(properties.getProxy().getPort())
.username(properties.getProxy().getUsername())
.password(username -> properties.getProxy().getPassword()));
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment