diff --git a/build.gradle b/build.gradle index 0a81b99..c5286a8 100644 --- a/build.gradle +++ b/build.gradle @@ -62,6 +62,7 @@ dependencies { implementation name: 'testlib-fat-0.3.1-all' implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '4.12.0' + implementation 'com.maxmind.geoip2:geoip2:4.2.0' implementation project(':referral') diff --git a/src/main/java/ru/soune/nocopy/dto/violation/ViolationResponse.java b/src/main/java/ru/soune/nocopy/dto/violation/ViolationResponse.java index 94f1321..9c0bf7e 100644 --- a/src/main/java/ru/soune/nocopy/dto/violation/ViolationResponse.java +++ b/src/main/java/ru/soune/nocopy/dto/violation/ViolationResponse.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Builder; import lombok.Data; import ru.soune.nocopy.entity.violation.Violation; +import ru.soune.nocopy.service.geo.GeoCountryService; import java.time.LocalDateTime; import java.util.List; @@ -12,6 +13,8 @@ import java.util.List; @Builder public class ViolationResponse { + private final GeoCountryService geoCountryService; + @JsonProperty("violations") private List violations; @@ -58,6 +61,9 @@ public class ViolationResponse { @JsonProperty("created_date") private LocalDateTime createdDate; + @JsonProperty("country") + private String country; + @JsonProperty("file_id") private String fileId; diff --git a/src/main/java/ru/soune/nocopy/handler/ViolationHandler.java b/src/main/java/ru/soune/nocopy/handler/ViolationHandler.java index 8b658b4..1b6c26b 100644 --- a/src/main/java/ru/soune/nocopy/handler/ViolationHandler.java +++ b/src/main/java/ru/soune/nocopy/handler/ViolationHandler.java @@ -13,6 +13,7 @@ import ru.soune.nocopy.entity.file.FileEntity; import ru.soune.nocopy.entity.violation.Violation; import ru.soune.nocopy.repository.FileEntityRepository; import ru.soune.nocopy.service.file.FileEntityService; +import ru.soune.nocopy.service.geo.GeoCountryService; import ru.soune.nocopy.service.register.AuthService; import ru.soune.nocopy.service.violation.ViolationService; import ru.soune.nocopy.service.violation.ViolationStatus; @@ -21,6 +22,7 @@ import java.io.FileNotFoundException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -38,6 +40,8 @@ public class ViolationHandler implements RequestHandler { private final FileEntityService fileEntityService; + private final GeoCountryService geoCountryService; + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); @Override @@ -112,10 +116,20 @@ public class ViolationHandler implements RequestHandler { ); } - List violationDtos = violationPage.getContent() - .stream() - .map(ViolationResponse.ViolationDto::fromEntity) - .toList(); + List content = violationPage.getContent(); + List violationDtos = new ArrayList<>(); + +// List violationDtos = violationPage.getContent() +// .stream() +// .map(ViolationResponse.ViolationDto::fromEntity) +// .toList(); + + for (Violation violation : content) { + ViolationResponse.ViolationDto violationDto = ViolationResponse.ViolationDto.fromEntity(violation); + violationDto.setCountry(geoCountryService.getCountry(violation.getHost())); + + violationDtos.add(violationDto); + } ViolationResponse response = ViolationResponse.builder() .violations(violationDtos) diff --git a/src/main/java/ru/soune/nocopy/service/geo/GeoCountryService.java b/src/main/java/ru/soune/nocopy/service/geo/GeoCountryService.java new file mode 100644 index 0000000..b88ad6d --- /dev/null +++ b/src/main/java/ru/soune/nocopy/service/geo/GeoCountryService.java @@ -0,0 +1,51 @@ +package ru.soune.nocopy.service.geo; + +import com.maxmind.geoip2.DatabaseReader; +import com.maxmind.geoip2.model.CountryResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.net.InetAddress; + +@Service +@Slf4j +public class GeoCountryService { + + private final DatabaseReader dbReader; + + public GeoCountryService() throws IOException { + Resource resource = new ClassPathResource("geo/GeoLite2-Country.mmdb"); + this.dbReader = new DatabaseReader.Builder(resource.getInputStream()).build(); + } + + public String getCountry(String input) { + try { + String domain = extractDomain(input); + + InetAddress ip = InetAddress.getByName(domain); + + CountryResponse response = dbReader.country(ip); + + return response.getCountry().getIsoCode(); + + } catch (Exception e) { + log.error("Failed for input: {}", input, e); + return "UNKNOWN"; + } + } + + private String extractDomain(String input) { + if (input == null || input.isEmpty()) { + throw new IllegalArgumentException("Input is empty"); + } + + String cleaned = input.replaceAll("^https?://", ""); + cleaned = cleaned.split("/")[0]; + cleaned = cleaned.split(":")[0]; + + return cleaned; + } +} diff --git a/src/main/resources/geo/GeoLite2-Country.mmdb b/src/main/resources/geo/GeoLite2-Country.mmdb new file mode 100644 index 0000000..e47ec55 Binary files /dev/null and b/src/main/resources/geo/GeoLite2-Country.mmdb differ