[DEV] better interface with search and filter

This commit is contained in:
Edouard DUPIN 2023-01-03 23:53:52 +01:00
parent 585630aeda
commit bd96b836d7
5 changed files with 247 additions and 28 deletions

View File

@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.kar</groupId> <groupId>org.kar</groupId>
<artifactId>karanage</artifactId> <artifactId>karanage</artifactId>
<version>0.1.0</version> <version>0.2.0</version>
<properties> <properties>
<maven.compiler.version>3.1</maven.compiler.version> <maven.compiler.version>3.1</maven.compiler.version>
@ -22,7 +22,7 @@
<dependency> <dependency>
<groupId>kangaroo-and-rabbit</groupId> <groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId> <artifactId>archidata</artifactId>
<version>0.1.5</version> <version>0.2.0</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -11,11 +11,16 @@ import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.server.ResourceConfig;
import org.kar.karanage.api.Front; import org.kar.karanage.api.Front;
import org.kar.karanage.api.HealthCheck; import org.kar.karanage.api.HealthCheck;
import org.kar.karanage.api.StateHistoryResource;
import org.kar.karanage.api.StateResource; import org.kar.karanage.api.StateResource;
import org.kar.karanage.api.UserResource; import org.kar.karanage.api.UserResource;
import org.kar.archidata.GlobalConfiguration; import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.SqlWrapper; import org.kar.archidata.SqlWrapper;
import org.kar.archidata.UpdateJwtPublicKey; import org.kar.archidata.UpdateJwtPublicKey;
import org.kar.archidata.catcher.ExceptionCatcher;
import org.kar.archidata.catcher.FailExceptionCatcher;
import org.kar.archidata.catcher.InputExceptionCatcher;
import org.kar.archidata.catcher.SystemExceptionCatcher;
import org.kar.archidata.filter.AuthenticationFilter; import org.kar.archidata.filter.AuthenticationFilter;
import org.kar.archidata.filter.CORSFilter; import org.kar.archidata.filter.CORSFilter;
import org.kar.archidata.filter.OptionFilter; import org.kar.archidata.filter.OptionFilter;
@ -60,9 +65,16 @@ public class WebLauncher {
rc.register(new CORSFilter()); rc.register(new CORSFilter());
// global authentication system // global authentication system
rc.registerClasses(AuthenticationFilter.class); rc.registerClasses(AuthenticationFilter.class);
// register exception catcher
rc.register(InputExceptionCatcher.class);
rc.register(SystemExceptionCatcher.class);
rc.register(FailExceptionCatcher.class);
rc.register(ExceptionCatcher.class);
// add default resource: // add default resource:
rc.registerClasses(UserResource.class); rc.registerClasses(UserResource.class);
rc.registerClasses(StateResource.class); rc.registerClasses(StateResource.class);
rc.registerClasses(StateHistoryResource.class);
rc.registerClasses(HealthCheck.class); rc.registerClasses(HealthCheck.class);
rc.registerClasses(Front.class); rc.registerClasses(Front.class);

View File

@ -0,0 +1,129 @@
package org.kar.karanage.api;
import org.kar.archidata.SqlWrapper;
import org.kar.archidata.WhereCondition;
import org.kar.karanage.model.DataInstant;
import org.kar.karanage.model.DataHistory;
import org.kar.karanage.model.Group;
import javax.ws.rs.core.Response;
import org.kar.archidata.annotation.security.PermitAll;
import org.kar.archidata.exception.FailException;
import org.kar.archidata.exception.InputException;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;
@Path("/state_history")
@Produces({MediaType.APPLICATION_JSON})
public class StateHistoryResource {
@GET
@Path("{group}/{topic:.*}")
//@RolesAllowed("USER")
@PermitAll
public static String get(
@PathParam("group") String groupName,
@PathParam("topic") String topic,
@QueryParam("since") String since,
@QueryParam("sinceId") Integer sinceId,
@QueryParam("limit") Integer limit) throws Exception {
// Keep Group ID:
if (groupName == null || groupName.length() == 0) {
throw new InputException("group", "Missing URL parameter /state/{group}/...");
}
Group group = SqlWrapper.getWhere(Group.class,
List.of(
new WhereCondition("name", "=", groupName)
),
false);
if (group == null) {
throw new InputException("group", "url: /state/{group}/... ==> Unknown group name");
}
if (topic == null || topic.length() == 0) {
throw new InputException("topic", "Missing URL parameter /state/xxx/{topic}/...");
}
if (limit == null || limit == 0) {
limit = 100;
}
if (limit > 100) {
limit = 100;
}
if (limit < 0) {
throw new InputException("limit", "Limit must be inside [1..100]");
}
if (since != null && sinceId != null) {
throw new InputException("since,sinceId", "The 2 parameters can not be set at the same time...");
}
List<DataHistory> datas = null;
if (since != null) {
Timestamp time = null;
try {
time = Timestamp.from(Instant.parse(since));
} catch (Exception ex) {
throw new InputException("since", "url: ?since=... ==> is not an iso 8601 time format");
}
datas = SqlWrapper.getsWhere(DataHistory.class,
List.of(
new WhereCondition("group", "=", group.id),
new WhereCondition("topic", "=", topic),
new WhereCondition("modify_date", ">", time)
),
"modify_date",
true,
limit);
if (datas == null) {
throw new FailException(Response.Status.NOT_FOUND, "Topic has no new data or does not exist: '" + topic + "'");
}
} else if (sinceId != null) {
datas = SqlWrapper.getsWhere(DataHistory.class,
List.of(
new WhereCondition("group", "=", group.id),
new WhereCondition("topic", "=", topic),
new WhereCondition("id", ">", sinceId)
),
"id",
true,
limit);
if (datas == null) {
throw new FailException(Response.Status.NOT_FOUND, "Topic has no new data or does not exist: '" + topic + "'");
}
} else {
datas = SqlWrapper.getsWhere(DataHistory.class,
List.of(
new WhereCondition("group", "=", group.id),
new WhereCondition("topic", "=", topic)
),
"id",
true,
limit);
if (datas == null) {
throw new FailException(Response.Status.NOT_FOUND, "Topic does not exist: '" + topic + "'");
}
}
StringBuilder out = new StringBuilder("[");
boolean first = true;
for (DataInstant data : datas) {
if (first) {
first = false;
} else {
out.append(",");
}
out.append("{ \"id\": " + data.id + ", \"time\": \"" + data.modify_date.toInstant().toString() + "\", \"data\":" + data.data + "}");
}
out.append("]");
return out.toString();
}
}

View File

@ -1,6 +1,7 @@
package org.kar.karanage.api; package org.kar.karanage.api;
import org.kar.archidata.SqlWrapper; import org.kar.archidata.SqlWrapper;
import org.kar.archidata.WhereCondition;
import org.kar.karanage.model.DataInstant; import org.kar.karanage.model.DataInstant;
import org.kar.karanage.model.DataHistory; import org.kar.karanage.model.DataHistory;
import org.kar.karanage.model.Group; import org.kar.karanage.model.Group;
@ -8,6 +9,9 @@ import javax.ws.rs.core.Response;
import org.kar.archidata.annotation.security.PermitAll; import org.kar.archidata.annotation.security.PermitAll;
import org.kar.archidata.exception.FailException;
import org.kar.archidata.exception.InputException;
import javax.ws.rs.*; import javax.ws.rs.*;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
@ -26,35 +30,94 @@ public class StateResource {
@Path("{group}/{topic:.*}") @Path("{group}/{topic:.*}")
//@RolesAllowed("USER") //@RolesAllowed("USER")
@PermitAll @PermitAll
public static String getWithTopic(@PathParam("group") String groupName, @PathParam("topic") String topic) throws Exception { public static String getWithTopic(
Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName); @PathParam("group") String groupName,
if (group == null) { @PathParam("topic") String topic,
throw new Exception("Missing Group !!!"); @QueryParam("since") String since) throws Exception {
if (groupName == null || groupName.length() == 0) {
throw new InputException("group", "Missing URL parameter /state/{group}/...");
} }
DataInstant data = SqlWrapper.getWhere(DataInstant.class, "group", "=", group.id, "topic", "=", topic, true); Group group = SqlWrapper.getWhere(Group.class,
List.of(
return "{ \"time\": \"" + data.modify_date.toLocalDateTime().toString() + "\", \"data\":" + data.data + "}"; new WhereCondition("name", "=", groupName)
),
false);
if (group == null) {
throw new InputException("group", "url: /state/{group}/... ==> Unknown group name");
}
DataInstant data = null;
if (since != null) {
Timestamp time = null;
try {
time = Timestamp.from(Instant.parse(since));
} catch (Exception ex) {
throw new InputException("since", "url: ?since=... ==> is not an iso 8601 time format");
}
data = SqlWrapper.getWhere(DataInstant.class,
List.of(
new WhereCondition("group", "=", group.id),
new WhereCondition("topic", "=", topic),
new WhereCondition("modify_date", ">", time)
),
true);
if (data == null) {
throw new FailException(Response.Status.NOT_FOUND, "Topic has no new data or does not exist: '" + topic + "'");
}
} else {
data = SqlWrapper.getWhere(DataInstant.class,
List.of(
new WhereCondition("group", "=", group.id),
new WhereCondition("topic", "=", topic)
),
true);
if (data == null) {
throw new FailException(Response.Status.NOT_FOUND, "Topic does not exist: '" + topic + "'");
}
}
return "{ \"time\": \"" + data.modify_date.toInstant().toString() + "\", \"data\":" + data.data + "}";
} }
/*
public static DataInstant getWithTopic(@PathParam("group") String groupName, @PathParam("topic") String topic) throws Exception {
Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName);
if (group == null) {
throw new Exception("Missing Group !!!");
}
return SqlWrapper.getWhere(DataInstant.class, "group", "=", group.id, "topic", "=", topic);
}*/
@GET @GET
@Path("{group}") @Path("{group}")
//@RolesAllowed("USER") //@RolesAllowed("USER")
@PermitAll @PermitAll
public String get(@PathParam("group") String groupName) throws Exception { public String get(
Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName); @PathParam("group") String groupName,
@QueryParam("since") String since) throws Exception {
if (groupName == null || groupName.length() == 0) {
throw new InputException("group", "Missing URL parameter /state/{group}/...");
}
Group group = SqlWrapper.getWhere(Group.class,
List.of(
new WhereCondition("name", "=", groupName)
),
false);
if (group == null) { if (group == null) {
throw new Exception("Missing Group !!!"); throw new InputException("group", "url: /state/{group}/... ==> Unknown group name");
}
List<DataInstant> datas = null;
if (since != null) {
Timestamp time = null;
try {
time = Timestamp.from(Instant.parse(since));
} catch (Exception ex) {
throw new InputException("since", "url: ?since=... ==> is not an iso 8601 time format");
}
datas = SqlWrapper.getsWhere(DataInstant.class,
List.of(
new WhereCondition("group", "=", group.id),
new WhereCondition("modify_date", ">", time)
),
true);
} else {
datas = SqlWrapper.getsWhere(DataInstant.class,
List.of(
new WhereCondition("group", "=", group.id)
),
true);
} }
StringBuilder out = new StringBuilder("["); StringBuilder out = new StringBuilder("[");
List<DataInstant> datas = SqlWrapper.getsWhere(DataInstant.class, "group", "=", group.id, true);
boolean first = true; boolean first = true;
for (DataInstant data : datas) { for (DataInstant data : datas) {
if (first) { if (first) {
@ -62,7 +125,7 @@ public class StateResource {
} else { } else {
out.append(","); out.append(",");
} }
out.append("{ \"time\": \"" + data.modify_date.toLocalDateTime().toString() + "\", \"topic\": \"" + data.topic + "\", \"data\":" + data.data + "}"); out.append("{ \"time\": \"" + data.modify_date.toInstant().toString() + "\", \"topic\": \"" + data.topic + "\", \"data\":" + data.data + "}");
} }
out.append("]"); out.append("]");
return out.toString(); return out.toString();
@ -82,11 +145,27 @@ public class StateResource {
//@RolesAllowed("ADMIN") //@RolesAllowed("ADMIN")
@PermitAll @PermitAll
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Response post(@PathParam("group") String groupName, @PathParam("topic") String topic, String dataToInsert) throws Exception { public Response post(
@PathParam("group") String groupName,
@PathParam("topic") String topic,
String dataToInsert) throws Exception {
DataInstant previous = null; DataInstant previous = null;
Group group = SqlWrapper.getWhere(Group.class, "name", "=", groupName);
Group group = SqlWrapper.getWhere(Group.class,
List.of(
new WhereCondition("name", "=", groupName)
),
false);
if (group == null) {
throw new InputException("group", "url: /state/{group}/... ==> Unknown group name");
}
if (group != null) { if (group != null) {
previous = SqlWrapper.getWhere(DataInstant.class, "group", "=", group.id, "topic", "=", topic, true); previous = SqlWrapper.getWhere(DataInstant.class,
List.of(
new WhereCondition("group", "=", group.id),
new WhereCondition("topic", "=", topic)
),
true);
} }
if (previous == null) { if (previous == null) {
// insert new data // insert new data
@ -111,7 +190,6 @@ public class StateResource {
DataHistory dataHistory = new DataHistory(previous); DataHistory dataHistory = new DataHistory(previous);
OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC ); OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC );
OffsetDateTime sqlTime = OffsetDateTime.ofInstant(Instant.ofEpochMilli(previous.modify_date.getTime()), ZoneOffset.UTC); OffsetDateTime sqlTime = OffsetDateTime.ofInstant(Instant.ofEpochMilli(previous.modify_date.getTime()), ZoneOffset.UTC);
//tstamp = Timestamp.valueOf(ofsdatetime.atZoneSameInstant(ZoneOffset.UTC).toLocalDateTime())
now.getDayOfMonth(); now.getDayOfMonth();
if (sqlTime.getYear() != now.getYear()) { if (sqlTime.getYear() != now.getYear()) {

View File

@ -1,11 +1,11 @@
package org.kar.karanage.api; package org.kar.karanage.api;
import org.kar.archidata.SqlWrapper;
import org.kar.archidata.filter.GenericContext; import org.kar.archidata.filter.GenericContext;
import org.kar.archidata.model.User; import org.kar.archidata.model.User;
import org.kar.karanage.model.UserKaranage; import org.kar.karanage.model.UserKaranage;
import org.kar.archidata.SqlWrapper;
import org.kar.archidata.annotation.security.RolesAllowed; import org.kar.archidata.annotation.security.RolesAllowed;
import javax.ws.rs.*; import javax.ws.rs.*;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;