Skip to content

Commit

Permalink
Merge pull request #132 from virtualidentityag/release-2024-03-20
Browse files Browse the repository at this point in the history
release 2024-03-20
  • Loading branch information
web-mi authored Mar 20, 2024
2 parents d01674d + a43226d commit c4c472e
Show file tree
Hide file tree
Showing 42 changed files with 805 additions and 91 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/dockerImage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:
push_to_registry:
strategy:
matrix:
registry: ["docker.pkg.github.com", "ghcr.io"]
registry: ["ghcr.io"]
needs: [test]
name: Push Docker image to GitHub Packages
runs-on: ubuntu-latest
Expand Down
12 changes: 12 additions & 0 deletions api/agencyadminservice.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,9 @@ components:
dataProtection:
type: object
$ref: '#/components/schemas/DataProtectionDTO'
agencyLogo:
type: string
example: "base64 encoded image"

DataProtectionDTO:
type: object
Expand Down Expand Up @@ -630,6 +633,12 @@ components:
items:
type: string
enum: [ RELATIVE_COUNSELLING, SELF_COUNSELLING, PARENTAL_COUNSELLING]
dataProtection:
type: object
$ref: '#/components/schemas/DataProtectionDTO'
agencyLogo:
type: string
example: "base64 encoded image"

AgencyAdminFullResponseDTO:
type: object
Expand Down Expand Up @@ -693,6 +702,9 @@ components:
dataProtection:
type: object
$ref: '#/components/schemas/DataProtectionDTO'
agencyLogo:
type: string
example: "base64 encoded image"

DemographicsDTO:
type: object
Expand Down
9 changes: 8 additions & 1 deletion api/agencyservice.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ paths:
parameters:
- name: postcode
in: query
required: true
required: false
description: The postcode the user entered
schema:
type: string
Expand Down Expand Up @@ -175,6 +175,13 @@ components:
agencySpecificPrivacy:
type: string
example: "specific for agency privacy text"
topicIds:
type: array
items:
type: long
agencyLogo:
type: string
example: "base64 encoded image"

FullAgencyResponseDTO:
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,13 @@ public class AgencyAdminService {
private final @NonNull AgencyTopicMergeService agencyTopicMergeService;
private final @NonNull AppointmentService appointmentService;

private final @NonNull DataProtectionConverter dataProtectionConverter;
@Autowired(required = false)
private AgencyTopicEnrichmentService agencyTopicEnrichmentService;

@Autowired(required = false)
private DemographicsConverter demographicsConverter;

@Autowired
private DataProtectionConverter dataProtectionConverter;

@Value("${feature.topics.enabled}")
private boolean featureTopicsEnabled;
Expand Down Expand Up @@ -141,13 +140,15 @@ private Agency fromAgencyDTO(AgencyDTO agencyDTO) {
.url(agencyDTO.getUrl())
.isExternal(agencyDTO.getExternal())
.counsellingRelations(Joiner.on(",").join(agencyDTO.getCounsellingRelations()))
.agencyLogo(agencyDTO.getAgencyLogo())
.createDate(LocalDateTime.now(ZoneOffset.UTC))
.updateDate(LocalDateTime.now(ZoneOffset.UTC));


if (featureDemographicsEnabled && agencyDTO.getDemographics() != null) {
demographicsConverter.convertToEntity(agencyDTO.getDemographics(), agencyBuilder);
}

dataProtectionConverter.convertToEntity(agencyDTO.getDataProtection(), agencyBuilder);
var agencyToCreate = agencyBuilder.build();

if (featureTopicsEnabled) {
Expand Down Expand Up @@ -208,11 +209,10 @@ private Agency mergeAgencies(Agency agency, UpdateAgencyDTO updateAgencyDTO) {
.createDate(agency.getCreateDate())
.updateDate(LocalDateTime.now(ZoneOffset.UTC))
.counsellingRelations(agency.getCounsellingRelations())
.deleteDate(agency.getDeleteDate());
.deleteDate(agency.getDeleteDate())
.agencyLogo(updateAgencyDTO.getAgencyLogo());

if (dataProtectionConverter != null) {
dataProtectionConverter.convertToEntity(updateAgencyDTO.getDataProtection(), agencyBuilder);
}
dataProtectionConverter.convertToEntity(updateAgencyDTO.getDataProtection(), agencyBuilder);

if (nonNull(updateAgencyDTO.getConsultingType())) {
agencyBuilder.consultingTypeId(updateAgencyDTO.getConsultingType());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ private AgencyAdminResponseDTO createAgency() {
.createDate(String.valueOf(this.agency.getCreateDate()))
.updateDate(String.valueOf(this.agency.getUpdateDate()))
.deleteDate(String.valueOf(this.agency.getDeleteDate()))
.dataProtection(new DataProtectionDTOBuilder(this.agency).fromAgency());
.dataProtection(new DataProtectionDTOBuilder(this.agency).fromAgency())
.agencyLogo(this.agency.getAgencyLogo());

responseDTO.demographics(getDemographics(this.agency));
return responseDTO;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
import de.caritas.cob.agencyservice.api.admin.validation.validators.annotation.CreateAgencyValidator;
import de.caritas.cob.agencyservice.api.admin.validation.validators.annotation.UpdateAgencyValidator;
import de.caritas.cob.agencyservice.api.admin.validation.validators.model.ValidateAgencyDTO;
import de.caritas.cob.agencyservice.api.exception.httpresponses.BadRequestException;
import de.caritas.cob.agencyservice.api.model.AgencyDTO;
import de.caritas.cob.agencyservice.api.model.UpdateAgencyDTO;
import de.caritas.cob.agencyservice.api.repository.agency.AgencyRepository;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationContext;
Expand All @@ -20,6 +22,8 @@ public class AgencyValidator {

private final @NonNull ApplicationContext applicationContext;

private final @NonNull AgencyRepository agencyRepository;

/**
* Validates an {@link AgencyDTO}.
*
Expand Down Expand Up @@ -53,15 +57,19 @@ private ValidateAgencyDTO fromAgencyDto(AgencyDTO agencyDto) {
.postcode(agencyDto.getPostcode())
.consultingType(agencyDto.getConsultingType())
.demographicsDTO(agencyDto.getDemographics())
.tenantId(agencyDto.getTenantId())
.build();
}

private ValidateAgencyDTO fromUpdateAgencyDto(Long agencyId, UpdateAgencyDTO updateAgencyDTO) {
var existingAgency = agencyRepository.findById(agencyId).orElseThrow(() -> new BadRequestException("Agency with id " + agencyId + "not found!"));
return ValidateAgencyDTO.builder()
.id(agencyId)
.postcode(updateAgencyDTO.getPostcode())
.offline(updateAgencyDTO.getOffline())
.tenantId(existingAgency.getTenantId())
.demographicsDTO(updateAgencyDTO.getDemographics())
.dataProtectionDTO(updateAgencyDTO.getDataProtection())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package de.caritas.cob.agencyservice.api.admin.validation.validators;

import static de.caritas.cob.agencyservice.api.model.DataProtectionDTO.DataProtectionResponsibleEntityEnum.AGENCY_RESPONSIBLE;
import static de.caritas.cob.agencyservice.api.model.DataProtectionDTO.DataProtectionResponsibleEntityEnum.ALTERNATIVE_REPRESENTATIVE;
import static de.caritas.cob.agencyservice.api.model.DataProtectionDTO.DataProtectionResponsibleEntityEnum.DATA_PROTECTION_OFFICER;
import static org.apache.commons.lang3.StringUtils.isBlank;

import de.caritas.cob.agencyservice.api.admin.validation.validators.model.ValidateAgencyDTO;
import de.caritas.cob.agencyservice.api.exception.httpresponses.HttpStatusExceptionReason;
import de.caritas.cob.agencyservice.api.exception.httpresponses.InvalidOfflineStatusException;
import de.caritas.cob.agencyservice.api.model.DataProtectionContactDTO;
import de.caritas.cob.agencyservice.api.repository.agency.DataProtectionPlaceHolderType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class AgencyDataProtectionValidationService {

public void validate(ValidateAgencyDTO validateAgencyDto) {
validateThatDataProtectionDtoExists(validateAgencyDto);
validateIfDataProtectionOfficer(validateAgencyDto);
validateIfAgencyResponsible(validateAgencyDto);
validateIfAlternativeRepresentative(validateAgencyDto);
}

private void validateThatDataProtectionDtoExists(ValidateAgencyDTO validateAgencyDto) {
if (validateAgencyDto.getDataProtectionDTO() == null) {
log.warn(
"Could not save agency with id {} status. Required fields for data protection officer is empty.",
validateAgencyDto.getId());
throw new InvalidOfflineStatusException(
HttpStatusExceptionReason.DATA_PROTECTION_DTO_IS_NULL);
}
}

private void validateIfDataProtectionOfficer(ValidateAgencyDTO validateAgencyDto) {
if (DATA_PROTECTION_OFFICER.equals(
validateAgencyDto.getDataProtectionDTO().getDataProtectionResponsibleEntity())
&& areFieldsEmpty(
validateAgencyDto.getDataProtectionDTO().getDataProtectionOfficerContact())) {
log.warn(
"Could not save agency with id {}. Required fields for data protection officer is empty.",
validateAgencyDto.getId());
throw new InvalidOfflineStatusException(
HttpStatusExceptionReason.DATA_PROTECTION_OFFICER_IS_EMPTY);
}
}

private void validateIfAgencyResponsible(ValidateAgencyDTO validateAgencyDto) {
if (AGENCY_RESPONSIBLE.equals(
validateAgencyDto.getDataProtectionDTO().getDataProtectionResponsibleEntity())
&& areFieldsEmpty(
validateAgencyDto.getDataProtectionDTO().getAgencyDataProtectionResponsibleContact())) {
log.warn(
"Could not save agency with id {} status. Required fields for agency responsible is empty.",
validateAgencyDto.getId());
throw new InvalidOfflineStatusException(
HttpStatusExceptionReason.DATA_PROTECTION_RESPONSIBLE_IS_EMPTY);
}
}

private void validateIfAlternativeRepresentative(ValidateAgencyDTO validateAgencyDto) {
if (ALTERNATIVE_REPRESENTATIVE.equals(
validateAgencyDto.getDataProtectionDTO().getDataProtectionResponsibleEntity())
&& areFieldsEmpty(validateAgencyDto.getDataProtectionDTO()
.getAlternativeDataProtectionRepresentativeContact())) {
log.warn(
"Could not save agency with id {} status. Required fields for alternative responsible is empty.",
validateAgencyDto.getId());
throw new InvalidOfflineStatusException(
HttpStatusExceptionReason.DATA_PROTECTION_ALTERNATIVE_RESPONSIBLE_IS_EMPTY);
}
}

private boolean areFieldsEmpty(DataProtectionContactDTO dataProtectionOfficerContact) {
return dataProtectionOfficerContact == null
|| isBlank(dataProtectionOfficerContact.getNameAndLegalForm())
|| isBlank(dataProtectionOfficerContact.getCity())
|| isBlank(dataProtectionOfficerContact.getPostcode())
|| isBlank(dataProtectionOfficerContact.getEmail());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package de.caritas.cob.agencyservice.api.admin.validation.validators;

import de.caritas.cob.agencyservice.api.admin.validation.validators.annotation.UpdateAgencyValidator;
import de.caritas.cob.agencyservice.api.admin.validation.validators.model.ValidateAgencyDTO;
import de.caritas.cob.agencyservice.api.service.ApplicationSettingsService;
import de.caritas.cob.agencyservice.api.service.TenantService;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
@UpdateAgencyValidator
@Slf4j
public class AgencyDataProtectionValidator implements ConcreteAgencyValidator {

private final @NonNull TenantService tenantService;

private final @NonNull ApplicationSettingsService applicationSettingsService;

private final @NonNull AgencyDataProtectionValidationService agencyDataProtectionValidationService;

@Value("${feature.multitenancy.with.single.domain.enabled}")
private boolean multitenancyWithSingleDomain;

@Override
public void validate(ValidateAgencyDTO validateAgencyDto) {

var tenant = tenantService.getRestrictedTenantDataByTenantId(validateAgencyDto.getTenantId());

if (Boolean.TRUE.equals(tenant.getSettings().getFeatureCentralDataProtectionTemplateEnabled())) {
log.info("Validating agency data protection for agency with id {}.", validateAgencyDto.getId());
agencyDataProtectionValidationService.validate(validateAgencyDto);
}

if (multitenancyWithSingleDomain) {
var mainTenantSubdomainForSingleDomainMultitenancy = applicationSettingsService.getApplicationSettings()
.getMainTenantSubdomainForSingleDomainMultitenancy();
de.caritas.cob.agencyservice.tenantservice.generated.web.model.RestrictedTenantDTO mainTenant = tenantService.getRestrictedTenantDataBySubdomain(
mainTenantSubdomainForSingleDomainMultitenancy.getValue());
if (Boolean.TRUE.equals(mainTenant.getSettings().getFeatureCentralDataProtectionTemplateEnabled())) {
agencyDataProtectionValidationService.validate(validateAgencyDto);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import de.caritas.cob.agencyservice.consultingtypeservice.generated.web.model.ExtendedConsultingTypeResponseDTO;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/*
Expand All @@ -24,6 +25,7 @@
@Component
@RequiredArgsConstructor
@UpdateAgencyValidator
@Slf4j
public class AgencyOfflineStatusValidator implements ConcreteAgencyValidator {

private final @NonNull AgencyRepository agencyRepository;
Expand All @@ -48,7 +50,6 @@ public void validate(ValidateAgencyDTO validateAgencyDto) {
if (hasNoConsultant(validateAgencyDto)) {
throw new InvalidOfflineStatusException(AGENCY_CONTAINS_NO_CONSULTANTS);
}

}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.caritas.cob.agencyservice.api.admin.validation.validators.model;

import de.caritas.cob.agencyservice.api.model.DataProtectionDTO;
import de.caritas.cob.agencyservice.api.model.DemographicsDTO;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -18,6 +19,9 @@ public class ValidateAgencyDTO {
private String postcode;
private Integer consultingType;
private Boolean offline;
private Long tenantId;
private DemographicsDTO demographicsDTO;

private DataProtectionDTO dataProtectionDTO;

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import de.caritas.cob.agencyservice.generated.api.controller.AgenciesApi;
import io.swagger.annotations.Api;
import java.util.List;
import java.util.Optional;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
Expand Down Expand Up @@ -38,14 +39,14 @@ public class AgencyController implements AgenciesApi {
*/
@Override
public ResponseEntity<List<FullAgencyResponseDTO>> getAgencies(
@RequestParam String postcode, @RequestParam Integer consultingType,
@RequestParam Integer consultingType, @RequestParam(required = false) String postcode,
@RequestParam(value = "topicId", required = false) Integer topicId,
@RequestParam(value = "age", required = false) Integer age,
@RequestParam(value = "gender", required = false) String gender,
@RequestParam(value = "counsellingRelation", required = false) String counsellingRelation
) {

var agencies = agencyService.getAgencies(postcode, consultingType,
var agencies = agencyService.getAgencies(Optional.ofNullable(postcode), consultingType,
ofNullable(topicId), ofNullable(age), ofNullable(gender), ofNullable(counsellingRelation));

return !CollectionUtils.isEmpty(agencies)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,12 @@ public enum HttpStatusExceptionReason {
AGENCY_CONTAINS_NO_CONSULTANTS,
AGENCY_IS_ALREADY_TEAM_AGENCY,
AGENCY_IS_ALREADY_DEFAULT_AGENCY,
DATA_PROTECTION_OFFICER_IS_EMPTY,
DATA_PROTECTION_RESPONSIBLE_IS_EMPTY,

DATA_PROTECTION_ALTERNATIVE_RESPONSIBLE_IS_EMPTY,

DATA_PROTECTION_DTO_IS_NULL,

AGENCY_ACCESS_DENIED
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ private Integer getPostCodeInteger() {
@Column(name = "counselling_relations")
private String counsellingRelations;

@Column(name = "agency_logo")
private String agencyLogo;

@Transient
public boolean hasAnyDemographicsAttributes() {
return getAgeTo() != null || getAgeFrom() != null || getGenders() != null;
Expand Down
Loading

0 comments on commit c4c472e

Please sign in to comment.