mirror of
https://github.com/OkaeriPoland/okaeri-timings.git
synced 2026-01-18 03:28:20 +01:00
Create backend parser concept
This commit is contained in:
@@ -0,0 +1,13 @@
|
|||||||
|
package eu.okaeri.timings.api;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class IndexController {
|
||||||
|
|
||||||
|
@RequestMapping
|
||||||
|
public String index() {
|
||||||
|
return "redirect:/swagger-ui";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package eu.okaeri.timings.api.security;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||||
|
import org.springframework.web.filter.CorsFilter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http.httpBasic().disable();
|
||||||
|
http.csrf().disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CorsFilter corsFilter() {
|
||||||
|
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||||
|
CorsConfiguration config = new CorsConfiguration();
|
||||||
|
config.setAllowCredentials(true);
|
||||||
|
config.setAllowedOrigins(List.of("*"));
|
||||||
|
config.setAllowedHeaders(Arrays.asList("Origin", "Content-Type", "Accept", "Authorization"));
|
||||||
|
config.setAllowedMethods(List.of("*"));
|
||||||
|
source.registerCorsConfiguration("/**", config);
|
||||||
|
return new CorsFilter(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package eu.okaeri.timings.api.v1;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestPart;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/v1/parse")
|
||||||
|
public class ParseController {
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
|
public ResponseEntity<?> parse(@RequestPart("file") MultipartFile file) {
|
||||||
|
|
||||||
|
if (!"text/csv".equals(file.getContentType())) {
|
||||||
|
return ResponseEntity.badRequest().body(Map.of("error", "Expected text/csv, got: " + file.getContentType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
String content = new String(file.getBytes(), StandardCharsets.UTF_8);
|
||||||
|
String[] lines = content.split("\r?\n");
|
||||||
|
|
||||||
|
Map<String, String> metadata = new LinkedHashMap<>();
|
||||||
|
List<String> header = null;
|
||||||
|
List<List<BigDecimal>> records = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String line : lines) {
|
||||||
|
|
||||||
|
// metadata
|
||||||
|
if (line.startsWith("#")) {
|
||||||
|
if (!line.contains(":")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String[] parts = line.substring(1).split(":", 2);
|
||||||
|
if (parts.length != 2) {
|
||||||
|
throw new RuntimeException("Cannot parse metadata: '" + line + "'");
|
||||||
|
}
|
||||||
|
String key = parts[0].trim().toLowerCase(Locale.ROOT);
|
||||||
|
String value = parts[1].trim();
|
||||||
|
metadata.put(key, value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// header
|
||||||
|
if (header == null) {
|
||||||
|
String[] parts = line.split(",");
|
||||||
|
if (parts.length < 2) {
|
||||||
|
throw new RuntimeException("Cannot parse header: '" + line + "'");
|
||||||
|
}
|
||||||
|
header = Arrays.asList(parts);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// data
|
||||||
|
String[] parts = line.split(",");
|
||||||
|
if (parts.length != header.size()) {
|
||||||
|
throw new RuntimeException("Cannot parse record: '" + line + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
records.add(Arrays.stream(parts)
|
||||||
|
.map(value -> {
|
||||||
|
try {
|
||||||
|
return new BigDecimal(value);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
throw new RuntimeException("Cannot parse value: '" + value + "' from record '" + line + "'");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header == null || records.size() < 2) {
|
||||||
|
throw new RuntimeException("Invalid report");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseEntity.ok(Map.of(
|
||||||
|
"meta", metadata,
|
||||||
|
"header", header,
|
||||||
|
"data", records
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,9 +20,11 @@ springdoc:
|
|||||||
default-produces-media-type: "application/json"
|
default-produces-media-type: "application/json"
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
data:
|
servlet:
|
||||||
rest:
|
multipart:
|
||||||
base-path: /rest
|
enabled: true
|
||||||
|
max-file-size: 1MB
|
||||||
|
max-request-size: 1MB
|
||||||
redis:
|
redis:
|
||||||
host: 127.0.0.1
|
host: 127.0.0.1
|
||||||
port: 6379
|
port: 6379
|
||||||
|
|||||||
Reference in New Issue
Block a user