add location logging, display last location on map
Signed-off-by: Nicolas Froger <nicolas@kektus.xyz>
This commit is contained in:
parent
4356816f07
commit
130581a411
13 changed files with 386 additions and 3 deletions
|
|
@ -0,0 +1,22 @@
|
|||
package fr.kektus.summer2024.converters;
|
||||
|
||||
import fr.kektus.summer2024.data.model.Location;
|
||||
import fr.kektus.summer2024.domain.entity.LocationEntity;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
@ApplicationScoped
|
||||
public class LocationConverter implements Converter<Location, LocationEntity> {
|
||||
@Override public Location toLeft(LocationEntity locationEntity) {
|
||||
return new Location().withId(locationEntity.id)
|
||||
.withLatitude(locationEntity.latitude)
|
||||
.withLongitude(locationEntity.longitude)
|
||||
.withTimestamp(locationEntity.timestamp);
|
||||
}
|
||||
|
||||
@Override public LocationEntity toRight(Location location) {
|
||||
return new LocationEntity().withId(location.id)
|
||||
.withLatitude(location.latitude)
|
||||
.withLongitude(location.longitude)
|
||||
.withTimestamp(location.timestamp);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package fr.kektus.summer2024.data.model;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.With;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
@Entity
|
||||
@AllArgsConstructor @NoArgsConstructor @With
|
||||
public class Location {
|
||||
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) public Long id;
|
||||
public ZonedDateTime timestamp;
|
||||
public Float latitude;
|
||||
public Float longitude;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package fr.kektus.summer2024.data.repository;
|
||||
|
||||
import fr.kektus.summer2024.data.model.Location;
|
||||
import io.quarkus.hibernate.orm.panache.PanacheRepository;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
@ApplicationScoped
|
||||
public class LocationRepository implements PanacheRepository<Location> {
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package fr.kektus.summer2024.domain.entity;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.With;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
@AllArgsConstructor @NoArgsConstructor @With
|
||||
public class LocationEntity {
|
||||
public Long id;
|
||||
public ZonedDateTime timestamp;
|
||||
public Float latitude;
|
||||
public Float longitude;
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package fr.kektus.summer2024.domain.service;
|
||||
|
||||
import fr.kektus.summer2024.converters.LocationConverter;
|
||||
import fr.kektus.summer2024.data.model.Location;
|
||||
import fr.kektus.summer2024.data.repository.LocationRepository;
|
||||
import fr.kektus.summer2024.domain.entity.LocationEntity;
|
||||
import io.quarkus.panache.common.Sort;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.transaction.Transactional;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
@ApplicationScoped
|
||||
public class LocationService {
|
||||
@Inject LocationRepository locationRepository;
|
||||
@Inject LocationConverter locationConverter;
|
||||
|
||||
@Transactional
|
||||
public LocationEntity createLocation(Float lat, Float lon) {
|
||||
final Location location = new Location().withLatitude(lat)
|
||||
.withLongitude(lon)
|
||||
.withTimestamp(ZonedDateTime.now());
|
||||
locationRepository.persist(location);
|
||||
return locationConverter.toRight(location);
|
||||
}
|
||||
|
||||
public LocationEntity getLatestLocation() {
|
||||
final Location lastLocation = locationRepository.findAll(Sort.descending("id")).firstResult();
|
||||
if (lastLocation == null)
|
||||
throw new NotFoundException();
|
||||
return locationConverter.toRight(lastLocation);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package fr.kektus.summer2024.presentation.rest;
|
||||
|
||||
import fr.kektus.summer2024.Validators;
|
||||
import fr.kektus.summer2024.domain.entity.LocationEntity;
|
||||
import fr.kektus.summer2024.domain.service.AuthService;
|
||||
import fr.kektus.summer2024.domain.service.LocationService;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.NotAuthorizedException;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.With;
|
||||
import org.jboss.resteasy.reactive.RestHeader;
|
||||
|
||||
@Path("/admin/location")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public class AdminLocationApi {
|
||||
@Inject AuthService authService;
|
||||
@Inject LocationService locationService;
|
||||
|
||||
@POST
|
||||
public LocationEntity createPost(@RestHeader("X-admin-token") final String adminToken,
|
||||
CreateLocation.Request request) {
|
||||
if (!authService.isAdminTokenValid(adminToken))
|
||||
throw new NotAuthorizedException("provided admin token is invalid");
|
||||
|
||||
Validators.assertNotNull(request, new BadRequestException());
|
||||
Validators.assertNotNull(request.latitude, new BadRequestException());
|
||||
Validators.assertNotNull(request.longitude, new BadRequestException());
|
||||
|
||||
return locationService.createLocation(request.latitude, request.longitude);
|
||||
}
|
||||
|
||||
public static class CreateLocation {
|
||||
@NoArgsConstructor @AllArgsConstructor @With
|
||||
public static class Request {
|
||||
public Float latitude;
|
||||
public Float longitude;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package fr.kektus.summer2024.presentation.rest;
|
||||
|
||||
import fr.kektus.summer2024.domain.entity.LocationEntity;
|
||||
import fr.kektus.summer2024.domain.service.LocationService;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
@Path("/location")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public class LocationApi {
|
||||
@Inject LocationService locationService;
|
||||
|
||||
@GET @Path("/last")
|
||||
public LocationEntity getLastLocation() {
|
||||
return locationService.getLatestLocation();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
create table Location
|
||||
(
|
||||
id bigserial not null primary key,
|
||||
latitude float4,
|
||||
longitude float4,
|
||||
timestamp timestamp(6) with time zone
|
||||
);
|
||||
Loading…
Add table
Add a link
Reference in a new issue