Compare commits

..

10 Commits

Author SHA1 Message Date
dependabot[bot]
7889bf48da Bump org.springframework.cloud:spring-cloud-dependencies
Some checks failed
deploy to hetzner / deploy (push) Failing after 7m27s
Bumps [org.springframework.cloud:spring-cloud-dependencies](https://github.com/spring-cloud/spring-cloud-release) from 2023.0.3 to 2024.0.0.
- [Release notes](https://github.com/spring-cloud/spring-cloud-release/releases)
- [Commits](https://github.com/spring-cloud/spring-cloud-release/compare/v2023.0.3...v2024.0.0)

---
updated-dependencies:
- dependency-name: org.springframework.cloud:spring-cloud-dependencies
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-12 00:06:31 +01:00
dependabot[bot]
ab230ef715 Bump org.springframework.boot:spring-boot-starter-parent
Bumps [org.springframework.boot:spring-boot-starter-parent](https://github.com/spring-projects/spring-boot) from 3.3.5 to 3.4.0.
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.5...v3.4.0)

---
updated-dependencies:
- dependency-name: org.springframework.boot:spring-boot-starter-parent
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-12 00:06:18 +01:00
dependabot[bot]
dfe260f412 Bump org.springdoc:springdoc-openapi-starter-webmvc-ui
Bumps [org.springdoc:springdoc-openapi-starter-webmvc-ui](https://github.com/springdoc/springdoc-openapi) from 2.6.0 to 2.7.0.
- [Release notes](https://github.com/springdoc/springdoc-openapi/releases)
- [Changelog](https://github.com/springdoc/springdoc-openapi/blob/main/CHANGELOG.md)
- [Commits](https://github.com/springdoc/springdoc-openapi/compare/v2.6.0...v2.7.0)

---
updated-dependencies:
- dependency-name: org.springdoc:springdoc-openapi-starter-webmvc-ui
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-12 00:04:28 +01:00
dependabot[bot]
577c97f1bb Bump org.springframework.modulith:spring-modulith-bom
Bumps [org.springframework.modulith:spring-modulith-bom](https://github.com/spring-projects/spring-modulith) from 1.2.5 to 1.3.0.
- [Release notes](https://github.com/spring-projects/spring-modulith/releases)
- [Commits](https://github.com/spring-projects/spring-modulith/compare/1.2.5...1.3.0)

---
updated-dependencies:
- dependency-name: org.springframework.modulith:spring-modulith-bom
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-12 00:02:56 +01:00
ee1ab34631 Revert "fixing opentelemetry uri"
This reverts commit 2dae9c9e14.
2024-11-01 22:54:22 +01:00
2dae9c9e14 fixing opentelemetry uri
Signed-off-by: Peter Siegmund <developer@mars3142.org>
2024-11-01 22:51:36 +01:00
8000a26aad reactivate testing
Signed-off-by: Peter Siegmund <developer@mars3142.org>
2024-10-30 19:22:22 +01:00
3c2eea0eb5 rename main package name
Signed-off-by: Peter Siegmund <developer@mars3142.org>
2024-10-30 12:09:51 +01:00
a184f4a038 remove hal+json and add pageable
Signed-off-by: Peter Siegmund <developer@mars3142.org>
2024-10-30 12:02:30 +01:00
46dd36a846 more hal+json optimisation
Signed-off-by: Peter Siegmund <developer@mars3142.org>
2024-10-29 09:42:30 +01:00
24 changed files with 134 additions and 103 deletions

View File

@@ -5,7 +5,7 @@
<env name="EUREKA" value="http://localhost:8761/eureka" />
</envs>
<module name="timezone-service" />
<option name="SPRING_BOOT_MAIN_CLASS" value="dev.mars3142.fhq.timezone_service.Application" />
<option name="SPRING_BOOT_MAIN_CLASS" value="dev.mars3142.fhq.timezone.Application" />
<method v="2">
<option name="Make" enabled="true" />
</method>

View File

@@ -3,7 +3,7 @@
<module name="timezone-service" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="dev.mars3142.fhq.timezone_service.*" />
<option name="PATTERN" value="dev.mars3142.fhq.timezone.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>

16
pom.xml
View File

@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
<version>3.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>dev.mars3142.fhq</groupId>
@@ -28,8 +28,8 @@
</scm>
<properties>
<java.version>17</java.version>
<spring-modulith.version>1.2.5</spring-modulith.version>
<spring-cloud.version>2023.0.3</spring-cloud.version>
<spring-modulith.version>1.3.0</spring-modulith.version>
<spring-cloud.version>2024.0.0</spring-cloud.version>
</properties>
<dependencies>
<dependency>
@@ -54,6 +54,10 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.modulith</groupId>
<artifactId>spring-modulith-starter-test</artifactId>
@@ -82,10 +86,6 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
@@ -94,7 +94,7 @@
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.6.0</version>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>

View File

@@ -1,4 +1,4 @@
package dev.mars3142.fhq.timezone_service;
package dev.mars3142.fhq.timezone;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

View File

@@ -1,4 +1,4 @@
package dev.mars3142.fhq.timezone_service.config;
package dev.mars3142.fhq.timezone.config;
import java.time.Duration;
import java.time.temporal.ChronoUnit;

View File

@@ -1,4 +1,4 @@
package dev.mars3142.fhq.timezone_service.config;
package dev.mars3142.fhq.timezone.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;

View File

@@ -1,4 +1,4 @@
package dev.mars3142.fhq.timezone_service.config;
package dev.mars3142.fhq.timezone.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;

View File

@@ -1,4 +1,4 @@
package dev.mars3142.fhq.timezone_service.exceptions;
package dev.mars3142.fhq.timezone.exceptions;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

View File

@@ -1,17 +1,18 @@
package dev.mars3142.fhq.timezone_service.timezone.controllers;
package dev.mars3142.fhq.timezone.timezone.controllers;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import dev.mars3142.fhq.timezone_service.timezone.domain.model.response.LocationResponse;
import dev.mars3142.fhq.timezone_service.timezone.domain.model.response.TimezoneResponse;
import dev.mars3142.fhq.timezone_service.timezone.service.TimezoneService;
import dev.mars3142.fhq.timezone.timezone.domain.model.response.TimezoneResponse;
import dev.mars3142.fhq.timezone.timezone.service.TimezoneService;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
@@ -25,23 +26,28 @@ public class TimezoneController {
@GetMapping
@ResponseStatus(HttpStatus.OK)
public TimezoneResponse getTimeZone(
@RequestHeader(value = "X-Forwarded-For", defaultValue = "127.0.0.1") String header) {
val clientIp = header.split(",")[0];
@RequestHeader(value = "X-Forwarded-For", defaultValue = "127.0.0.1") String header_ip) {
val clientIp = header_ip.split(",")[0];
val ip = timeZoneService.getExternalIp(clientIp);
val timezoneInfo = timeZoneService.getTimeZoneInfoByIp(ip);
val posix = timeZoneService.getPosixTimeZone(timezoneInfo.timezone());
val response = new TimezoneResponse();
response.setTimezone(timezoneInfo.timezone());
response.setPosix_tz(posix);
response.add(linkTo(TimezoneController.class).slash(ip).withSelfRel());
return response;
}
@GetMapping("{area}")
@ResponseStatus(HttpStatus.OK)
public LocationResponse getLocations(@PathVariable String area) {
val locations = timeZoneService.getLocations(area);
return new LocationResponse(locations.size(), locations);
public Page<String> getLocations(@PathVariable String area,
@RequestParam(value = "pageSize", required = false, defaultValue = "10") int pageSize,
@RequestParam(value = "page", required = false, defaultValue = "0") int page,
@RequestParam(value = "direction", required = false) String direction) {
var pageRequest = PageRequest.of(page, pageSize);
if (direction != null && !direction.isEmpty()) {
pageRequest = PageRequest.of(page, pageSize, Direction.fromString(direction), "location");
}
return timeZoneService.getPagedLocations(area, pageRequest);
}
@GetMapping("{area}/{location}")
@@ -52,7 +58,6 @@ public class TimezoneController {
val response = new TimezoneResponse();
response.setTimezone(timezone);
response.setPosix_tz(posix);
response.add(linkTo(TimezoneController.class).slash(area).slash(location).withSelfRel());
return response;
}
}

View File

@@ -1,4 +1,4 @@
package dev.mars3142.fhq.timezone_service.timezone.domain.entities.response;
package dev.mars3142.fhq.timezone.timezone.domain.entities.response;
public record IPApiResponse(String status, String country, String countryCode, String region, String regionName,
String city, String zip, String lat, String lon, String timezone, String isp, String or,

View File

@@ -0,0 +1,5 @@
package dev.mars3142.fhq.timezone.timezone.domain.entities.response;
public record IpifyResponse(String ip) {
}

View File

@@ -1,4 +1,4 @@
package dev.mars3142.fhq.timezone_service.timezone.domain.entities.response;
package dev.mars3142.fhq.timezone.timezone.domain.entities.response;
public record TimeApiTimezoneZoneResponse(Interval dstInterval) {

View File

@@ -0,0 +1,12 @@
package dev.mars3142.fhq.timezone.timezone.domain.model.response;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class TimezoneResponse {
private String timezone;
private String posix_tz;
}

View File

@@ -0,0 +1,19 @@
package dev.mars3142.fhq.timezone.timezone.service;
import dev.mars3142.fhq.timezone.timezone.domain.entities.response.IPApiResponse;
import dev.mars3142.fhq.timezone.timezone.domain.entities.response.TimeApiTimezoneZoneResponse;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
public interface TimezoneService {
String getExternalIp(String ip);
IPApiResponse getTimeZoneInfoByIp(String ip);
TimeApiTimezoneZoneResponse getTimeZoneInfo(String timezone);
String getPosixTimeZone(String timezone);
Page<String> getPagedLocations(String area, PageRequest pageRequest);
}

View File

@@ -1,10 +1,10 @@
package dev.mars3142.fhq.timezone_service.timezone.service.impl;
package dev.mars3142.fhq.timezone.timezone.service.impl;
import dev.mars3142.fhq.timezone_service.exceptions.NotFoundException;
import dev.mars3142.fhq.timezone_service.timezone.domain.entities.response.IPApiResponse;
import dev.mars3142.fhq.timezone_service.timezone.domain.entities.response.IpifyResponse;
import dev.mars3142.fhq.timezone_service.timezone.domain.entities.response.TimeApiTimezoneZoneResponse;
import dev.mars3142.fhq.timezone_service.timezone.service.TimezoneService;
import dev.mars3142.fhq.timezone.exceptions.NotFoundException;
import dev.mars3142.fhq.timezone.timezone.domain.entities.response.IPApiResponse;
import dev.mars3142.fhq.timezone.timezone.domain.entities.response.IpifyResponse;
import dev.mars3142.fhq.timezone.timezone.domain.entities.response.TimeApiTimezoneZoneResponse;
import dev.mars3142.fhq.timezone.timezone.service.TimezoneService;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
@@ -15,6 +15,9 @@ import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpStatusCode;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
@@ -48,18 +51,18 @@ public class TimezoneServiceImpl implements TimezoneService {
@Override
@Cacheable(value = "TZInfoByIp", key = "{#ip}")
public IPApiResponse getTimeZoneInfoByIp(String ip) {
return restClient
.get()
.uri(builder -> builder
.scheme("http")
.host("ip-api.com")
.path("json/" + ip)
.build())
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError, (request, response) -> {
throw new NotFoundException();
})
.body(IPApiResponse.class);
return restClient
.get()
.uri(builder -> builder
.scheme("http")
.host("ip-api.com")
.path("json/" + ip)
.build())
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError, (request, response) -> {
throw new NotFoundException();
})
.body(IPApiResponse.class);
}
@Override
@@ -97,19 +100,41 @@ public class TimezoneServiceImpl implements TimezoneService {
}
@Override
@Cacheable(value = "locations", key = "{#area}")
public List<String> getLocations(String area) {
@Cacheable(value = "locations", key = "{#area, #pageRequest}")
public Page<String> getPagedLocations(String area, PageRequest pageRequest) {
val directory = new File("/usr/share/zoneinfo/" + area);
if (!directory.exists()) {
throw new NotFoundException();
}
return Stream.of(Objects.requireNonNull(directory.listFiles()))
return toPage(Stream.of(Objects.requireNonNull(directory.listFiles()))
.filter(file -> !file.isDirectory())
.map(file -> {
val path = file.getPath().split("/");
return path[path.length - 2] + "/" + path[path.length - 1];
})
.sorted()
.toList();
.toList(), pageRequest);
}
Page<String> toPage(List<String> list, PageRequest pageRequest) {
val pageSize = pageRequest.getPageSize();
val pageNumber = pageRequest.getPageNumber();
val totalPages = list.size() / pageSize;
int max = pageNumber >= totalPages ? list.size() : pageSize * (pageNumber + 1);
int min = pageNumber > totalPages ? max : pageSize * pageNumber;
var content = list.stream().sorted((left, right) -> {
if (!pageRequest.getSort().isSorted()) {
return 0;
}
if (Objects.requireNonNull(pageRequest.getSort().getOrderFor("location")).isAscending()) {
return left.compareTo(right);
} else {
return right.compareTo(left);
}
}
);
return new PageImpl<>(content.toList().subList(min, max), pageRequest, list.size());
}
}

View File

@@ -1,5 +0,0 @@
package dev.mars3142.fhq.timezone_service.timezone.domain.entities.response;
public record IpifyResponse(String ip) {
}

View File

@@ -1,7 +0,0 @@
package dev.mars3142.fhq.timezone_service.timezone.domain.model.response;
import java.util.List;
public record LocationResponse(int count, List<String> locations) {
}

View File

@@ -1,15 +0,0 @@
package dev.mars3142.fhq.timezone_service.timezone.domain.model.response;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.springframework.hateoas.RepresentationModel;
@Getter
@Setter
@RequiredArgsConstructor
public class TimezoneResponse extends RepresentationModel<TimezoneResponse> {
private String timezone;
private String posix_tz;
}

View File

@@ -1,18 +0,0 @@
package dev.mars3142.fhq.timezone_service.timezone.service;
import dev.mars3142.fhq.timezone_service.timezone.domain.entities.response.IPApiResponse;
import dev.mars3142.fhq.timezone_service.timezone.domain.entities.response.TimeApiTimezoneZoneResponse;
import java.util.List;
public interface TimezoneService {
String getExternalIp(String ip);
IPApiResponse getTimeZoneInfoByIp(String ip);
TimeApiTimezoneZoneResponse getTimeZoneInfo(String timezone);
String getPosixTimeZone(String timezone);
List<String> getLocations(String area);
}

View File

@@ -1,7 +1,7 @@
eureka:
client:
register-with-eureka: true
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: ${EUREKA}

View File

@@ -1,4 +1,4 @@
package dev.mars3142.fhq.timezone_service;
package dev.mars3142.fhq.timezone;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

View File

@@ -1,4 +1,4 @@
package dev.mars3142.fhq.timezone_service.timezone.service.impl;
package dev.mars3142.fhq.timezone.timezone.service.impl;
import lombok.val;
import org.junit.jupiter.api.BeforeEach;
@@ -59,6 +59,6 @@ class TimezoneServiceImplTest {
}
@Test
void getLocations() {
void getPagedLocations() {
}
}

View File

@@ -1,4 +1,4 @@
package dev.mars3142.fhq.timezone_service.timezone.web.controllers;
package dev.mars3142.fhq.timezone.timezone.web.controllers;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;

View File

@@ -0,0 +1,10 @@
eureka:
client:
enabled: false
spring:
application:
name: timezone-service
cloud:
config:
enabled: false