[New] Added CRUD services for notifications

This commit is contained in:
Robert von Burg 2024-02-27 16:44:53 +01:00
parent 7b9f2f867f
commit 22359e51d8
Signed by: eitch
GPG Key ID: 75DB9C85C74331F7
7 changed files with 303 additions and 15 deletions

View File

@ -97,5 +97,7 @@ public class StrolchConstants extends StrolchModelConstants {
public static final String PRIVILEGE_REMOVE_PREFIX = "Remove";
public static final String PRIVILEGE_GET_PREFIX = "Get";
public static final String PRIVILEGE_GET_NOTIFICATIONS = "GetNotifications";
public static final String PRIVILEGE_GET_NOTIFICATION = "GetNotification";
public static final String PRIVILEGE_GET_NOTIFICATIONS_ALL = "GetNotificationsAll";
}
}

View File

@ -105,9 +105,12 @@ public class StrolchModelConstants {
public static final String PARAM_GROUP = "group";
public static final String PARAM_VISIBLE_FROM = "visibleFrom";
public static final String PARAM_VISIBLE_TO = "visibleTo";
public static final String PARAM_TITLE = "title";
public static final String PARAM_TEXT = "text";
public static final String PARAM_FOR_ALL = "forAll";
public static final String PARAM_ROLES = "roles";
public static final String PARAM_LOCATIONS = "locations";
public static final String PARAM_LANGUAGES = "languages";
public static final String PARAM_GROUPS = "groups";
public static class PolicyConstants {

View File

@ -0,0 +1,104 @@
package li.strolch.service.notifications;
import com.google.gson.JsonObject;
import li.strolch.agent.api.StrolchAgent;
import li.strolch.model.ParameterBag;
import li.strolch.model.Resource;
import li.strolch.model.builder.ResourceBuilder;
import li.strolch.model.json.FromFlatJsonVisitor;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.runtime.configuration.SupportedLanguage;
import li.strolch.service.JsonServiceArgument;
import li.strolch.service.api.AbstractService;
import li.strolch.service.api.ServiceResult;
import li.strolch.utils.dbc.DBC;
import java.util.Set;
import java.util.stream.Collectors;
import static li.strolch.model.StrolchModelConstants.*;
public class CreateNotificationService extends AbstractService<JsonServiceArgument, ServiceResult> {
@Override
protected ServiceResult getResultInstance() {
return new ServiceResult();
}
@Override
public JsonServiceArgument getArgumentInstance() {
return new JsonServiceArgument();
}
@Override
protected ServiceResult internalDoService(JsonServiceArgument arg) throws Exception {
DBC.PRE.assertNotNull("JsonElement must be set", arg.jsonElement);
DBC.PRE.assertNotNull("JsonElement must be a JsonObject", arg.jsonElement.isJsonObject());
JsonObject jsonObject = arg.jsonElement.getAsJsonObject();
Resource notification = buildNotification(jsonObject, getSupportedLanguages(getAgent()));
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
tx.add(notification);
tx.commitOnClose();
}
return ServiceResult.success();
}
protected static Resource buildNotification(JsonObject jsonObject, Set<String> supportedLanguages) {
DBC.PRE.assertTrue("JsonObject must have languages!", jsonObject.has(PARAM_LANGUAGES));
JsonObject languagesJ = jsonObject.get(PARAM_LANGUAGES).getAsJsonObject();
DBC.PRE.assertNotEmpty("JsonObject must have at least one languages!", languagesJ.keySet());
FromFlatJsonVisitor visitor = new FromFlatJsonVisitor(jsonObject);
visitor.optionalParameter(PARAM_ROLES);
visitor.optionalParameter(PARAM_LOCATIONS);
visitor.optionalParameter(PARAM_FOR_ALL);
Resource notification = newNotification();
notification.accept(visitor);
for (String language : languagesJ.keySet()) {
if (!supportedLanguages.contains(language))
throw new IllegalArgumentException("The agent doesn't support language " + language);
JsonObject languageJ = languagesJ.get(language).getAsJsonObject();
String title = languageJ.get(PARAM_TITLE).getAsString();
String text = languageJ.get(PARAM_TEXT).getAsString();
ParameterBag languageBag = new ParameterBag(language, language, TYPE_TEXT);
languageBag.setString(PARAM_TITLE, title);
languageBag.setString(PARAM_TEXT, text);
notification.addParameterBag(languageBag);
}
return notification;
}
protected static Set<String> getSupportedLanguages(StrolchAgent agent) {
return agent
.getStrolchConfiguration()
.getRuntimeConfiguration()
.getSupportedLanguages()
.stream()
.map(SupportedLanguage::locale)
.collect(Collectors.toSet());
}
protected static Resource newNotification() {
ResourceBuilder notificationBuilder = new ResourceBuilder(TYPE_NOTIFICATION, TYPE_NOTIFICATION)
.bag(BAG_VISIBILITY, TYPE_VISIBILITY)
.date(PARAM_VISIBLE_FROM).end()
.date(PARAM_VISIBLE_TO).end()
.booleanB(PARAM_FOR_ALL).end()
.stringList(PARAM_ROLES).end()
.stringList(PARAM_LOCATIONS).end()
.endBag();
return notificationBuilder.build();
}
}

View File

@ -0,0 +1,35 @@
package li.strolch.service.notifications;
import li.strolch.model.Resource;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.service.StringArgument;
import li.strolch.service.api.AbstractService;
import li.strolch.service.api.ServiceResult;
import li.strolch.utils.dbc.DBC;
import static li.strolch.model.StrolchModelConstants.TYPE_NOTIFICATION;
public class RemoveNotificationService extends AbstractService<StringArgument, ServiceResult> {
@Override
protected ServiceResult getResultInstance() {
return new ServiceResult();
}
@Override
public StringArgument getArgumentInstance() {
return new StringArgument();
}
@Override
protected ServiceResult internalDoService(StringArgument arg) throws Exception {
DBC.PRE.assertNotEmpty("value must be set", arg.value);
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
Resource notification = tx.getResourceBy(TYPE_NOTIFICATION, arg.value, true);
tx.remove(notification);
tx.commitOnClose();
}
return ServiceResult.success();
}
}

View File

@ -0,0 +1,46 @@
package li.strolch.service.notifications;
import com.google.gson.JsonObject;
import li.strolch.model.Resource;
import li.strolch.model.Tags;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.service.JsonServiceArgument;
import li.strolch.service.api.AbstractService;
import li.strolch.service.api.ServiceResult;
import li.strolch.utils.dbc.DBC;
import static li.strolch.service.notifications.CreateNotificationService.buildNotification;
import static li.strolch.service.notifications.CreateNotificationService.getSupportedLanguages;
public class UpdateNotificationService extends AbstractService<JsonServiceArgument, ServiceResult> {
@Override
protected ServiceResult getResultInstance() {
return new ServiceResult();
}
@Override
public JsonServiceArgument getArgumentInstance() {
return new JsonServiceArgument();
}
@Override
protected ServiceResult internalDoService(JsonServiceArgument arg) throws Exception {
DBC.PRE.assertNotEmpty("objectId must be set", arg.objectId);
DBC.PRE.assertNotNull("JsonElement must be set", arg.jsonElement);
DBC.PRE.assertNotNull("JsonElement must be a JsonObject", arg.jsonElement.isJsonObject());
JsonObject jsonObject = arg.jsonElement.getAsJsonObject();
DBC.PRE.assertEquals("arg ID and jsonObject ID must be the same", arg.objectId,
jsonObject.get(Tags.Json.ID).getAsString());
Resource notification = buildNotification(jsonObject, getSupportedLanguages(getAgent()));
notification.setId(arg.objectId);
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
tx.update(notification);
tx.commitOnClose();
}
return ServiceResult.success();
}
}

View File

@ -48,8 +48,6 @@ public class StrolchRestfulConstants {
public static final String PARAM_TO = "to";
public static final String PARAM_FILTER = "filter";
public static final String PARAM_QUERY = "query";
public static final String PARAM_TITLE = "title";
public static final String PARAM_TEXT = "text";
public static final MediaType TEXT_CSV_TYPE = new MediaType("text", "csv");
public static final String TEXT_CSV = "text/csv";

View File

@ -15,23 +15,31 @@
*/
package li.strolch.rest.endpoint;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import li.strolch.agent.api.StrolchAgent;
import li.strolch.model.ParameterBag;
import li.strolch.model.Resource;
import li.strolch.model.Tags;
import li.strolch.model.json.StrolchRootElementToJsonVisitor;
import li.strolch.persistence.api.Operation;
import li.strolch.persistence.api.StrolchTransaction;
import li.strolch.policy.notifications.NotificationsPolicy;
import li.strolch.privilege.model.Certificate;
import li.strolch.rest.RestfulStrolchComponent;
import li.strolch.rest.helper.ResponseUtil;
import li.strolch.service.JsonServiceArgument;
import li.strolch.service.StringArgument;
import li.strolch.service.api.ServiceHandler;
import li.strolch.service.api.ServiceResult;
import li.strolch.service.notifications.CreateNotificationService;
import li.strolch.service.notifications.RemoveNotificationService;
import li.strolch.service.notifications.UpdateNotificationService;
import li.strolch.utils.helper.StringHelper;
import li.strolch.utils.iso8601.ISO8601;
import org.slf4j.Logger;
@ -44,10 +52,12 @@ import java.util.function.Function;
import static java.util.Optional.ofNullable;
import static li.strolch.model.StrolchModelConstants.*;
import static li.strolch.privilege.base.PrivilegeConstants.REALM;
import static li.strolch.rest.StrolchRestfulConstants.*;
import static li.strolch.rest.RestfulStrolchComponent.getInstance;
import static li.strolch.rest.StrolchRestfulConstants.DATA;
import static li.strolch.rest.StrolchRestfulConstants.STROLCH_CERTIFICATE;
import static li.strolch.rest.helper.ResponseUtil.*;
import static li.strolch.runtime.StrolchConstants.DEFAULT_REALM;
import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.PRIVILEGE_GET_NOTIFICATIONS;
import static li.strolch.runtime.StrolchConstants.StrolchPrivilegeConstants.*;
import static li.strolch.utils.helper.ExceptionHelper.getCallerMethod;
import static li.strolch.utils.helper.ExceptionHelper.getCallerMethodNoClass;
@ -66,30 +76,60 @@ public class NotificationResource {
return RestfulStrolchComponent.getInstance().openTx(certificate, realm, getCallerMethod());
}
private static Certificate validateCertificate(HttpServletRequest request) {
private static Certificate validateCertificate(HttpServletRequest request, String privilege) {
Certificate cert = (Certificate) request.getAttribute(STROLCH_CERTIFICATE);
RestfulStrolchComponent rest = RestfulStrolchComponent.getInstance();
rest.validate(cert).validateAction(PRIVILEGE_GET_NOTIFICATIONS, getCallerMethodNoClass(2));
rest.validate(cert).validateAction(privilege, getCallerMethodNoClass(2));
return cert;
}
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getNotifications(@Context HttpServletRequest request) {
Certificate cert = validateCertificate(request);
public Response getUserNotifications(@Context HttpServletRequest request) {
Certificate cert = validateCertificate(request, PRIVILEGE_GET_NOTIFICATIONS);
try (StrolchTransaction tx = openTx(cert)) {
List<Resource> notifications = NotificationsPolicy.getDefaultPolicy(tx).findUserNotifications();
Function<Resource, JsonObject> visitor = notificationToJson(tx.getAgent(), cert);
return ResponseUtil.toResponse(DATA, notifications.stream().map(visitor).filter(Objects::nonNull).toList());
return toResponse(DATA, notifications.stream().map(visitor).filter(Objects::nonNull).toList());
} catch (Exception e) {
logger.error(e.getMessage(), e);
return ResponseUtil.toResponse(e);
return toResponse(e);
}
}
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public Response getNotification(@Context HttpServletRequest request, @PathParam("id") String id) {
Certificate cert = validateCertificate(request, PRIVILEGE_GET_NOTIFICATION);
try (StrolchTransaction tx = openTx(cert)) {
Resource notification = tx.getResourceBy(TYPE_NOTIFICATION, id, true);
tx.assertHasPrivilege(Operation.GET, notification);
return toResponse(DATA, notificationToJson(tx.getAgent(), cert).apply(notification));
} catch (Exception e) {
logger.error(e.getMessage(), e);
return toResponse(e);
}
}
@GET
@Path("all")
@Produces(MediaType.APPLICATION_JSON)
public Response getAllNotifications(@Context HttpServletRequest request) {
Certificate cert = validateCertificate(request, PRIVILEGE_GET_NOTIFICATIONS_ALL);
try (StrolchTransaction tx = openTx(cert)) {
StrolchRootElementToJsonVisitor visitor = new StrolchRootElementToJsonVisitor().flatBags();
return toResponse(DATA, tx.streamResources(TYPE_NOTIFICATION).map(a -> a.accept(visitor)).toList());
} catch (Exception e) {
logger.error(e.getMessage(), e);
return toResponse(e);
}
}
private static Function<Resource, JsonObject> notificationToJson(StrolchAgent agent, Certificate cert) {
return notification -> {
JsonObject notificationJ = new JsonObject();
notificationJ.addProperty(Tags.Json.ID, notification.getId());
String lang = cert.getLocale().getLanguage();
Optional<ParameterBag> textBagO = ofNullable(notification.getParameterBag(lang))
@ -109,4 +149,64 @@ public class NotificationResource {
return notificationJ;
};
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response create(@Context HttpServletRequest request, String data) {
Certificate cert = (Certificate) request.getAttribute(STROLCH_CERTIFICATE);
// get JSON
JsonObject jsonObject = JsonParser.parseString(data).getAsJsonObject();
// create service and argument
CreateNotificationService svc = new CreateNotificationService();
ServiceHandler svcHandler = getInstance().getServiceHandler();
JsonServiceArgument arg = svc.getArgumentInstance();
arg.jsonElement = jsonObject;
// call service
ServiceResult result = svcHandler.doService(cert, svc, arg);
return toResponse(result);
}
@PUT
@Path("{id}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response update(@Context HttpServletRequest request, @PathParam("id") String id, String data) {
Certificate cert = (Certificate) request.getAttribute(STROLCH_CERTIFICATE);
// get JSON
JsonObject jsonObject = JsonParser.parseString(data).getAsJsonObject();
// create service and argument
UpdateNotificationService svc = new UpdateNotificationService();
ServiceHandler svcHandler = getInstance().getServiceHandler();
JsonServiceArgument arg = svc.getArgumentInstance();
arg.objectId = id;
arg.jsonElement = jsonObject;
// call service
ServiceResult result = svcHandler.doService(cert, svc, arg);
return toResponse(result);
}
@DELETE
@Path("{id}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response remove(@Context HttpServletRequest request, @PathParam("id") String id) {
Certificate cert = (Certificate) request.getAttribute(STROLCH_CERTIFICATE);
// create service and argument
RemoveNotificationService svc = new RemoveNotificationService();
ServiceHandler svcHandler = getInstance().getServiceHandler();
StringArgument arg = svc.getArgumentInstance();
arg.value = id;
// call service
ServiceResult result = svcHandler.doService(cert, svc, arg);
return toResponse(result);
}
}