Skip to content

Commit

Permalink
Comments
Browse files Browse the repository at this point in the history
Max Zollbrecht committed Apr 22, 2024
1 parent 3e7e7a0 commit fb59371
Showing 21 changed files with 203 additions and 72 deletions.
Original file line number Diff line number Diff line change
@@ -1,32 +1,13 @@
package de.muenchen.rbs.kitafindereai;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class KitaFinderEaiApplication implements CommandLineRunner {

@Override
public void run(String... arg0) throws Exception {
if (arg0.length > 0 && arg0[0].equals("exitcode")) {
throw new ExitException();
}
}
public class KitaFinderEaiApplication {

public static void main(String[] args) throws Exception {
new SpringApplication(KitaFinderEaiApplication.class).run(args);
}

class ExitException extends RuntimeException implements ExitCodeGenerator {
private static final long serialVersionUID = 1L;

@Override
public int getExitCode() {
return 10;
}

}

}
Original file line number Diff line number Diff line change
@@ -23,7 +23,9 @@
import lombok.extern.slf4j.Slf4j;

/**
* Adapter handling calls to kitafinder.
*
* @author m.zollbrecht
*/
@Slf4j
@Component
Original file line number Diff line number Diff line change
@@ -16,7 +16,10 @@
import lombok.extern.slf4j.Slf4j;

/**
* Service to call kitafinder using stored config data in the form of
* {@linkplain KitafinderKitaKonfigData}.
*
* @author m.zollbrecht
*/
@Slf4j
@Service
Original file line number Diff line number Diff line change
@@ -11,7 +11,9 @@
import lombok.NoArgsConstructor;

/**
* Wrapper of kitafinder-export data.
*
* @author m.zollbrecht
*/
@Data
@NoArgsConstructor
Original file line number Diff line number Diff line change
@@ -11,7 +11,9 @@
import lombok.NoArgsConstructor;

/**
* A child as received from kitafinder.
*
* @author m.zollbrecht
*/
@Data
@NoArgsConstructor
Original file line number Diff line number Diff line change
@@ -14,7 +14,9 @@
import lombok.NoArgsConstructor;

/**
* A list of children as received from kitafinder.
*
* @author m.zollbrecht
*/
@Data
@NoArgsConstructor
Original file line number Diff line number Diff line change
@@ -15,8 +15,9 @@
import org.springframework.web.bind.annotation.RestController;

import de.muenchen.rbs.kitafindereai.data.KitafinderKitaKonfigData;
import de.muenchen.rbs.kitafindereai.data.KitafinderKitaKonfigDataDto;
import de.muenchen.rbs.kitafindereai.data.KitafinderKitaKonfigDataReadDto;
import de.muenchen.rbs.kitafindereai.data.KitafinderKitaKonfigDataRepository;
import de.muenchen.rbs.kitafindereai.data.KitafinderKitaKonfigDataWriteDto;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -40,29 +41,42 @@ public class InternalApiController {
ModelMapper mapper;

@PostMapping("kitadata/{kibigWebId}")
public ResponseEntity<KitafinderKitaKonfigDataDto> saveKitafinderKitaKonfig(
public ResponseEntity<KitafinderKitaKonfigDataReadDto> saveKitafinderKitaKonfig(
@Parameter(in = ParameterIn.PATH, description = "kibigWebId der Einrichtung für die Kinddaten abgerufen werden", required = true, schema = @Schema(type = "string", description = "KibigwebId 162(für München) - 001 (für Städtisch) - \\d (Art/Form der Einrichtung) - \\d{3} (Nummer der Einrichtung)", example = "1620018207")) @PathVariable("kibigWebId") String kibigWebId,
@RequestBody KitafinderKitaKonfigData data) {
if (!kibigWebId.equals(data.getKibigwebId())) {
ResponseEntity.unprocessableEntity().build();
}
@RequestBody KitafinderKitaKonfigDataWriteDto data) {
log.info("Endpoint POST kitadata/{} was called. Updating/saving the received data...", kibigWebId);
Optional<KitafinderKitaKonfigData> kitaKonfig = repository.findById(kibigWebId);

// retrieve existing data or get default
KitafinderKitaKonfigData kitaKonfigData = kitaKonfig.orElseGet(() -> {
KitafinderKitaKonfigData defaultData = new KitafinderKitaKonfigData();
defaultData.setKibigwebId(kibigWebId);
return defaultData;
});

data.setPassword(encryptor.encrypt(data.getPassword()));
KitafinderKitaKonfigData savedData = repository.save(data);
// Update with POSTed values
kitaKonfigData.setPassword(encryptor.encrypt(data.getPassword()));
kitaKonfigData.setKitaIdExtern(data.getKitaIdExtern());
kitaKonfigData.setTraeger(data.getTraeger());

// save
KitafinderKitaKonfigData savedData = repository.save(kitaKonfigData);

KitafinderKitaKonfigDataDto dto = mapper.map(savedData, KitafinderKitaKonfigDataDto.class);
// return saved data
KitafinderKitaKonfigDataReadDto dto = mapper.map(savedData, KitafinderKitaKonfigDataReadDto.class);
return ResponseEntity.ok().body(dto);
}

@GetMapping("kitadata/{kibigWebId}")
public ResponseEntity<KitafinderKitaKonfigDataDto> getKitafinderKitaKonfig(
public ResponseEntity<KitafinderKitaKonfigDataReadDto> getKitafinderKitaKonfig(
@Parameter(in = ParameterIn.PATH, description = "kibigWebId der Einrichtung für die Kinddaten abgerufen werden", required = true, schema = @Schema(type = "string", description = "KibigwebId 162(für München) - 001 (für Städtisch) - \\d (Art/Form der Einrichtung) - \\d{3} (Nummer der Einrichtung)", example = "1620018207")) @PathVariable("kibigWebId") String kibigWebId) {
log.info("Endpoint GET kitadata/{} was called. Retrieving the stored data...", kibigWebId);
Optional<KitafinderKitaKonfigData> kitaKonfig = repository.findById(kibigWebId);

if (kitaKonfig.isEmpty()) {
return ResponseEntity.notFound().build();
} else {
KitafinderKitaKonfigDataDto dto = mapper.map(kitaKonfig.get(), KitafinderKitaKonfigDataDto.class);
KitafinderKitaKonfigDataReadDto dto = mapper.map(kitaKonfig.get(), KitafinderKitaKonfigDataReadDto.class);
return ResponseEntity.ok().body(dto);
}
}
Original file line number Diff line number Diff line change
@@ -58,7 +58,7 @@ public class KitaAppApiController {
@GetMapping("einrichtungen/{kibigWebId}/mitGruppenUndKindern")
public ResponseEntity<Institute> getGroupsWithKidsByKibigwebid(
@Parameter(in = ParameterIn.PATH, description = "kibigWebId der Einrichtung für die Kinddaten abgerufen werden", required = true, schema = @Schema(type = "string", description = "KibigwebId 162(für München) - 001 (für Städtisch) - \\d (Art/Form der Einrichtung) - \\d{3} (Nummer der Einrichtung)", example = "1620018207")) @PathVariable("kibigWebId") String kibigWebId) {
log.info("Endpoint einrichtungen/{}/mitGruppenUndKindern called.", kibigWebId);
log.info("Endpoint GET einrichtungen/{}/mitGruppenUndKindern called.", kibigWebId);

KitafinderExport export = kitaFinderService.exportKitaData(kibigWebId);
Institute institute = mapper.map(export.getDatensaetze(), Institute.class);
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@
import lombok.NoArgsConstructor;

/**
* Adresse des Kindes. Wird aus der Adresse der SB1 | SB2 bzw. der abweichenden (ABW) Adresse berechnet. Berechnung abhängig von [WOHNHAFT_BEI]
* Adress
*/
@Data
@NoArgsConstructor
Original file line number Diff line number Diff line change
@@ -36,7 +36,7 @@ public class Parent {
// Kitafinder-Column [SB1_NACHNAME | SB2_NACHNAME | ABW_NACHNAME]
private String lastName;

enum ParentType {
public enum ParentType {
sb1, sb2, abw;
}

Original file line number Diff line number Diff line change
@@ -18,8 +18,7 @@
import lombok.RequiredArgsConstructor;

/**
* ControllerAdvice für globales Handling von Exceptions, die z.B. von Services geworfen werden
* können.
* ControllerAdvice for global handling of exceptions.
*
* @author m.zollbrecht
*/
Original file line number Diff line number Diff line change
@@ -4,26 +4,38 @@
*/
package de.muenchen.rbs.kitafindereai.config;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Optional;

import org.modelmapper.Converter;
import org.modelmapper.ModelMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import de.muenchen.rbs.kitafindereai.adapter.kitaplaner.model.KitafinderKind;
import de.muenchen.rbs.kitafindereai.adapter.kitaplaner.model.KitafinderKindList;
import de.muenchen.rbs.kitafindereai.api.model.Child;
import de.muenchen.rbs.kitafindereai.api.model.ChildAddress;
import de.muenchen.rbs.kitafindereai.api.model.Group;
import de.muenchen.rbs.kitafindereai.api.model.Institute;
import de.muenchen.rbs.kitafindereai.api.model.Parent;
import de.muenchen.rbs.kitafindereai.api.model.Parent.ParentType;

/**
* Create a ModelMapper to expose as a Bean.
*
* @author m.zollbrecht
*/
@Configuration
public class ModelMapperConfiguration {

public static DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd'.'MM'.'yyyy", Locale.GERMAN);

@Bean
public ModelMapper modelMapper() {
ModelMapper mapper = new ModelMapper();
@@ -58,10 +70,48 @@ public ModelMapper modelMapper() {
}
});

Converter<String, LocalDate> dateConverter = context -> {
if (context.getSource() == null || context.getSource().length() == 0) {
return null;
}
return LocalDate.parse(context.getSource(), DATE_FORMATTER);
};

Converter<KitafinderKind, ChildAddress> adressConverter = context -> {
if (context == null || context.getSource() == null) {
return null;
}
// TODO: dependent on WOHNHAFT_BEI
ChildAddress adress = new ChildAddress();
adress.setCity(context.getSource().getSB1_ORT());
adress.setStreet(context.getSource().getSB1_STRASSE());
adress.setStreetNo(context.getSource().getSB1_HAUSNUMMER());
adress.setZipCode(context.getSource().getSB1_POSTLEITZAHL());
return adress;
};

Converter<KitafinderKind, Collection<Parent>> parentConverter = context -> {
if (context == null || context.getSource() == null) {
return null;
}
// TODO: add ABW
List<Parent> parents = List.of(
new Parent(ParentType.sb1, context.getSource().getSB1_VORNAME(),
context.getSource().getSB1_NACHNAME()),
new Parent(ParentType.sb2, context.getSource().getSB2_VORNAME(),
context.getSource().getSB2_NACHNAME()));
return parents;
};

mapper.createTypeMap(KitafinderKind.class, Child.class).addMappings(m -> {
m.map(KitafinderKind::getKIND_ID_EXTERN, Child::setChildId);
m.map(KitafinderKind::getKIND_VORNAME, Child::setFirstName);
m.map(KitafinderKind::getKIND_NACHNAME, Child::setLastName);
// TODO remaining props
m.using(dateConverter).map(KitafinderKind::getKIND_GEBDATUM, Child::setBirthday);
m.using(dateConverter).map(KitafinderKind::getVER_VERTRAG_AB, Child::setCareStart);
m.using(dateConverter).map(KitafinderKind::getVER_KUENDIGUNG_ZUM, Child::setCareEnd);
m.using(adressConverter).map(k -> k, Child::setAddress);
m.using(parentConverter).map(k -> k, Child::setParents);
});

return mapper;
Original file line number Diff line number Diff line change
@@ -11,6 +11,8 @@

/**
* Configures the {@link RestTemplate}
*
* @author m.zollbrecht
*/
@Configuration
public class RestTemplateConfiguration {
Original file line number Diff line number Diff line change
@@ -14,18 +14,13 @@
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.User.UserBuilder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.jwt.JwtClaimValidator;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtDecoders;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

import de.muenchen.rbs.kitafindereai.api.InternalApiController;
import de.muenchen.rbs.kitafindereai.api.KitaAppApiController;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.security.OAuthFlow;
import io.swagger.v3.oas.annotations.security.OAuthFlows;
@@ -34,13 +29,16 @@

/**
* The central class for configuration of all security aspects.
*
* @author m.zollbrecht
*/
@Slf4j
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration {

/** Security for {@link InternalApiController} */
@Bean
@Order(1)
@Profile("!no-security")
@@ -52,6 +50,7 @@ public SecurityFilterChain internalApiSecurityFilterChain(HttpSecurity http) thr
return http.build();
}

/** Security for {@link KitaAppApiController} */
@Bean
@Order(2)
@Profile("!no-security")
@@ -65,12 +64,16 @@ public SecurityFilterChain kitaAppApiSecurityFilterChain(HttpSecurity http) thro
return http.build();
}

/**
* Security for remaining endpoints.
* Excluding Swagger UI and spring actuators.
*/
@Bean
@Order(3)
@Profile("!no-security")
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/actuator/info", "/actuator/health/**", "/explorer/**",
.requestMatchers("/actuator/info", "/actuator/health/**",
"/swagger-ui/**", "/v3/api-docs/**")
.permitAll()
.anyRequest().authenticated())
@@ -80,16 +83,23 @@ public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws
return http.build();
}

/**
* UserDetailsService for BasicAuth
*
* @param user User for BasicAuth
* @param password Password for BasicAuth
* @return UserDetailsService for BasicAuth
*/
@Bean
@Profile("!no-security")
public UserDetailsService userDetailsService(@Value("${app.internalApi.authentication.user}") String user,
@Value("${app.internalApi.authentication.password}") String password) {
UserBuilder users = User.withDefaultPasswordEncoder();
UserDetails userDetails = users.username(user).password(password).build();
UserDetails userDetails = User.withDefaultPasswordEncoder().username(user).password(password).build();

return new InMemoryUserDetailsManager(userDetails);
}

/** Security-config for profile 'no-security' */
@Bean
@Profile("no-security")
public SecurityFilterChain noSecurityFilterChain(HttpSecurity http)
@@ -100,6 +110,7 @@ public SecurityFilterChain noSecurityFilterChain(HttpSecurity http)
return http.build();
}

/** Swagger-API config for security */
@Configuration
@SecurityScheme(name = "OAUTH2", type = SecuritySchemeType.OAUTH2, flows = @OAuthFlows(clientCredentials = @OAuthFlow(tokenUrl = "${app.security.token-url}")))
@SecurityScheme(name = "BasicAuth", type = SecuritySchemeType.HTTP, scheme = "basic")
Loading

0 comments on commit fb59371

Please sign in to comment.