Compare commits
5 Commits
5526f20220
...
f850367d2b
Author | SHA1 | Date |
---|---|---|
Robert von Burg | f850367d2b | |
Robert von Burg | a4119ef1da | |
Robert von Burg | abe089f95c | |
Robert von Burg | 15b2788b9a | |
Robert von Burg | f02b541848 |
|
@ -20,12 +20,15 @@ public class DefaultNotificationsPolicy extends NotificationsPolicy {
|
|||
return tx().streamResources(StrolchModelConstants.TYPE_NOTIFICATION).filter(this::isForUser).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canView(Resource notification) {
|
||||
return isForAll(notification) || isForRole(notification) || isForGroup(notification);
|
||||
}
|
||||
|
||||
protected boolean isForUser(Resource notification) {
|
||||
if (!isActive(notification))
|
||||
return false;
|
||||
if (isForAll(notification))
|
||||
return true;
|
||||
return isForRole(notification) || isForGroup(notification);
|
||||
return isForAll(notification) || isForRole(notification) || isForGroup(notification);
|
||||
}
|
||||
|
||||
protected boolean isActive(Resource notification) {
|
||||
|
|
|
@ -18,6 +18,7 @@ public abstract class NotificationsPolicy extends StrolchPolicy {
|
|||
}
|
||||
|
||||
public abstract List<Resource> findUserNotifications();
|
||||
public abstract boolean canView(Resource notification);
|
||||
|
||||
public static NotificationsPolicy getDefaultPolicy(StrolchTransaction tx) {
|
||||
PolicyDef defaultDef = getKeyPolicy(NotificationsPolicy.class, POLICY_DEFAULT);
|
||||
|
|
|
@ -86,6 +86,7 @@ public class StrolchModelConstants {
|
|||
public static final String TYPE_NOTIFICATION = "Notification";
|
||||
public static final String TYPE_VISIBILITY = "Visibility";
|
||||
public static final String TYPE_TEXT = "Text";
|
||||
public static final String TYPE_LOCATION = "Location";
|
||||
|
||||
public static final String RES_CONFIGURATION = "configuration";
|
||||
|
||||
|
@ -110,6 +111,7 @@ public class StrolchModelConstants {
|
|||
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_LOCATION_NAMES = "locationNames";
|
||||
public static final String PARAM_LANGUAGES = "languages";
|
||||
public static final String PARAM_GROUPS = "groups";
|
||||
|
||||
|
|
|
@ -15,11 +15,6 @@
|
|||
*/
|
||||
package li.strolch.privilege.policy;
|
||||
|
||||
import static li.strolch.privilege.policy.PrivilegePolicyHelper.checkByAllowDenyValues;
|
||||
import static li.strolch.privilege.policy.PrivilegePolicyHelper.preValidate;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
|
||||
import li.strolch.privilege.base.AccessDeniedException;
|
||||
import li.strolch.privilege.base.PrivilegeException;
|
||||
import li.strolch.privilege.handler.PrivilegeHandler;
|
||||
|
@ -31,6 +26,11 @@ import li.strolch.privilege.model.internal.Role;
|
|||
import li.strolch.utils.collections.Tuple;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
|
||||
import static li.strolch.privilege.policy.PrivilegePolicyHelper.checkByAllowDenyValues;
|
||||
import static li.strolch.privilege.policy.PrivilegePolicyHelper.preValidate;
|
||||
|
||||
/**
|
||||
* This {@link PrivilegePolicy} expects a {@link Tuple} as {@link Restrictable#getPrivilegeValue()}. The Tuple must
|
||||
* contain {@link Role} as first and second value. Then the policy decides depending on the user specific privileges
|
||||
|
@ -67,8 +67,8 @@ public class RoleAccessPrivilege implements PrivilegePolicy {
|
|||
|
||||
// RoleAccessPrivilege policy expects the privilege value to be a role
|
||||
if (!(object instanceof Tuple tuple)) {
|
||||
String msg = Restrictable.class.getName() + PrivilegeMessages
|
||||
.getString("Privilege.illegalArgument.nontuple");
|
||||
String msg = Restrictable.class.getName() + PrivilegeMessages.getString(
|
||||
"Privilege.illegalArgument.nontuple");
|
||||
msg = MessageFormat.format(msg, restrictable.getClass().getSimpleName());
|
||||
throw new PrivilegeException(msg);
|
||||
}
|
||||
|
@ -78,32 +78,30 @@ public class RoleAccessPrivilege implements PrivilegePolicy {
|
|||
return true;
|
||||
|
||||
// get role name as privilege value
|
||||
Role oldRole = tuple.getFirst();
|
||||
Role newRole = tuple.getSecond();
|
||||
String oldRole = tuple.getFirst() instanceof Role r ? r.getName() : tuple.getFirst();
|
||||
String newRole = tuple.getSecond() instanceof Role r ? r.getName() : tuple.getSecond();
|
||||
|
||||
switch (privilegeName) {
|
||||
case PrivilegeHandler.PRIVILEGE_GET_ROLE, PrivilegeHandler.PRIVILEGE_ADD_ROLE, PrivilegeHandler.PRIVILEGE_REMOVE_ROLE -> {
|
||||
DBC.INTERIM.assertNull("For " + privilegeName + " first must be null!", oldRole);
|
||||
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newRole);
|
||||
case PrivilegeHandler.PRIVILEGE_GET_ROLE, PrivilegeHandler.PRIVILEGE_ADD_ROLE, PrivilegeHandler.PRIVILEGE_REMOVE_ROLE -> {
|
||||
DBC.INTERIM.assertNull("For " + privilegeName + " first must be null!", oldRole);
|
||||
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newRole);
|
||||
|
||||
String privilegeValue = newRole.getName();
|
||||
return checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue, assertHasPrivilege);
|
||||
}
|
||||
case PrivilegeHandler.PRIVILEGE_MODIFY_ROLE -> {
|
||||
DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", oldRole);
|
||||
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newRole);
|
||||
return checkByAllowDenyValues(ctx, privilege, restrictable, newRole, assertHasPrivilege);
|
||||
}
|
||||
case PrivilegeHandler.PRIVILEGE_MODIFY_ROLE -> {
|
||||
DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", oldRole);
|
||||
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newRole);
|
||||
|
||||
String privilegeValue = newRole.getName();
|
||||
DBC.INTERIM.assertEquals("oldRole and newRole names must be the same", oldRole.getName(), privilegeValue);
|
||||
DBC.INTERIM.assertEquals("oldRole and newRole names must be the same", oldRole, newRole);
|
||||
|
||||
return checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue, assertHasPrivilege);
|
||||
}
|
||||
default -> {
|
||||
String msg = Restrictable.class.getName() + PrivilegeMessages.getString(
|
||||
"Privilege.roleAccessPrivilege.unknownPrivilege");
|
||||
msg = MessageFormat.format(msg, privilegeName);
|
||||
throw new PrivilegeException(msg);
|
||||
}
|
||||
return checkByAllowDenyValues(ctx, privilege, restrictable, newRole, assertHasPrivilege);
|
||||
}
|
||||
default -> {
|
||||
String msg = Restrictable.class.getName() + PrivilegeMessages.getString(
|
||||
"Privilege.roleAccessPrivilege.unknownPrivilege");
|
||||
msg = MessageFormat.format(msg, privilegeName);
|
||||
throw new PrivilegeException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,18 +5,23 @@ 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.Operation;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.privilege.model.SimpleRestrictable;
|
||||
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.collections.Tuple;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static li.strolch.model.StrolchModelConstants.*;
|
||||
import static li.strolch.privilege.handler.DefaultPrivilegeHandler.PRIVILEGE_GET_ROLE;
|
||||
import static li.strolch.utils.iso8601.ISO8601.parseToZdt;
|
||||
|
||||
public class CreateNotificationService extends AbstractService<JsonServiceArgument, ServiceResult> {
|
||||
@Override
|
||||
|
@ -35,9 +40,9 @@ public class CreateNotificationService extends AbstractService<JsonServiceArgume
|
|||
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)) {
|
||||
Resource notification = buildNotification(tx, jsonObject, getSupportedLanguages(getAgent()));
|
||||
tx.add(notification);
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
@ -45,22 +50,41 @@ public class CreateNotificationService extends AbstractService<JsonServiceArgume
|
|||
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);
|
||||
protected static Resource buildNotification(StrolchTransaction tx, JsonObject jsonObject,
|
||||
Set<String> supportedLanguages) {
|
||||
Resource notification = newNotification();
|
||||
notification.accept(visitor);
|
||||
PrivilegeContext ctx = tx.getPrivilegeContext();
|
||||
|
||||
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();
|
||||
JsonObject visibilityJ = jsonObject.get(BAG_VISIBILITY).getAsJsonObject();
|
||||
ParameterBag visibility = notification.getParameterBag(BAG_VISIBILITY);
|
||||
|
||||
visibility.setBoolean(PARAM_FOR_ALL,
|
||||
visibilityJ.has(PARAM_FOR_ALL) && visibilityJ.get(PARAM_FOR_ALL).getAsBoolean());
|
||||
if (visibilityJ.has(PARAM_VISIBLE_FROM))
|
||||
visibility.setDate(PARAM_VISIBLE_FROM, parseToZdt(visibilityJ.get(PARAM_VISIBLE_FROM).getAsString()));
|
||||
if (visibilityJ.has(PARAM_VISIBLE_TO))
|
||||
visibility.setDate(PARAM_VISIBLE_TO, parseToZdt(visibilityJ.get(PARAM_VISIBLE_TO).getAsString()));
|
||||
|
||||
if (visibilityJ.has(PARAM_ROLES)) {
|
||||
String rolesJ = visibilityJ.get(PARAM_ROLES).getAsString();
|
||||
visibility.getStringListP(PARAM_ROLES).setValueFromString(rolesJ);
|
||||
for (String role : visibility.getStringList(PARAM_ROLES)) {
|
||||
ctx.validateAction(new SimpleRestrictable(PRIVILEGE_GET_ROLE, new Tuple(null, role)));
|
||||
}
|
||||
}
|
||||
|
||||
if (visibilityJ.has(PARAM_LOCATIONS)) {
|
||||
String locationsJ = visibilityJ.get(PARAM_LOCATIONS).getAsString();
|
||||
visibility.getStringListP(PARAM_LOCATIONS).setValueFromString(locationsJ);
|
||||
for (String locationId : visibility.getStringList(PARAM_LOCATIONS)) {
|
||||
tx.assertHasPrivilege(Operation.GET, tx.getResourceBy(TYPE_LOCATION, locationId, true));
|
||||
}
|
||||
}
|
||||
|
||||
for (String language : supportedLanguages) {
|
||||
if (!jsonObject.has(language))
|
||||
continue;
|
||||
JsonObject languageJ = jsonObject.get(language).getAsJsonObject();
|
||||
String title = languageJ.get(PARAM_TITLE).getAsString();
|
||||
String text = languageJ.get(PARAM_TEXT).getAsString();
|
||||
|
||||
|
|
|
@ -33,10 +33,11 @@ public class UpdateNotificationService extends AbstractService<JsonServiceArgume
|
|||
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)) {
|
||||
|
||||
Resource notification = buildNotification(tx, jsonObject, getSupportedLanguages(getAgent()));
|
||||
notification.setId(arg.objectId);
|
||||
|
||||
tx.update(notification);
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ public class SynchronizedMapOfListsTest {
|
|||
Future<Boolean> task5 = this.executorService.submit(iterateTask);
|
||||
|
||||
run.set(true);
|
||||
Thread.sleep(20L);
|
||||
Thread.sleep(100L);
|
||||
run.set(false);
|
||||
|
||||
Boolean result0 = task0.get();
|
||||
|
|
|
@ -13,8 +13,10 @@ import li.strolch.runtime.configuration.SupportedLanguage;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Comparator.*;
|
||||
import static li.strolch.utils.helper.ExceptionHelper.getRootCauseMessage;
|
||||
|
||||
@Path("strolch/languages")
|
||||
|
@ -27,14 +29,20 @@ public class LanguagesResource {
|
|||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getSupportedLanguages() {
|
||||
try {
|
||||
Set<SupportedLanguage> supportedLanguages = RestfulStrolchComponent.getInstance().getAgent()
|
||||
.getStrolchConfiguration().getRuntimeConfiguration().getSupportedLanguages();
|
||||
JsonArray result = supportedLanguages.stream().map(language -> {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty(Tags.Json.LOCALE, language.locale());
|
||||
jsonObject.addProperty(Tags.Json.NAME, language.name());
|
||||
return jsonObject;
|
||||
}).collect(JsonArray::new, JsonArray::add, JsonArray::addAll);
|
||||
JsonArray result = RestfulStrolchComponent
|
||||
.getInstance()
|
||||
.getAgent()
|
||||
.getRuntimeConfiguration()
|
||||
.getSupportedLanguages()
|
||||
.stream()
|
||||
.sorted(comparing(SupportedLanguage::name))
|
||||
.map(language -> {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty(Tags.Json.LOCALE, language.locale());
|
||||
jsonObject.addProperty(Tags.Json.NAME, language.name());
|
||||
return jsonObject;
|
||||
})
|
||||
.collect(JsonArray::new, JsonArray::add, JsonArray::addAll);
|
||||
|
||||
return Response.ok().entity(result.toString()).build();
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
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;
|
||||
|
@ -49,6 +50,7 @@ import java.util.List;
|
|||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static li.strolch.model.StrolchModelConstants.*;
|
||||
|
@ -120,9 +122,9 @@ public class NotificationResource {
|
|||
try (StrolchTransaction tx = openTx(cert)) {
|
||||
StrolchRootElementToJsonVisitor visitor = new StrolchRootElementToJsonVisitor()
|
||||
.withoutPolicies()
|
||||
.withoutVersion()
|
||||
.withoutStateVariables()
|
||||
.flatBagsByType(TYPE_TEXT, TYPE_VISIBILITY);
|
||||
.flatBagsByType(TYPE_TEXT, TYPE_VISIBILITY)
|
||||
.resourceHook((notification, notificationJ) -> addLocationNames(notification, notificationJ, tx));
|
||||
return toResponse(DATA, tx.streamResources(TYPE_NOTIFICATION).map(a -> a.accept(visitor)).toList());
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
|
@ -130,6 +132,20 @@ public class NotificationResource {
|
|||
}
|
||||
}
|
||||
|
||||
private static void addLocationNames(Resource notification, JsonObject notificationJ, StrolchTransaction tx) {
|
||||
if (!notification.hasParameter(BAG_VISIBILITY, PARAM_LOCATIONS))
|
||||
return;
|
||||
JsonArray locationNamesJ = notification
|
||||
.getStringList(BAG_VISIBILITY, PARAM_LOCATIONS)
|
||||
.stream()
|
||||
.map(locationId -> {
|
||||
Resource location = tx.getResourceBy(TYPE_LOCATION, locationId);
|
||||
return location == null ? locationId : location.getName();
|
||||
})
|
||||
.collect(JsonArray::new, JsonArray::add, JsonArray::addAll);
|
||||
notificationJ.get(BAG_VISIBILITY).getAsJsonObject().add(PARAM_LOCATION_NAMES, locationNamesJ);
|
||||
}
|
||||
|
||||
private static Function<Resource, JsonObject> notificationToJson(StrolchAgent agent, Certificate cert) {
|
||||
return notification -> {
|
||||
JsonObject notificationJ = new JsonObject();
|
||||
|
|
Loading…
Reference in New Issue