some fixes, added api key as param
This commit is contained in:
parent
dfbc1e00bd
commit
3c19a9191b
10 changed files with 74 additions and 100 deletions
|
|
@ -21,6 +21,7 @@ import java.util.List;
|
||||||
public class ApiKeyFilter extends OncePerRequestFilter {
|
public class ApiKeyFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
private static final String API_KEY_HEADER = "X-API-Key";
|
private static final String API_KEY_HEADER = "X-API-Key";
|
||||||
|
private static final String API_KEY_PARAM = "apiKey";
|
||||||
|
|
||||||
private static final List<String> PUBLIC_PATHS = List.of(
|
private static final List<String> PUBLIC_PATHS = List.of(
|
||||||
"/actuator/health",
|
"/actuator/health",
|
||||||
|
|
@ -29,7 +30,7 @@ public class ApiKeyFilter extends OncePerRequestFilter {
|
||||||
"/v3/api-docs"
|
"/v3/api-docs"
|
||||||
);
|
);
|
||||||
|
|
||||||
@Value("${taric.api-key}")
|
@Value("${taric.api.key}")
|
||||||
private String validApiKey;
|
private String validApiKey;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -39,7 +40,6 @@ public class ApiKeyFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
String path = request.getRequestURI();
|
String path = request.getRequestURI();
|
||||||
|
|
||||||
|
|
||||||
if ("OPTIONS".equals(request.getMethod())) {
|
if ("OPTIONS".equals(request.getMethod())) {
|
||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
return;
|
return;
|
||||||
|
|
@ -50,15 +50,9 @@ public class ApiKeyFilter extends OncePerRequestFilter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String apiKey = request.getHeader(API_KEY_HEADER);
|
String apiKey = extractApiKey(request);
|
||||||
|
|
||||||
if (apiKey == null) {
|
|
||||||
apiKey = request.getHeader(API_KEY_HEADER.toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (validApiKey != null && validApiKey.equals(apiKey)) {
|
if (validApiKey != null && validApiKey.equals(apiKey)) {
|
||||||
|
|
||||||
|
|
||||||
UsernamePasswordAuthenticationToken authentication =
|
UsernamePasswordAuthenticationToken authentication =
|
||||||
new UsernamePasswordAuthenticationToken(
|
new UsernamePasswordAuthenticationToken(
|
||||||
"api-user",
|
"api-user",
|
||||||
|
|
@ -76,6 +70,21 @@ public class ApiKeyFilter extends OncePerRequestFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String extractApiKey(HttpServletRequest request) {
|
||||||
|
|
||||||
|
String apiKey = request.getHeader(API_KEY_HEADER);
|
||||||
|
|
||||||
|
if (apiKey == null) {
|
||||||
|
apiKey = request.getHeader(API_KEY_HEADER.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apiKey == null) {
|
||||||
|
apiKey = request.getParameter(API_KEY_PARAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isPublicPath(String path) {
|
private boolean isPublicPath(String path) {
|
||||||
return PUBLIC_PATHS.stream().anyMatch(path::startsWith);
|
return PUBLIC_PATHS.stream().anyMatch(path::startsWith);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import de.avatic.taric.repository.MeasureActionRepository;
|
||||||
import de.avatic.taric.repository.MeasureRepository;
|
import de.avatic.taric.repository.MeasureRepository;
|
||||||
import de.avatic.taric.repository.MeasureSeriesRepository;
|
import de.avatic.taric.repository.MeasureSeriesRepository;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.media.Content;
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
|
@ -14,10 +15,9 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/measures")
|
@RequestMapping("/api/v1/measures")
|
||||||
@Tag(name = "Measures", description = "API endpoints for trade measures, measure series, and measure actions")
|
@Tag(name = "Measures", description = "API endpoints for trade measures, measure series, and measure actions")
|
||||||
|
|
@ -45,7 +45,12 @@ public class MeasureController {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public Iterable<Measure> getMeasures() {
|
public Iterable<Measure> getMeasures(@Parameter(description = "Optional series to filter measures by series")
|
||||||
|
@RequestParam(required = false) String series) {
|
||||||
|
|
||||||
|
if( series != null )
|
||||||
|
return measureRepository.findByMeasureSeries(series);
|
||||||
|
|
||||||
return measureRepository.findAll();
|
return measureRepository.findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.validation.constraints.Min;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
@ -65,8 +66,10 @@ public class NomenclatureController {
|
||||||
@GetMapping("/declarable")
|
@GetMapping("/declarable")
|
||||||
public List<Nomenclature> getDeclarable(
|
public List<Nomenclature> getDeclarable(
|
||||||
@Parameter(description = "Parent HS code to retrieve declarable children from", required = true)
|
@Parameter(description = "Parent HS code to retrieve declarable children from", required = true)
|
||||||
@RequestParam String hscode) {
|
@RequestParam String hscode,
|
||||||
return nomenclatureService.getDeclarableChildren(hscode);
|
@Parameter(description = "Limit (default =10)", required = true)
|
||||||
|
@RequestParam(required = false, defaultValue = "10") @Min(1) Integer limit) {
|
||||||
|
return nomenclatureService.getDeclarableChildren(hscode, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(
|
@Operation(
|
||||||
|
|
@ -84,7 +87,6 @@ public class NomenclatureController {
|
||||||
public List<Nomenclature> getCascade(
|
public List<Nomenclature> getCascade(
|
||||||
@Parameter(description = "HS code to retrieve the complete hierarchy for", required = true)
|
@Parameter(description = "HS code to retrieve the complete hierarchy for", required = true)
|
||||||
@RequestParam String hscode) {
|
@RequestParam String hscode) {
|
||||||
var found = nomenclatureService.getNomenclatureCascade(hscode);
|
return nomenclatureService.getNomenclatureCascade(hscode);
|
||||||
return found;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -55,9 +55,9 @@ public class TariffController {
|
||||||
@GetMapping("")
|
@GetMapping("")
|
||||||
public Map<String, Map<String, List<AppliedMeasure>>> getTariffRate(
|
public Map<String, Map<String, List<AppliedMeasure>>> getTariffRate(
|
||||||
@Parameter(description = "Harmonized System code (e.g., 0101210000)", required = true, example = "0101210000")
|
@Parameter(description = "Harmonized System code (e.g., 0101210000)", required = true, example = "0101210000")
|
||||||
@RequestParam String hsCode,
|
@RequestParam String hscode,
|
||||||
@Parameter(description = "ISO country code (e.g., US, CN, GB)", required = true, example = "US")
|
@Parameter(description = "ISO country code (e.g., US, CN, GB)", required = true, example = "US")
|
||||||
@RequestParam String countryCode) {
|
@RequestParam String countryCode) {
|
||||||
return tariffService.getAppliedMeasures(hsCode, countryCode);
|
return tariffService.getAppliedMeasures(hscode, countryCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,11 +2,15 @@ package de.avatic.taric.model;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
|
|
||||||
import jakarta.validation.constraints.Size;
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
public class MonetaryUnitDesc {
|
public class MonetaryUnitDesc {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
|
|
@ -19,43 +23,4 @@ public class MonetaryUnitDesc {
|
||||||
|
|
||||||
private LocalDate descStartDate;
|
private LocalDate descStartDate;
|
||||||
|
|
||||||
public MonetaryUnitDesc(String lang, String desc, LocalDate descStartDate) {
|
|
||||||
this.lang = lang;
|
|
||||||
this.desc = desc;
|
|
||||||
this.descStartDate = descStartDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(final Integer id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLang() {
|
|
||||||
return lang;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLang(final String lang) {
|
|
||||||
this.lang = lang;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDesc() {
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDescc(final String desc) {
|
|
||||||
this.desc = desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocalDate getDescStartDate() {
|
|
||||||
return descStartDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDescStartDate(final LocalDate descStartDate) {
|
|
||||||
this.descStartDate = descStartDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package de.avatic.taric.repository;
|
package de.avatic.taric.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.jdbc.repository.query.Query;
|
||||||
import org.springframework.data.repository.CrudRepository;
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
|
||||||
import de.avatic.taric.model.Measure;
|
import de.avatic.taric.model.Measure;
|
||||||
|
|
@ -7,4 +8,6 @@ import de.avatic.taric.model.Measure;
|
||||||
public interface MeasureRepository extends CrudRepository<Measure, Integer> {
|
public interface MeasureRepository extends CrudRepository<Measure, Integer> {
|
||||||
|
|
||||||
|
|
||||||
|
@Query("SELECT * FROM measure m LEFT JOIN measure_series s ON m.measure_series_id = s.id WHERE s.measure_series_code = :series")
|
||||||
|
Iterable<Measure> findByMeasureSeries(String series);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,25 @@
|
||||||
package de.avatic.taric.repository;
|
package de.avatic.taric.repository;
|
||||||
|
|
||||||
import de.avatic.taric.model.Nomenclature;
|
import de.avatic.taric.model.Nomenclature;
|
||||||
|
import org.springframework.data.domain.Limit;
|
||||||
import org.springframework.data.jdbc.repository.query.Query;
|
import org.springframework.data.jdbc.repository.query.Query;
|
||||||
import org.springframework.data.repository.CrudRepository;
|
import org.springframework.data.repository.CrudRepository;
|
||||||
import org.springframework.data.repository.query.Param;
|
import org.springframework.data.repository.query.Param;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface NomenclatureRepository extends CrudRepository<Nomenclature, Integer> {
|
public interface NomenclatureRepository extends CrudRepository<Nomenclature, Integer> {
|
||||||
|
|
||||||
|
|
||||||
@Query("SELECT * FROM nomenclature WHERE hscode = :hscode AND (end_date IS NULL OR end_date >= CURRENT_DATE)")
|
@Query("SELECT * FROM nomenclature WHERE hscode = :hscode AND (end_date IS NULL OR end_date >= CURRENT_DATE)")
|
||||||
Optional<Nomenclature> findByHscode(String hscode);
|
Optional<Nomenclature> findByHscode(String hscode);
|
||||||
|
|
||||||
@Query("SELECT * FROM nomenclature WHERE is_leaf = 1 AND hscode LIKE CONCAT(:code, '%') AND (end_date IS NULL OR end_date >= CURRENT_DATE)")
|
@Query("SELECT * FROM nomenclature WHERE is_leaf = 1 AND hscode LIKE CONCAT(:code, '%') AND (end_date IS NULL OR end_date >= CURRENT_DATE)")
|
||||||
List<Nomenclature> findDeclarableChildren(@Param("code") String code);
|
List<Nomenclature> findDeclarableChildren(@Param("code") String code);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -25,26 +25,32 @@ public class DescSetSerializer extends JsonSerializer<Set<Description>> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serialize(Set<Description> value, JsonGenerator gen, SerializerProvider serializer) throws IOException {
|
public void serialize(Set<Description> value, JsonGenerator gen, SerializerProvider serializer) throws IOException {
|
||||||
if (value != null) {
|
if (value == null || value.isEmpty()) {
|
||||||
var filtered = value;
|
gen.writeNull();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String language = LANGUAGE_CONTEXT.get();
|
String language = LANGUAGE_CONTEXT.get();
|
||||||
if (language != null) {
|
|
||||||
filtered = value.stream()
|
|
||||||
.filter(desc -> language.equalsIgnoreCase(desc.getLang()))
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filtered.isEmpty()) {
|
Set<Description> filtered = Set.of();
|
||||||
filtered = value.stream()
|
if (language != null) {
|
||||||
.filter(desc -> "EN".equalsIgnoreCase(desc.getLang()))
|
filtered = value.stream()
|
||||||
.collect(Collectors.toSet());
|
.filter(desc -> language.equalsIgnoreCase(desc.getLang()))
|
||||||
}
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
if(filtered.size() == 1)
|
if (filtered.isEmpty()) {
|
||||||
gen.writeObject(filtered.iterator().next());
|
filtered = value.stream()
|
||||||
else
|
.filter(desc -> "EN".equalsIgnoreCase(desc.getLang()))
|
||||||
gen.writeObject(filtered);
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filtered.isEmpty() && !value.isEmpty()) {
|
||||||
|
filtered = Set.of(value.iterator().next());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filtered.isEmpty()) {
|
||||||
|
gen.writeObject(filtered.iterator().next());
|
||||||
} else {
|
} else {
|
||||||
gen.writeNull();
|
gen.writeNull();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package de.avatic.taric.service;
|
||||||
|
|
||||||
import de.avatic.taric.model.Nomenclature;
|
import de.avatic.taric.model.Nomenclature;
|
||||||
import de.avatic.taric.repository.NomenclatureRepository;
|
import de.avatic.taric.repository.NomenclatureRepository;
|
||||||
|
import org.springframework.data.domain.Limit;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
@ -20,16 +21,11 @@ public class NomenclatureService {
|
||||||
return nomenclatureRepository.findByHscode(normalize(hscode.replaceAll("[^0-9]", "")));
|
return nomenclatureRepository.findByHscode(normalize(hscode.replaceAll("[^0-9]", "")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDeclarable(String hscode) {
|
public List<Nomenclature> getDeclarableChildren(String hscode, Integer limit) {
|
||||||
var nomenclature = getNomenclature(hscode);
|
// var normalized = normalize(hscode.replaceAll("[^0-9]", ""));
|
||||||
if (nomenclature.isEmpty()) return false;
|
// var level = getHierarchyLevel(normalized);
|
||||||
return nomenclature.get().getIsLeaf();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Nomenclature> getDeclarableChildren(String hscode) {
|
return nomenclatureRepository.findDeclarableChildren(hscode).stream().limit(limit).toList();
|
||||||
var normalized = normalize(hscode.replaceAll("[^0-9]", ""));
|
|
||||||
var level = getHierarchyLevel(normalized);
|
|
||||||
return nomenclatureRepository.findDeclarableChildren(normalized.substring(0, level));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Nomenclature> getNomenclatureCascade(String hscode) {
|
public List<Nomenclature> getNomenclatureCascade(String hscode) {
|
||||||
|
|
|
||||||
|
|
@ -63,23 +63,6 @@ public class TariffService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<Double> findTariff(Collection<AppliedMeasure> measures, Measure appl) {
|
|
||||||
|
|
||||||
var code = appl.getMeasureCode();
|
|
||||||
|
|
||||||
//TODO return all measures...
|
|
||||||
|
|
||||||
List<AppliedMeasure> filteredMeasures = measures.stream()
|
|
||||||
.filter(meas -> meas.getAmount() != null && meas.getAmount().trim().matches("\\d+\\.\\d+\\s*%"))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
AppliedMeasure customTariff = filteredMeasures.stream().filter(meas -> meas.getMeasure().getId().equals(appl.getId())).findAny().orElse(filteredMeasures.isEmpty() ? null : filteredMeasures.getFirst());
|
|
||||||
|
|
||||||
if (!filteredMeasures.isEmpty())
|
|
||||||
return Optional.of(customTariff).map(meas -> Double.parseDouble(meas.getAmount().trim().replace("%", "").trim()) / 100);
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<AppliedMeasure> findAppliedMeasureByGeo(Nomenclature nomenclature, Geo geo) {
|
public List<AppliedMeasure> findAppliedMeasureByGeo(Nomenclature nomenclature, Geo geo) {
|
||||||
|
|
||||||
var foundImport = importRepository.findByNomenclatureAndGeo(nomenclature.getId(), geo.getId());
|
var foundImport = importRepository.findByNomenclatureAndGeo(nomenclature.getId(), geo.getId());
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue