diff --git a/ccm-core/src/main/java/org/libreccm/api/pagemodels/Components.java b/ccm-core/src/main/java/org/libreccm/api/pagemodels/Components.java new file mode 100644 index 000000000..629b3d2a6 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/api/pagemodels/Components.java @@ -0,0 +1,531 @@ +/* + * Copyright (C) 2018 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.api.pagemodels; + +import org.libreccm.core.CoreConstants; +import org.libreccm.pagemodel.ComponentModel; +import org.libreccm.pagemodel.ComponentModelJsonConverter; +import org.libreccm.pagemodel.ComponentModelRepository; +import org.libreccm.pagemodel.ContainerModel; +import org.libreccm.pagemodel.ContainerModelManager; +import org.libreccm.pagemodel.ConvertsComponentModel; +import org.libreccm.pagemodel.PageModel; +import org.libreccm.security.AuthorizationRequired; +import org.libreccm.security.RequiresPrivilege; +import org.libreccm.web.CcmApplication; + +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.util.Iterator; +import java.util.Objects; +import java.util.Optional; + +import javax.enterprise.context.RequestScoped; +import javax.enterprise.inject.Any; +import javax.enterprise.inject.Instance; +import javax.enterprise.util.AnnotationLiteral; +import javax.inject.Inject; +import javax.json.Json; +import javax.json.JsonArray; +import javax.json.JsonArrayBuilder; +import javax.json.JsonObject; +import javax.transaction.Transactional; +import javax.ws.rs.BadRequestException; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +/** + * Provides RESTful endpoints for retrieving, creating, updating and deleting + * {@link ComponentModel}s of a {@link ContainerModel}. + * + * @author Jens Pelzetter + */ +@RequestScoped +@Path("/{appName}/{pageModelName}/containers/{containerKey}/components") +public class Components { + + @Inject + private ComponentModelRepository componentRepo; + + @Inject + private ContainerModelManager containerManager; + + @Inject + private PageModelsController controller; + + @Inject + @Any + private Instance jsonConverters; + + /** + * Retrieve all {@link ComponentModel} of a {@link ContainerModel}. + * + * @param Name The primary URL of the {@link CcmApplication}. + * @param pageModelName The name of the {@link PageModel}. + * @param containerKey The key of the {@link ContainerModel}. + * + * @return A JSON array containing the data of all {@link ComponentModel} of + * the {@link ContainerModel}. + */ + @GET + @Path("/") + @Produces(MediaType.APPLICATION_JSON) + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + public JsonArray getComponents( + @PathParam("appName") final String Name, + @PathParam("pageModelName") final String pageModelName, + @PathParam("containerKey") final String containerKey + ) { + Objects.requireNonNull(Name); + Objects.requireNonNull(pageModelName); + Objects.requireNonNull(containerKey); + + final CcmApplication app = controller.findCcmApplication( + String.format("/%s/", Name) + ); + final PageModel pageModel = controller.findPageModel( + app, pageModelName + ); + final ContainerModel container = controller.findContainer( + app, pageModel, containerKey + ); + + final JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); + container + .getComponents() + .stream() + .map(component -> mapComponentModelToJson(component)) + .forEach(arrayBuilder::add); + + return arrayBuilder.build(); + } + + /** + * Retrieves a specific {@link ComponentModel}. + * + * @param appName The primary URL of the {@link CcmApplication}. + * @param pageModelName The name of the {@link PageModel}. + * @param containerKey The key of the {@link ContainerModel}. + * @param componentKey The key of the {@link ComponentModel}. + * + * @return A JSON object containing the data of the {@link ComponentModel}. + */ + @GET + @Path("/{componentKey}") + @Produces(MediaType.APPLICATION_JSON) + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + public JsonObject getComponent( + @PathParam("appName") final String appName, + @PathParam("pageModelName") final String pageModelName, + @PathParam("containerKey") final String containerKey, + @PathParam("componentKey") final String componentKey + ) { + Objects.requireNonNull(appName); + Objects.requireNonNull(pageModelName); + Objects.requireNonNull(containerKey); + Objects.requireNonNull(componentKey); + + final CcmApplication app = controller.findCcmApplication( + String.format("/%s/", appName) + ); + final PageModel pageModel = controller.findPageModel( + app, pageModelName + ); + final ContainerModel container = controller.findContainer( + app, pageModel, containerKey + ); + final ComponentModel component = controller.findComponentModel( + app, pageModel, container, componentKey + ); + + return mapComponentModelToJson(component); + } + + /** + * Creates or updates a {@link ComponentModel}.If a {@link ComponentModel} + * with provided {@code componentKey} already exists in the container + * identified by {@code appName}, {@code pageModelName} and + * {@code containerKey} the {@link ComponentModel} is updated with the data + * from {@code componentModelData}. + * + * Otherwise a new {@link ComponentModel} is created using the data from + * {@code componentModelData}. + * + * @param appName The primary URL of the {@link CcmApplication}. + * @param pageModelName The name of the {@link PageModel}. + * @param containerKey The key of the {@link ContainerModel}. + * @param componentKey The key of the {@link ComponentModel} to create + * or update. + * @param componentModelData The data for creating or updating the + * {@link ComponentModel}. + * + * @return A HTTP response with the status code {@code 200} if the component + * model was updated or {@code 201} if the component model was + * created. If the component model was created the response also + * contains the URI of the new component model. + * + * + */ + @PUT + @Path("/{componentKey}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + public Response putComponent( + @PathParam("appName") final String appName, + @PathParam("pageModelName") final String pageModelName, + @PathParam("containerKey") final String containerKey, + @PathParam("componentKey") final String componentKey, + final JsonObject componentModelData + ) { + Objects.requireNonNull(appName); + Objects.requireNonNull(pageModelName); + Objects.requireNonNull(containerKey); + Objects.requireNonNull(componentKey); + Objects.requireNonNull(componentModelData); + + final CcmApplication app = controller.findCcmApplication( + String.format("/%s/", appName) + ); + final PageModel pageModel = controller.findPageModel( + app, pageModelName + ); + final ContainerModel container = controller.findContainer( + app, pageModel, containerKey + ); + + final Optional result = container + .getComponents() + .stream() + .filter(c -> c.getKey().equals(componentKey)) + .findAny(); + + final ComponentModel componentModel; + final boolean created; + if (result.isPresent()) { + componentModel = result.get(); + created = false; + } else { + componentModel = createComponentModel(componentModelData); + componentModel.setKey(componentKey); + containerManager.addComponentModel(container, componentModel); + created = true; + } + + setComponentPropertiesFromJson(componentModelData, componentModel); + componentRepo.save(componentModel); + + if (created) { + return Response.created( + URI.create( + String.format( + "/page-models/%s/%s/%s/%s", + appName, + pageModelName, + containerKey, + componentKey + ) + ) + ).build(); + } else { + return Response.ok( + String.format( + "Component %s of container %s of page model %s of " + + "application %s updated successfully.", + componentKey, + containerKey, + pageModelName, + appName + ) + ).build(); + } + } + + /** + * Deletes a {@link ComponentModel}. + * + * @param appName The primary URL of the {@link CcmApplication}. + * @param pageModelName The name of the {@link PageModel}. + * @param containerKey The key of the {@link ContainerModel}. + * @param componentKey The key of the {@link ComponentModel} to delete. + * + * @return HTTP response for successful delete. + * + */ + @DELETE + @Path("/{componentKey}") + @Transactional(Transactional.TxType.REQUIRED) + @AuthorizationRequired + @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) + public Response deleteComponent( + @PathParam("appName") final String appName, + @PathParam("pageModelName") final String pageModelName, + @PathParam("containerKey") final String containerKey, + @PathParam("componentKey") final String componentKey + ) { + Objects.requireNonNull(appName); + Objects.requireNonNull(pageModelName); + Objects.requireNonNull(containerKey); + Objects.requireNonNull(componentKey); + + final CcmApplication app = controller.findCcmApplication( + String.format("/%s/", appName) + ); + final PageModel pageModel = controller.findPageModel( + app, pageModelName + ); + final ContainerModel container = controller.findContainer( + app, pageModel, containerKey + ); + final ComponentModel component = controller.findComponentModel( + app, pageModel, container, componentKey + ); + + containerManager.removeComponentModel(container, component); + + return Response.ok( + String.format( + "Component %s successfully deleted from container %s " + + "of page model %s of application %s.", + componentKey, + containerKey, + pageModelName, + appName + ) + ).build(); + } + + /** + * Helper method for mapping a {@link ComponentModel} to JSON. + * + * @param componentModel The {@link ComponentModel} to map. + * + * @return The JSON representation of the + * {@link ComponentModel} {@code componentModel}. + */ + private JsonObject mapComponentModelToJson( + final ComponentModel componentModel) { + + final Class clazz = Objects + .requireNonNull(componentModel) + .getClass(); + + final ComponentModelJsonConverter jsonConverter + = findJsonConverter(clazz) + .orElseThrow( + () -> new WebApplicationException( + String.format( + "No JSON converter available for component " + + "model \"%s\".", + clazz.getName() + ), + Response.Status.INTERNAL_SERVER_ERROR + ) + ); + + return jsonConverter.toJson(componentModel); + } + + /** + * Creates a new {@link ComponentModel} instance. + * + * Uses reflection and the value of {@code type} property from the JSON + * {@code data} to determine the correct class. + * + * @param data The data from which the new {@link ComponentModel} is + * created. + * + * @return The new {@link ComponentModel}. + */ + private ComponentModel createComponentModel(final JsonObject data) { + + Objects.requireNonNull(data); + + if (!data.containsKey("type")) { + throw new WebApplicationException( + "The JSON data for creating the " + + "component has no value for the type of the component to " + + "create.", + Response.Status.BAD_REQUEST + ); + } + + final String type = data.getString("type"); + final Class clazz = findComponentModelClass( + type + ); + + final ComponentModel componentModel; + try { + componentModel = clazz.getConstructor().newInstance(); + } catch (IllegalAccessException + | InstantiationException + | InvocationTargetException + | NoSuchMethodException ex) { + throw new WebApplicationException(ex); + } + + return componentModel; + } + + /** + * Helper method for finding the correct subclass of {@link ComponentModel} + * using the fully qualified name the class. + * + * @param type The fully qualified name of the subclass of + * {@link ComponentModel}. + * + * @return The subclass of {@link ComponentModel}. + * + * @throws BadRequestException If there is no subclass of + * {@link ComponentModel} with the fully + * qualified name provided by the {@code type} + * parameter. + */ + @SuppressWarnings("unchecked") + private Class findComponentModelClass( + final String type + ) { + Objects.requireNonNull(type); + + try { + final Class clazz = Class.forName(type); + + if (ComponentModel.class.isAssignableFrom(clazz)) { + return (Class) clazz; + } else { + throw new WebApplicationException( + String.format( + "The type \"%s\" is not a subclass of \"%s\".", + type, + ComponentModel.class.getName() + ), + Response.Status.BAD_REQUEST + ); + } + } catch (ClassNotFoundException ex) { + throw new WebApplicationException( + String.format( + "The component model type \"%s\" " + + "does not exist.", + type + ), + Response.Status.BAD_REQUEST + ); + } + } + + /** + * Helper method for setting the properties of a {@link ComponentModel} from + * the JSON data. + * + * @param data The JSON data. + * @param componentModel The {@link ComponentModel}. + */ + private void setComponentPropertiesFromJson( + final JsonObject data, + final ComponentModel componentModel + ) { + final Class clazz = Objects + .requireNonNull(componentModel) + .getClass(); + + final ComponentModelJsonConverter jsonConverter + = findJsonConverter(clazz) + .orElseThrow( + () -> new WebApplicationException( + String.format( + "No JSON converter available for component " + + "model \"%s\".", + clazz.getName() + ), + Response.Status.INTERNAL_SERVER_ERROR + ) + ); + + jsonConverter.fromJson(data, componentModel); + } + + private Optional + findJsonConverter( + final Class componentModelClass + ) { + + final ConvertsComponentModelLiteral literal + = new ConvertsComponentModelLiteral( + componentModelClass + ); + final Instance instance = jsonConverters + .select(literal); + if (instance.isUnsatisfied()) { + return Optional.empty(); + } else if (instance.isAmbiguous()) { + throw new WebApplicationException( + String.format( + "Multiple JSONConverter for \"%s\".", + componentModelClass.getName() + ), + Response.Status.INTERNAL_SERVER_ERROR + ); + } else { + final Iterator iterator = instance + .iterator(); + @SuppressWarnings("unchecked") + final ComponentModelJsonConverter converter = iterator.next(); + + return Optional.of(converter); + } + } + + private static class ConvertsComponentModelLiteral + extends AnnotationLiteral + implements ConvertsComponentModel { + + private static final long serialVersionUID = 1L; + + private final Class componentModel; + + public ConvertsComponentModelLiteral( + final Class componentModel + ) { + this.componentModel = componentModel; + } + + @Override + public Class componentModel() { + return componentModel; + } + + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/Containers.java b/ccm-core/src/main/java/org/libreccm/api/pagemodels/Containers.java similarity index 64% rename from ccm-core/src/main/java/org/libreccm/pagemodel/rs/Containers.java rename to ccm-core/src/main/java/org/libreccm/api/pagemodels/Containers.java index 437f44b04..169e2d249 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/Containers.java +++ b/ccm-core/src/main/java/org/libreccm/api/pagemodels/Containers.java @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ -package org.libreccm.pagemodel.rs; +package org.libreccm.api.pagemodels; import org.libreccm.core.CoreConstants; import org.libreccm.pagemodel.ContainerModel; @@ -27,6 +27,7 @@ import org.libreccm.security.AuthorizationRequired; import org.libreccm.security.RequiresPrivilege; import org.libreccm.web.CcmApplication; +import java.net.URI; import java.util.Optional; import javax.enterprise.context.RequestScoped; @@ -43,6 +44,8 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; /** * Provides RESTful endpoints for managing the {@link ContainerModel}s of a @@ -51,7 +54,7 @@ import javax.ws.rs.Produces; * @author Jens Pelzetter */ @RequestScoped -@Path("/") +@Path("/{appName}/{pageModelName}/containers") public class Containers { @Inject @@ -66,7 +69,7 @@ public class Containers { /** * Retrieves all {@link ContainerModel}s of a {@link PageModel}. * - * @param appPath The primary URL of the {@link CcmApplication} to + * @param appName The primary URL of the {@link CcmApplication} to * which the {@link PageModel} belongs. * @param pageModelName The name of the {@link PageModel} of which the * containers are retrieved. @@ -76,20 +79,22 @@ public class Containers { * the {@link CcmApplication} with the primary URL {@code appPath}. */ @GET - @Path(PageModelsApp.CONTAINERS_PATH) - @Produces("application/json; charset=utf-8") + @Path("/") + @Produces(MediaType.APPLICATION_JSON) @Transactional(Transactional.TxType.REQUIRED) @AuthorizationRequired @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) public JsonArray getContainers( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName) { - + @PathParam("appName") final String appName, + @PathParam("pageModelName") final String pageModelName + ) { final CcmApplication app = controller.findCcmApplication( - String.format("/%s/", appPath)); + String.format("/%s/", appName) + ); - final PageModel pageModel = controller.findPageModel(app, - pageModelName); + final PageModel pageModel = controller.findPageModel( + app, pageModelName + ); final JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); pageModel @@ -104,7 +109,7 @@ public class Containers { /** * Retrieve a specific {@link ContainerModel}. * - * @param appPath The primary URL of the {@link CcmApplication} to + * @param appName The primary URL of the {@link CcmApplication} to * which the {@link PageModel} belongs. * @param pageModelName The name of the {@link PageModel} to which the * {@link ContainerModel} belongs. @@ -114,25 +119,27 @@ public class Containers { * @return A JSON object containing the data of the {@link PageModel}. */ @GET - @Path(PageModelsApp.CONTAINER_PATH) - @Produces("application/json; charset=utf-8") + @Path("/{containerKey}") + @Produces(MediaType.APPLICATION_JSON) @Transactional(Transactional.TxType.REQUIRED) @AuthorizationRequired @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) public JsonObject getContainer( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey) { - + @PathParam("appName") final String appName, + @PathParam("pageModelName") final String pageModelName, + @PathParam("containerKey") final String containerKey + ) { final CcmApplication app = controller.findCcmApplication( - String.format("/%s/", appPath)); + String.format("/%s/", appName) + ); - final PageModel pageModel = controller.findPageModel(app, - pageModelName); + final PageModel pageModel = controller.findPageModel( + app, pageModelName + ); - final ContainerModel container = controller.findContainer(app, - pageModel, - containerKey); + final ContainerModel container = controller.findContainer( + app, pageModel, containerKey + ); return mapContainerModelToJson(container); } @@ -147,32 +154,36 @@ public class Containers { * If there is no such {@link ContainerModel} a new {@link ContainerModel} * is created using the data provided by {@code containerModelData}. * - * @param appPath The path of the {@link CcmApplication}. + * @param appName The path of the {@link CcmApplication}. * @param pageModelName The name of the {@link PageModel}. * @param containerKey The key identifying the {@link ContainerModel}. * @param containerModelData The data for updating or creating the * {@link ContainerModel}. * - * @return The new or updated {@link ContainerModel}. + * @return A HTTP response with the status code {@code 200} if the container + * model was updated or {@code 201} if the container model was + * created. If the container model was created the response also + * contains the URI of the new container model. */ @PUT - @Path(PageModelsApp.CONTAINER_PATH) - @Consumes("application/json; charset=utf-8") - @Produces("application/json; charset=utf-8") + @Path("/{containerKey}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) @Transactional(Transactional.TxType.REQUIRED) @AuthorizationRequired @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject putContainer( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - final JsonObject containerModelData) { - + public Response putContainer( + @PathParam("appName") final String appName, + @PathParam("pageModelName") final String pageModelName, + @PathParam("containerKey") final String containerKey, + final JsonObject containerModelData + ) { final CcmApplication app = controller.findCcmApplication( - String.format("/%s/", appPath)); - - final PageModel pageModel = controller.findPageModel(app, - pageModelName); + String.format("/%s/", appName) + ); + final PageModel pageModel = controller.findPageModel( + app, pageModelName + ); final Optional result = pageModel .getContainers() @@ -181,52 +192,90 @@ public class Containers { .findAny(); final ContainerModel containerModel; + final boolean created; if (result.isPresent()) { - containerModel = result.get(); - result.get().setKey(containerKey); - containerModelRepo.save(result.get()); + containerModel.setKey(containerKey); + containerModelRepo.save(containerModel); + created = false; } else { - containerModel = new ContainerModel(); containerModel.setKey(containerKey); pageModelManager.addContainerModel(pageModel, containerModel); + created = true; } - return mapContainerModelToJson(containerModel); + if (created) { + return Response.created( + URI.create( + String.format( + "/page-models/%s/%s/containers/%s", + appName, + pageModelName, + containerKey + ) + ) + ).build(); + } else { + return Response.ok( + String.format( + "Container model %s of page model %s of application %s " + + "updated successfully.", + containerKey, + pageModelName, + appName + ) + ).build(); + } } /** * Deletes the {@link ContainerModel} identified by the provided parameters. * - * @param appPath The path of the {@link CcmApplication}. + * @param appName The path of the {@link CcmApplication}. * @param pageModelName The name of the {@link PageModel}. * @param containerKey The key identifying the {@link ContainerModel} to * delete. + * + * @return A HTTP response with the status code {@code 200} if the container + * model was deleted successfully. */ @DELETE - @Path(PageModelsApp.CONTAINER_PATH) + @Path("/{containerKey}") @Transactional(Transactional.TxType.REQUIRED) @AuthorizationRequired @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public void deleteContainer( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey) { + public Response deleteContainer( + @PathParam("appName") final String appName, + @PathParam("pageModelName") final String pageModelName, + @PathParam("containerKey") final String containerKey + ) { final CcmApplication app = controller.findCcmApplication( - String.format("/%s/", appPath)); + String.format("/%s/", appName) + ); - final PageModel pageModel = controller.findPageModel(app, - pageModelName); + final PageModel pageModel = controller.findPageModel( + app, pageModelName + ); - final ContainerModel container = controller.findContainer(app, - pageModel, - containerKey); + final ContainerModel container = controller.findContainer( + app, pageModel, containerKey + ); pageModelManager.removeContainerModel(pageModel, container); + + return Response.ok( + String.format( + "Container model %s of page model %s of application %s deleted" + + "successfully.", + containerKey, + pageModelName, + appName + ) + ).build(); } /** diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModels.java b/ccm-core/src/main/java/org/libreccm/api/pagemodels/PageModels.java similarity index 62% rename from ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModels.java rename to ccm-core/src/main/java/org/libreccm/api/pagemodels/PageModels.java index d242ee713..7a7540542 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModels.java +++ b/ccm-core/src/main/java/org/libreccm/api/pagemodels/PageModels.java @@ -16,14 +16,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ -package org.libreccm.pagemodel.rs; +package org.libreccm.api.pagemodels; import com.arsdigita.kernel.KernelConfig; import org.libreccm.configuration.ConfigurationManager; import org.libreccm.core.CoreConstants; import org.libreccm.l10n.GlobalizationHelper; -import org.libreccm.pagemodel.ComponentModel; import org.libreccm.pagemodel.ContainerModel; import org.libreccm.pagemodel.PageModel; import org.libreccm.pagemodel.PageModelManager; @@ -32,6 +31,8 @@ import org.libreccm.security.AuthorizationRequired; import org.libreccm.security.RequiresPrivilege; import org.libreccm.web.CcmApplication; +import java.net.URI; + import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.json.Json; @@ -50,11 +51,11 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; -import java.util.Date; -import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; /** * Provides RESTful endpoints for retrieving, creating, updating and deleting @@ -63,7 +64,7 @@ import java.util.stream.Collectors; * @author Jens Pelzetter */ @RequestScoped -@Path("/") +@Path("/{appName}") public class PageModels { @Inject @@ -85,29 +86,29 @@ public class PageModels { * Retrieves all {@link PageModel}s available for an {@link * CcmApplication}. * - * @param appPath The path of the {@code app}. + * @param appName The path of the {@code app}. * * @return A JSON array with the data of all {@link PageModel}s of the - * {@link CcmApplication} {@code app}. + * {@link CcmApplication} {@code app}. * * @throws NotFoundException If there is no {@link CcmApplication} with the * primary URL {@code appPath} an {@link - * NotFoundException} thrown resulting in 404 - * response. + * NotFoundException} thrown resulting in 404 response. */ @GET - @Path(PageModelsApp.PAGE_MODELS_PATH) - @Produces("application/json; charset=utf-8") + @Path("/") + @Produces(MediaType.APPLICATION_JSON) @Transactional(Transactional.TxType.REQUIRED) @AuthorizationRequired @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) public JsonArray getAllPageModels( - @PathParam(PageModelsApp.APP_NAME) String appPath) { + @PathParam("appName") String appName + ) { + Objects.requireNonNull(appName); - Objects.requireNonNull(appPath); - - final CcmApplication app = controller - .findCcmApplication(String.format("/%s/", appPath)); + final CcmApplication app = controller.findCcmApplication( + String.format("/%s/", appName) + ); final JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); pageModelRepo .findDraftByApplication(app) @@ -121,65 +122,73 @@ public class PageModels { /** * Retrieves a specific {@link PageModel}. * - * @param appPath The path ({@link CcmApplication#primaryUrl} of the + * @param appName The path ({@link CcmApplication#primaryUrl} of the * {@link CcmApplication} to which the {@link - * PageModel} belongs (see - * {@link PageModel#application}). + * PageModel} belongs (see {@link PageModel#application}). * @param pageModelName The name of the {@link PageModel} to retrieve (see * {@link PageModel#name}). * * @return A JSON object containing the data of the {@link PageModel}. * * @throws NotFoundException If there is not {@link CcmApplication} with the - * primary URL {@code appPath} a {@link - * NotFoundException} is thrown resulting in a 404 - * response. A {@link NotFoundException} is also - * thrown if there no {@link PageModel} identified - * by {@code pageModelName} for the {@link - * CcmApplication} with the primary URL {@code - * appPath}. + * primary URL {@code appPath} a + * {@link NotFoundException} is thrown resulting + * in a 404 response. A {@link NotFoundException} + * is also thrown if there no {@link PageModel} + * identified by {@code pageModelName} for the + * {@link CcmApplication} with the primary URL + * {@code appPath}. */ @GET - @Path(PageModelsApp.PAGE_MODEL_PATH) - @Produces("application/json; charset=utf-8") + @Path("/{pageModelName}") + @Produces(MediaType.APPLICATION_JSON) @Transactional(Transactional.TxType.REQUIRED) @AuthorizationRequired @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) public JsonObject getPageModel( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName) { - - Objects.requireNonNull(appPath); + @PathParam("appName") final String appName, + @PathParam("pageModelName") final String pageModelName + ) { + Objects.requireNonNull(appName); Objects.requireNonNull(pageModelName); - final CcmApplication app = controller - .findCcmApplication(String.format("/%s/", appPath)); - final PageModel pageModel = controller.findPageModel(app, - pageModelName); + final CcmApplication app = controller.findCcmApplication( + String.format("/%s/", appName) + ); + final PageModel pageModel = controller.findPageModel( + app, pageModelName + ); return mapPageModelToJson(pageModel); } @POST - @Path(PageModelsApp.PAGE_MODEL_PATH) - @Produces("application/json; charset=utf-8") + @Path("/{pageModelName}") + @Produces(MediaType.APPLICATION_JSON) @Transactional(Transactional.TxType.REQUIRED) @AuthorizationRequired @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject publishPageModel( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @FormParam("action") String action) { - + public Response publishPageModel( + @PathParam("appName") final String appName, + @PathParam("pageModelName") final String pageModelName, + @FormParam("action") String action + ) { if ("publish".equals(action)) { - - final CcmApplication app = controller - .findCcmApplication(String.format("/%s/", appPath)); - final PageModel pageModel = controller.findPageModel(app, - pageModelName); + final CcmApplication app = controller.findCcmApplication( + String.format("/%s/", appName) + ); + final PageModel pageModel = controller.findPageModel( + app, pageModelName + ); pageModelManager.publish(pageModel); } - return getPageModel(appPath, pageModelName); + return Response.ok( + String.format( + "Page model %s of application %s successfully published.", + pageModelName, + appName + ) + ).build(); } /** @@ -191,82 +200,123 @@ public class PageModels { * {@link PageModel} is created and associated with the {@link * CcmApplication} identified by the primary URL {@code appPath}. * - * @param appPath The primary URL of the {@link CcmApplication} to + * @param appName The primary URL of the {@link CcmApplication} to * which the {@link PageModel} belongs. * @param pageModelName The name of the {@link PageModel}. * @param pageModelData The data for creating or updating the {@link * PageModel}. * - * @return The new or updated {@link PageModel}. + * @return A HTTP response with status code {@code 200} if the page model + * was updated successfully or with status code {@code 201} if the + * page model was successfully created. If the page model was + * created the response also contains the URI of the new page model. */ @PUT - @Path(PageModelsApp.PAGE_MODEL_PATH) - @Consumes("application/json; charset=utf-8") - @Produces("application/json; charset=utf-8") + @Path("/{pageModelName}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) @Transactional(Transactional.TxType.REQUIRED) @AuthorizationRequired @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject putPageModel( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - final JsonObject pageModelData) { - - Objects.requireNonNull(appPath); + public Response putPageModel( + @PathParam("appName") final String appName, + @PathParam("pageModelName") final String pageModelName, + final JsonObject pageModelData + ) { + Objects.requireNonNull(appName); Objects.requireNonNull(pageModelName); - final CcmApplication app = controller - .findCcmApplication(String.format("/%s/", appPath)); + final CcmApplication app = controller.findCcmApplication( + String.format("/%s/", appName) + ); final KernelConfig kernelConfig = confManager .findConfiguration(KernelConfig.class); final PageModel pageModel; + final boolean created; if (controller.existsPageModel(app, pageModelName)) { pageModel = controller.findPageModel(app, pageModelName); - + created = false; } else { pageModel = pageModelManager.createPageModel(pageModelName, app); + created = true; } if (pageModelData.containsKey("title")) { - pageModel.getTitle().addValue(kernelConfig.getDefaultLocale(), - pageModelData.getString("title")); + pageModel.getTitle().addValue( + kernelConfig.getDefaultLocale(), + pageModelData.getString("title") + ); } if (pageModelData.containsKey("description")) { pageModel .getDescription() - .addValue(kernelConfig.getDefaultLocale(), - pageModelData.getString("description")); + .addValue( + kernelConfig.getDefaultLocale(), + pageModelData.getString("description") + ); } controller.savePageModel(pageModel); - return mapPageModelToJson(pageModel); + if (created) { + return Response.created( + URI.create( + String.format( + "/page-models/%s/%s", + appName, + pageModelName + ) + ) + ).build(); + } else { + return Response.ok( + String.format( + "Page model %s of application %s updated successfully", + pageModelName, + appName + ) + ).build(); + } } /** * Deletes a {@link PageModel}. * - * @param appPath The primary URL of the {@link CcmApplication} to + * @param appName The primary URL of the {@link CcmApplication} to * which the {@link PageModel} belongs. * @param pageModelName The name of the {@link PageModel} to delete. + * + * @return A HTTP response with status code {@code 200} if the page model + * was deleted sucessfully. */ @DELETE - @Path(PageModelsApp.PAGE_MODEL_PATH) + @Path("/{appName}/{pageModelName}") @Transactional(Transactional.TxType.REQUIRED) @AuthorizationRequired @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public void deletePageModel( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName) { - - Objects.requireNonNull(appPath); + public Response deletePageModel( + @PathParam("appName") final String appName, + @PathParam("pageModelName") final String pageModelName + ) { + Objects.requireNonNull(appName); Objects.requireNonNull(pageModelName); - final CcmApplication app = controller - .findCcmApplication(String.format("/%s/", appPath)); - final PageModel pageModel = controller.findPageModel(app, - pageModelName); + final CcmApplication app = controller.findCcmApplication( + String.format("/%s/", appName) + ); + final PageModel pageModel = controller.findPageModel( + app, pageModelName + ); pageModelRepo.delete(pageModel); + + return Response.ok( + String.format( + "Page model %s of application %s deleted successfully.", + pageModelName, + appName + ) + ).build(); } /** @@ -282,10 +332,11 @@ public class PageModels { Objects.requireNonNull(pageModel); final long lastPublished; - final Optional liveModel = pageModelManager - .getLiveVersion(pageModel); + final Optional liveModel = pageModelManager.getLiveVersion( + pageModel + ); if (liveModel.isPresent() - && liveModel.get().getLastModified() != null) { + && liveModel.get().getLastModified() != null) { lastPublished = liveModel.get().getLastModified().getTime(); } else { lastPublished = 0; @@ -300,27 +351,33 @@ public class PageModels { return Json .createObjectBuilder() .add("containers", mapContainersToJson(pageModel)) - .add("description", - globalizationHelper - .getValueFromLocalizedString(pageModel.getDescription())) + .add( + "description", + globalizationHelper.getValueFromLocalizedString( + pageModel.getDescription() + ) + ) .add("modelUuid", pageModel.getModelUuid()) .add("name", pageModel.getName()) .add("pageModelId", Long.toString(pageModel.getPageModelId())) - .add("title", - globalizationHelper - .getValueFromLocalizedString(pageModel.getTitle())) + .add( + "title", + globalizationHelper.getValueFromLocalizedString( + pageModel.getTitle() + ) + ) .add("type", pageModel.getType()) .add("uuid", pageModel.getUuid()) .add("version", pageModel.getVersion().toString()) .add("publicationStatus", - getPublicationStatus(pageModel).toString()) + getPublicationStatus(pageModel).toString() + ) .add("lastModified", lastModified) .add("lastPublished", lastPublished) .build(); } private JsonArray mapContainersToJson(final PageModel pageModel) { - final JsonArrayBuilder containers = Json.createArrayBuilder(); pageModel @@ -333,7 +390,6 @@ public class PageModels { } private JsonObject mapContainerToJson(final ContainerModel container) { - return Json .createObjectBuilder() .add("containerUuid", container.getContainerUuid()) @@ -341,7 +397,7 @@ public class PageModels { .add("uuid", container.getUuid()) .build(); } - + /** * Check if the {@link PublicationStatus} of the provided PageModel. * @@ -350,7 +406,6 @@ public class PageModels { * @return */ private PublicationStatus getPublicationStatus(final PageModel pageModel) { - final PageModel draftModel = pageModelManager .getDraftVersion(pageModel); final Optional liveModel = pageModelManager @@ -361,7 +416,7 @@ public class PageModels { // Fallback if one the last modified dates is null if (draftModel.getLastModified() == null - || liveModel.get().getLastModified() == null) { + || liveModel.get().getLastModified() == null) { return PublicationStatus.NEEDS_UPDATE; } else if (draftModel diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModelsApp.java b/ccm-core/src/main/java/org/libreccm/api/pagemodels/PageModelsApp.java similarity index 53% rename from ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModelsApp.java rename to ccm-core/src/main/java/org/libreccm/api/pagemodels/PageModelsApp.java index 82e4e0e72..e1c431a77 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModelsApp.java +++ b/ccm-core/src/main/java/org/libreccm/api/pagemodels/PageModelsApp.java @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ -package org.libreccm.pagemodel.rs; +package org.libreccm.api.pagemodels; import org.libreccm.pagemodel.PageModel; @@ -42,34 +42,9 @@ import javax.ws.rs.core.Application; * * @author Jens Pelzetter */ -@ApplicationPath("/page-models") +@ApplicationPath("/api/page-models") public class PageModelsApp extends Application { - protected static final String APP_NAME = "appName"; - protected static final String PAGE_MODEL_NAME = "pageModelName"; - protected static final String CONTAINER_KEY = "containerKey"; - protected static final String COMPONENT_KEY = "componentKey"; - - protected static final String PAGE_MODELS_PATH = "/{" + APP_NAME + "}"; - protected static final String PAGE_MODEL_PATH = PAGE_MODELS_PATH - + "/{" - + PAGE_MODEL_NAME - + "}"; - protected static final String CONTAINERS_PATH = PAGE_MODEL_PATH - + "/containers"; - protected static final String CONTAINER_PATH = CONTAINERS_PATH - + "/{" - + CONTAINER_KEY - + "}"; - protected static final String COMPONENTS_PATH = CONTAINER_PATH - + "/components"; - protected static final String COMPONENT_PATH = COMPONENTS_PATH - + "/{" - + COMPONENT_KEY - + "}"; - - protected static final String STYLES_PATH = CONTAINER_PATH + "/styles"; - @Override public Set> getClasses() { @@ -77,9 +52,6 @@ public class PageModelsApp extends Application { classes.add(PageModels.class); classes.add(Containers.class); classes.add(Components.class); - classes.add(StylesRs.class); - classes.add(StylesMediaRule.class); - classes.add(StylesRule.class); return classes; } diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModelsController.java b/ccm-core/src/main/java/org/libreccm/api/pagemodels/PageModelsController.java similarity index 72% rename from ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModelsController.java rename to ccm-core/src/main/java/org/libreccm/api/pagemodels/PageModelsController.java index eb35d69ed..7728a7ba7 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/PageModelsController.java +++ b/ccm-core/src/main/java/org/libreccm/api/pagemodels/PageModelsController.java @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ -package org.libreccm.pagemodel.rs; +package org.libreccm.api.pagemodels; import org.libreccm.pagemodel.ComponentModel; import org.libreccm.pagemodel.ComponentModelRepository; @@ -67,9 +67,12 @@ class PageModelsController { return appRepo .retrieveApplicationForPath(Objects.requireNonNull(appPath)) - .orElseThrow(() -> new NotFoundException(String - .format("No application with path \"%s\" found.", - appPath))); + .orElseThrow(() -> new NotFoundException( + String.format( + "No application with path \"%s\" found.", + appPath) + ) + ); } /** @@ -88,18 +91,23 @@ class PageModelsController { final CcmApplication app, final PageModel pageModel, final ContainerModel containerModel, - final String componentKey) { - + final String componentKey + ) { return componentModelRepo .findComponentByContainerAndKey(containerModel, componentKey) - .orElseThrow(() -> new NotFoundException(String - .format( - "The Container \"%s\" of the PageModel \"%s\" of application" - + "\"%s\" does not contain a component with the key \"%s\".", - containerModel.getKey(), - pageModel.getName(), - app.getPrimaryUrl(), - componentKey))); + .orElseThrow( + () -> new NotFoundException( + String.format( + "The Container \"%s\" of the PageModel \"%s\" of" + + " application \"%s\" does not contain a " + + "component with the key \"%s\".", + containerModel.getKey(), + pageModel.getName(), + app.getPrimaryUrl(), + componentKey + ) + ) + ); } /** @@ -113,20 +121,26 @@ class PageModelsController { * {@code containerKey}. */ @Transactional(Transactional.TxType.REQUIRED) - protected ContainerModel findContainer(final CcmApplication app, - final PageModel pageModel, - final String containerKey) { + protected ContainerModel findContainer( + final CcmApplication app, + final PageModel pageModel, + final String containerKey + ) { return containerRepo .findContainerByKeyAndPageModel( Objects.requireNonNull(containerKey), Objects.requireNonNull(pageModel)) - .orElseThrow(() -> new NotFoundException(String - .format("The PageModel \"%s\" of application \"%s\" does not have " - + "a container identified by the key \"%s\".", - pageModel.getName(), - app.getPrimaryUrl(), - containerKey))); + .orElseThrow( + () -> new NotFoundException( + String.format( + "The PageModel \"%s\" of application \"%s\" does not " + + "have a container identified by the key \"%s\".", + pageModel.getName(), + app.getPrimaryUrl(), + containerKey) + ) + ); } /** @@ -142,8 +156,9 @@ class PageModelsController { * {@link CcmApplication} {@code app}, {@code false} otherwise. */ @Transactional(Transactional.TxType.REQUIRED) - protected boolean existsPageModel(final CcmApplication app, - final String pageModelName) { + protected boolean existsPageModel( + final CcmApplication app, final String pageModelName + ) { return pageModelRepo .findDraftByApplicationAndName(app, pageModelName) .isPresent(); @@ -160,16 +175,22 @@ class PageModelsController { * {@code pageModelName} for the {@link CcmApplication} {@code app}. */ @Transactional(Transactional.TxType.REQUIRED) - protected PageModel findPageModel(final CcmApplication app, - final String pageModelName) { - + protected PageModel findPageModel( + final CcmApplication app, final String pageModelName + ) { return pageModelRepo .findDraftByApplicationAndName( Objects.requireNonNull(app), - Objects.requireNonNull(pageModelName)) - .orElseThrow(() -> new NotFoundException(String.format( - "No PageModel with name \"%s\" for application \"%s\".", - pageModelName, app.getPrimaryUrl()))); + Objects.requireNonNull(pageModelName) + ) + .orElseThrow( + () -> new NotFoundException( + String.format( + "No PageModel with name \"%s\" for application \"%s\".", + pageModelName, app.getPrimaryUrl() + ) + ) + ); } @Transactional(Transactional.TxType.REQUIRED) diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/PublicationStatus.java b/ccm-core/src/main/java/org/libreccm/api/pagemodels/PublicationStatus.java similarity index 70% rename from ccm-core/src/main/java/org/libreccm/pagemodel/rs/PublicationStatus.java rename to ccm-core/src/main/java/org/libreccm/api/pagemodels/PublicationStatus.java index ce1b19b15..9f79997ea 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/PublicationStatus.java +++ b/ccm-core/src/main/java/org/libreccm/api/pagemodels/PublicationStatus.java @@ -1,4 +1,4 @@ -package org.libreccm.pagemodel.rs; +package org.libreccm.api.pagemodels; public enum PublicationStatus { diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/package-info.java b/ccm-core/src/main/java/org/libreccm/api/pagemodels/package-info.java similarity index 96% rename from ccm-core/src/main/java/org/libreccm/pagemodel/rs/package-info.java rename to ccm-core/src/main/java/org/libreccm/api/pagemodels/package-info.java index a18589a62..b64ebcd66 100644 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/package-info.java +++ b/ccm-core/src/main/java/org/libreccm/api/pagemodels/package-info.java @@ -22,4 +22,4 @@ * editors. * */ -package org.libreccm.pagemodel.rs; +package org.libreccm.api.pagemodels; diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/Components.java b/ccm-core/src/main/java/org/libreccm/pagemodel/rs/Components.java deleted file mode 100644 index e8a1a5d84..000000000 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/Components.java +++ /dev/null @@ -1,627 +0,0 @@ -/* - * Copyright (C) 2018 LibreCCM Foundation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ -package org.libreccm.pagemodel.rs; - -import org.libreccm.core.CoreConstants; -import org.libreccm.pagemodel.ComponentModel; -import org.libreccm.pagemodel.ComponentModelJsonConverter; -import org.libreccm.pagemodel.ComponentModelRepository; -import org.libreccm.pagemodel.ContainerModel; -import org.libreccm.pagemodel.ContainerModelManager; -import org.libreccm.pagemodel.ConvertsComponentModel; -import org.libreccm.pagemodel.PageModel; -import org.libreccm.security.AuthorizationRequired; -import org.libreccm.security.RequiresPrivilege; -import org.libreccm.web.CcmApplication; - -import java.beans.PropertyDescriptor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; - -import javax.enterprise.context.RequestScoped; -import javax.enterprise.inject.Any; -import javax.enterprise.inject.Instance; -import javax.enterprise.util.AnnotationLiteral; -import javax.inject.Inject; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonArrayBuilder; -import javax.json.JsonObject; -import javax.json.JsonValue; -import javax.transaction.Transactional; -import javax.ws.rs.BadRequestException; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.WebApplicationException; - -/** - * Provides RESTful endpoints for retrieving, creating, updating and deleting - * {@link ComponentModel}s of a {@link ContainerModel}. - * - * @author Jens Pelzetter - */ -@RequestScoped -@Path("/") -public class Components { - - @Inject - private ComponentModelRepository componentRepo; - - @Inject - private ContainerModelManager containerManager; - - @Inject - private PageModelsController controller; - - @Inject - @Any - private Instance jsonConverters; - - /** - * Retrieve all {@link ComponentModel} of a {@link ContainerModel}. - * - * @param appPath The primary URL of the {@link CcmApplication}. - * @param pageModelName The name of the {@link PageModel}. - * @param containerKey The key of the {@link ContainerModel}. - * - * @return A JSON array containing the data of all {@link ComponentModel} of - * the {@link ContainerModel}. - */ - @GET - @Path(PageModelsApp.COMPONENTS_PATH) - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonArray getComponents( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - - final CcmApplication app = controller.findCcmApplication( - String.format("/%s/", appPath)); - final PageModel pageModel = controller.findPageModel(app, - pageModelName); - final ContainerModel container = controller.findContainer(app, - pageModel, - containerKey); - - final JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); - container - .getComponents() - .stream() - .map(component -> mapComponentModelToJson(component)) - .forEach(arrayBuilder::add); - - return arrayBuilder.build(); - } - - /** - * Retrieves a specific {@link ComponentModel}. - * - * @param appPath The primary URL of the {@link CcmApplication}. - * @param pageModelName The name of the {@link PageModel}. - * @param containerKey The key of the {@link ContainerModel}. - * @param componentKey The key of the {@link ComponentModel}. - * - * @return A JSON object containing the data of the {@link ComponentModel}. - */ - @GET - @Path(PageModelsApp.COMPONENT_PATH) - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject getComponent( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(PageModelsApp.COMPONENT_KEY) final String componentKey) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(componentKey); - - final CcmApplication app = controller.findCcmApplication( - String.format("/%s/", appPath)); - final PageModel pageModel = controller.findPageModel(app, - pageModelName); - final ContainerModel container = controller.findContainer(app, - pageModel, - containerKey); - final ComponentModel component = controller - .findComponentModel(app, pageModel, container, componentKey); - - return mapComponentModelToJson(component); - } - - /** - * Creates or updates a {@link ComponentModel}. - * - * If a {@link ComponentModel} with provided {@code componentKey} already - * exists in the container identified by {@code appPath}, - * {@code pageModelName} and {@code containerKey} the {@link ComponentModel} - * is updated with the data from {@code componentModelData}. - * - * Otherwise a new {@link ComponentModel} is created using the data from - * {@code componentModelData}. - * - * @param appPath The primary URL of the {@link CcmApplication}. - * @param pageModelName The name of the {@link PageModel}. - * @param containerKey The key of the {@link ContainerModel}. - * @param componentKey The key of the {@link ComponentModel} to create - * or update. - * @param componentModelData The data for creating or updating the - * {@link ComponentModel}. - * - * @return The new or updated {@link ComponentModel}. - */ - @PUT - @Path(PageModelsApp.COMPONENT_PATH) - @Consumes("application/json; charset=utf-8") - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject putComponent( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(PageModelsApp.COMPONENT_KEY) final String componentKey, - final JsonObject componentModelData) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(componentKey); - Objects.requireNonNull(componentModelData); - - final CcmApplication app = controller.findCcmApplication( - String.format("/%s/", appPath)); - final PageModel pageModel = controller.findPageModel(app, - pageModelName); - final ContainerModel container = controller.findContainer(app, - pageModel, - containerKey); - - final Optional result = container - .getComponents() - .stream() - .filter(c -> c.getKey().equals(componentKey)) - .findAny(); - - final ComponentModel componentModel; - if (result.isPresent()) { - - componentModel = result.get(); - - } else { - - componentModel = createComponentModel(componentModelData); - componentModel.setKey(componentKey); - containerManager.addComponentModel(container, componentModel); - } - - setComponentPropertiesFromJson(componentModelData, componentModel); - - componentRepo.save(componentModel); - - final ComponentModel saved = controller - .findComponentModel(app, pageModel, container, componentKey); - return mapComponentModelToJson(saved); - } - - /** - * Deletes a {@link ComponentModel}. - * - * @param appPath The primary URL of the {@link CcmApplication}. - * @param pageModelName The name of the {@link PageModel}. - * @param containerKey The key of the {@link ContainerModel}. - * @param componentKey The key of the {@link ComponentModel} to delete. - * - */ - @DELETE - @Path(PageModelsApp.COMPONENT_PATH) - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public void deleteComponent( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(PageModelsApp.COMPONENT_KEY) final String componentKey) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(componentKey); - - final CcmApplication app = controller.findCcmApplication( - String.format("/%s/", appPath)); - final PageModel pageModel = controller.findPageModel(app, - pageModelName); - final ContainerModel container = controller.findContainer(app, - pageModel, - containerKey); - final ComponentModel component = controller - .findComponentModel(app, pageModel, container, componentKey); - - containerManager.removeComponentModel(container, component); - } - - /** - * Helper method for mapping a {@link ComponentModel} to JSON. - * - * @param componentModel The {@link ComponentModel} to map. - * - * @return The JSON representation of the - * {@link ComponentModel} {@code componentModel}. - */ - private JsonObject mapComponentModelToJson( - final ComponentModel componentModel) { - - final Class clazz = Objects - .requireNonNull(componentModel) - .getClass(); - - final ComponentModelJsonConverter jsonConverter - = findJsonConverter(clazz) - .orElseThrow(() -> new WebApplicationException(String.format( - "No JSON converter available for component model \"%s\".", - clazz.getName()))); - - return jsonConverter.toJson(componentModel); - -// Objects.requireNonNull(componentModel); -// -// final JsonObjectBuilder objectBuilder = Json -// .createObjectBuilder() -// .add("componentModelId", -// Long.toString(componentModel.getComponentModelId())) -// .add("uuid", componentModel.getUuid()) -// .add("modelUuid", componentModel.getModelUuid()) -// .add("key", componentModel.getKey()) -// .add("type", componentModel.getClass().getName()); -// -// if (componentModel.getIdAttribute() != null) { -// objectBuilder.add("idAttribute", componentModel.getIdAttribute()); -// } -// -// if (componentModel.getClassAttribute() != null) { -// objectBuilder.add("classAttribute", -// componentModel.getClassAttribute()); -// } -// -// if (componentModel.getStyleAttribute() != null) { -// objectBuilder.add("styleAttribute", -// componentModel.getStyleAttribute()); -// } -// -// final Class clazz = componentModel.getClass(); -// final BeanInfo beanInfo; -// try { -// beanInfo = Introspector.getBeanInfo(clazz); -// } catch (IntrospectionException ex) { -// throw new WebApplicationException(ex); -// } -// -// for (final PropertyDescriptor propertyDescriptor -// : beanInfo.getPropertyDescriptors()) { -// -// final Method readMethod = propertyDescriptor.getReadMethod(); -// final Object value; -// try { -// value = readMethod.invoke(componentModel); -// } catch (IllegalAccessException -// | InvocationTargetException ex) { -// throw new WebApplicationException(ex); -// } -// -// final String valueStr; -// if (value == null) { -// valueStr = ""; -// } else { -// valueStr = value.toString(); -// } -// -// objectBuilder.add(propertyDescriptor.getName(), valueStr); -// -// } -// -// return objectBuilder.build(); - } - - /** - * Creates a new {@link ComponentModel} instance. - * - * Uses reflection and the value of {@code type} property from the JSON - * {@code data} to determine the correct class. - * - * @param data The data from which the new {@link ComponentModel} is - * created. - * - * @return The new {@link ComponentModel}. - */ - private ComponentModel createComponentModel(final JsonObject data) { - - Objects.requireNonNull(data); - - if (!data.containsKey("type")) { - throw new BadRequestException("The JSON data for creating the " - + "component has no value for the type of the component to " - + "create."); - } - - final String type = data.getString("type"); - final Class clazz = findComponentModelClass( - type); - - final ComponentModel componentModel; - try { - componentModel = clazz.getConstructor().newInstance(); - } catch (IllegalAccessException - | InstantiationException - | InvocationTargetException - | NoSuchMethodException ex) { - throw new WebApplicationException(ex); - } - - return componentModel; - } - - /** - * Helper method for finding the correct subclass of {@link ComponentModel} - * using the fully qualified name the class. - * - * @param type The fully qualified name of the subclass of - * {@link ComponentModel}. - * - * @return The subclass of {@link ComponentModel}. - * - * @throws BadRequestException If there is no subclass of - * {@link ComponentModel} with the fully - * qualified name provided by the {@code type} - * parameter. - */ - @SuppressWarnings("unchecked") - private Class findComponentModelClass( - final String type) { - - Objects.requireNonNull(type);; - - try { - final Class clazz = Class.forName(type); - - if (ComponentModel.class.isAssignableFrom(clazz)) { - return (Class) clazz; - } else { - throw new BadRequestException(String.format( - "The type \"%s\" is not a subclass of \"%s\".", - type, - ComponentModel.class.getName())); - } - } catch (ClassNotFoundException ex) { - throw new BadRequestException(String.format( - "The component model type \"%s\" " - + "does not exist.", - type)); - } - } - - /** - * Helper method for setting the properties of a {@link ComponentModel} from - * the JSON data. - * - * @param data The JSON data. - * @param componentModel The {@link ComponentModel}. - */ - private void setComponentPropertiesFromJson( - final JsonObject data, - final ComponentModel componentModel) { - - final Class clazz = Objects - .requireNonNull(componentModel) - .getClass(); - - final ComponentModelJsonConverter jsonConverter - = findJsonConverter(clazz) - .orElseThrow(() -> new WebApplicationException(String.format( - "No JSON converter available for component model \"%s\".", - clazz.getName()))); - - jsonConverter.fromJson(data, componentModel); - -// final BeanInfo beanInfo; -// try { -// beanInfo = Introspector.getBeanInfo(componentModel.getClass()); -// } catch (IntrospectionException ex) { -// throw new WebApplicationException(ex); -// } -// -// Arrays -// .stream(beanInfo.getPropertyDescriptors()) -// .forEach( -// propertyDesc -> setComponentPropertyFromJson(componentModel, -// propertyDesc, -// data)); - } - - /** - * Helper emthod for setting a property of a {@link ComponentModel} using a - * value from JSON data. - * - * @param componentModel The {@link ComponentModel} - * @param propertyDesc The {@link PropertyDescriptor} for the property to - * set. - * @param data The JSON data containing the new value of the - * property. - */ - private void setComponentPropertyFromJson( - final ComponentModel componentModel, - final PropertyDescriptor propertyDesc, - final JsonObject data) { - - // Ignore key and type (handled by other methods). - if ("key".equals(propertyDesc.getName()) - || "type".equals(propertyDesc.getName())) { - - return; - } - - if (data.containsKey(propertyDesc.getName())) { - - final Method writeMethod = propertyDesc.getWriteMethod(); - final Class propertyType = propertyDesc.getPropertyType(); - - if (writeMethod != null) { - try { - -// final String value = data.getString(propertyDesc.getName()); - final JsonValue value = data.get(propertyDesc.getName()); -// final JsonValue.ValueType valueType = value.getValueType(); - - if (propertyType == Boolean.TYPE) { - writeMethod.invoke( - componentModel, - Boolean.parseBoolean(value.toString())); - } else if (propertyType == Double.TYPE) { - writeMethod.invoke( - componentModel, - Double.parseDouble(value.toString())); - } else if (propertyType == Float.TYPE) { - writeMethod.invoke(componentModel, - Float.parseFloat(value.toString())); - } else if (propertyType == Integer.TYPE) { - writeMethod.invoke(componentModel, - Integer.parseInt(value.toString())); - } else if (propertyType == Long.TYPE) { - writeMethod.invoke(componentModel, - Long.parseLong(value.toString())); - } else if (propertyType == String.class) { - writeMethod.invoke(componentModel, value.toString()); - } else if (propertyType == List.class) { - - final JsonValue valueObj = data - .get(propertyDesc.getName()); - if (valueObj.getValueType() - == JsonValue.ValueType.ARRAY) { - - final JsonArray dataArray = data - .getJsonArray(propertyDesc.getName()); - final List values = dataArray - .stream() - .map(jsonValue -> jsonValue.toString()) - .collect(Collectors.toList()); - writeMethod.invoke(componentModel, values); - } else { - - String valueStr = value.toString(); - if (valueStr.startsWith("[")) { - valueStr = valueStr.substring(1); - } - - if (valueStr.endsWith("]")) { - valueStr = valueStr - .substring(valueStr.length() - 1); - } - - final String[] tokens = valueStr.split(","); - - final List values = Arrays - .stream(tokens) - .map(token -> token.trim()) - .collect(Collectors.toList()); - writeMethod.invoke(componentModel, values); - } - } else { - throw new IllegalArgumentException( - "Unsupported property type."); - } - - } catch (IllegalAccessException - | InvocationTargetException ex) { - throw new WebApplicationException(ex); - } - } - } - } - - private Optional - findJsonConverter( - final Class componentModelClass) { - - final ConvertsComponentModelLiteral literal - = new ConvertsComponentModelLiteral( - componentModelClass); - final Instance instance = jsonConverters - .select(literal); - if (instance.isUnsatisfied()) { - return Optional.empty(); - } else if (instance.isAmbiguous()) { - throw new IllegalStateException(String.format( - "Multiple JSONConverter for \"%s\".", - componentModelClass.getName())); - } else { - final Iterator iterator = instance - .iterator(); - @SuppressWarnings("unchecked") - final ComponentModelJsonConverter converter = iterator.next(); - - return Optional.of(converter); - } - } - - private static class ConvertsComponentModelLiteral - extends AnnotationLiteral - implements ConvertsComponentModel { - - private static final long serialVersionUID = 1L; - - private final Class componentModel; - - public ConvertsComponentModelLiteral( - final Class componentModel) { - - this.componentModel = componentModel; - } - - @Override - public Class componentModel() { - return componentModel; - } - - } - -} diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/StylesJsonMapper.java b/ccm-core/src/main/java/org/libreccm/pagemodel/rs/StylesJsonMapper.java deleted file mode 100644 index fbc351de0..000000000 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/StylesJsonMapper.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2018 LibreCCM Foundation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ -package org.libreccm.pagemodel.rs; - -import org.libreccm.pagemodel.styles.CssProperty; -import org.libreccm.pagemodel.styles.Dimension; -import org.libreccm.pagemodel.styles.MediaQuery; -import org.libreccm.pagemodel.styles.MediaRule; -import org.libreccm.pagemodel.styles.Rule; - -import java.util.List; -import java.util.Objects; - -import javax.enterprise.context.RequestScoped; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonArrayBuilder; -import javax.json.JsonObject; - -/** - * Utility class for mapping the entities from the - * {@link org.libreccm.pagemodel.styles} package to JSON. - * - * @author Jens Pelzetter - */ -@RequestScoped -class StylesJsonMapper { - - /** - * Map a {@link Dimension} object to JSON. - * - * @param dimension The {@link Dimension} object to map. - * - * @return A JSON object representing the provided {@link Dimension} object. - */ - protected JsonObject mapDimensionToJson(final Dimension dimension) { - - Objects.requireNonNull(dimension); - - return Json - .createObjectBuilder() - .add("value", dimension.getValue()) - .add("unit", dimension.getUnit().toString()) - .build(); - } - - /** - * Maps a List of {@link MediaRule} objects to JSON. - * - * @param mediaRules The {@link MediaRule}s to map. - * - * @return An JSON array with the data from the {@link MediaRule} objects in - * the list. - */ - protected JsonArray mapMediaRulesToJson(final List mediaRules) { - - final JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); - Objects - .requireNonNull(mediaRules) - .stream() - .map(this::mapMediaRuleToJson) - .forEach(arrayBuilder::add); - - return arrayBuilder.build(); - } - - /** - * Maps a {@link MediaRule} object to JSON. - * - * @param mediaRule The {@link MediaRule} object to map. - * - * @return The JSON representation of the provided {@link MediaRule} object. - */ - protected JsonObject mapMediaRuleToJson(final MediaRule mediaRule) { - - Objects.requireNonNull(mediaRule); - - return Json - .createObjectBuilder() - .add("mediaRuleId", mediaRule.getMediaRuleId()) - .add("mediaQuery", mapMediaQueryToJson(mediaRule.getMediaQuery())) - .add("rules", mapRulesToJson(mediaRule.getRules())) - .build(); - } - - /** - * Maps a {@link MediaQuery} object to JSON. - * - * @param mediaQuery The {@link MediaQuery} object to map. - * - * @return The JSON representation of the provided {@link MediaQuery} - * object. - */ - protected JsonObject mapMediaQueryToJson(final MediaQuery mediaQuery) { - - Objects.requireNonNull(mediaQuery); - - return Json - .createObjectBuilder() - .add("mediaQueryId", mediaQuery.getMediaQueryId()) - .add("mediaType", mediaQuery.getMediaType().toString()) - .add("minWidth", mapDimensionToJson(mediaQuery.getMinWidth())) - .add("maxWidth", mapDimensionToJson(mediaQuery.getMaxWidth())) - .build(); - } - - /** - * Maps a list of {@link Rule} objects to JSON. - * - * @param rules The list of {@link Rule} objects to map. - * - * @return A JSON array with the JSON representations of the {@link Rule} - * objects in the list. - */ - protected JsonArray mapRulesToJson(final List rules) { - - final JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); - Objects - .requireNonNull(rules) - .stream() - .map(this::mapRuleToJson) - .forEach(arrayBuilder::add); - - return arrayBuilder.build(); - } - - /** - * Maps a {@link Rule} object to JSON. - * - * @param rule The {@link Rule} object to map. - * - * @return The JSON representation of the provided {@link RuleObject}. - */ - protected JsonObject mapRuleToJson(final Rule rule) { - - Objects.requireNonNull(rule); - - return Json - .createObjectBuilder() - .add("ruleId", rule.getRuleId()) - .add("selector", rule.getSelector()) - .add("properties", mapPropertiesToJson(rule.getProperties())) - .build(); - } - - /** - * Maps a list of {@link CssProperty} objects to JSON. - * - * @param properties The list of {@link CssProperty} objects to map. - * - * @return A JSON array containing the JSON representations of the - * {@link CssProperty} objects in the list. - */ - protected JsonArray mapPropertiesToJson(final List properties) { - - final JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); - Objects - .requireNonNull(properties) - .stream() - .map(this::mapCssPropertyToJson) - .forEach(arrayBuilder::add); - - return arrayBuilder.build(); - } - - /** - * Maps a {@link CssProperty} object to JSON. - * - * @param property The {@link CssProperty} to map. - * @return The JSON representation of the provided {@link CssProperty}. - */ - protected JsonObject mapCssPropertyToJson(final CssProperty property) { - - Objects.requireNonNull(property); - - return Json - .createObjectBuilder() - .add("propertyId", property.getPropertyId()) - .add("name", property.getName()) - .add("value", property.getValue()) - .build(); - } - -} diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/StylesMediaRule.java b/ccm-core/src/main/java/org/libreccm/pagemodel/rs/StylesMediaRule.java deleted file mode 100644 index 99c1eb7da..000000000 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/StylesMediaRule.java +++ /dev/null @@ -1,622 +0,0 @@ -/* - * Copyright (C) 2018 LibreCCM Foundation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ -package org.libreccm.pagemodel.rs; - -import org.libreccm.core.CoreConstants; -import org.libreccm.pagemodel.ContainerModel; -import org.libreccm.pagemodel.styles.CssProperty; -import org.libreccm.pagemodel.styles.MediaRule; -import org.libreccm.pagemodel.styles.Rule; -import org.libreccm.pagemodel.styles.StylesManager; -import org.libreccm.pagemodel.styles.StylesRepository; -import org.libreccm.security.AuthorizationRequired; -import org.libreccm.security.RequiresPrivilege; -import org.libreccm.web.CcmApplication; - -import java.io.Serializable; -import java.util.Objects; - -import javax.enterprise.context.RequestScoped; -import javax.inject.Inject; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.transaction.Transactional; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.NotFoundException; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.WebApplicationException; - -/** - * Provides RESTful endpoints for retrieving, creating, updating and deleting - * {@link MediaRule}s. - * - * @author Jens Pelzetter - */ -@RequestScoped -@Path(StylesRs.MEDIA_RULE_PATH) -public class StylesMediaRule implements Serializable { - - private static final long serialVersionUID = 3257114872624583807L; - - protected final static String PROPERTY_ID = "propertyId"; - protected final static String RULE_ID = "ruleId"; - - protected final static String RULES_PATH = "/rules"; - protected final static String RULE_PATH = RULES_PATH - + "/{" - + RULE_ID - + "}"; - protected final static String PROPERTIES_PATH = RULE_PATH + "/properties"; - protected final static String PROPERTY_PATH = PROPERTIES_PATH - + "/{" - + PROPERTY_ID - + "}"; - - @Inject - private StylesJsonMapper stylesJsonMapper; - - @Inject - private StylesManager stylesManager; - - @Inject - private StylesRepository stylesRepo; - - @Inject - private StylesRs stylesRs; - - /** - * Retrieves all {@link Rule}s of a {@link MediaRule}. - * - * @param appPath The path of the {@link CcmApplication} to which - * the {@link PageModel} belongs. - * @param pageModelName The name of the {@link PageModel} to which the - * {@link ContainerModel} belongs. - * @param containerKey The key of the {@link ContainerModel} to which - * the {@link MediaRule} belongs. - * @param mediaRuleIdParam The ID of the {@link MediaRule}. - * - * @return A JSON array with the JSON representations of all {@link Rule}s - * belonging the {@link MediaRule} identified by the provided path. - */ - @GET - @Path(RULES_PATH) - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonArray getRules( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(StylesRs.MEDIA_RULE_ID) final String mediaRuleIdParam) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(mediaRuleIdParam); - - final MediaRule mediaRule = stylesRs.findMediaRule(appPath, - pageModelName, - containerKey, - mediaRuleIdParam); - return stylesJsonMapper.mapRulesToJson(mediaRule.getRules()); - } - - /** - * Retrieves a specific {@link Rule} from a {@link MediaRule}. - * - * @param appPath The path of the {@link CcmApplication} to which - * the {@link PageModel} belongs. - * @param pageModelName The name of the {@link PageModel} to which the - * {@link ContainerModel} belongs. - * @param containerKey The key of the {@link ContainerModel} to which - * the {@link MediaRule} belongs. - * @param mediaRuleIdParam The ID of the {@link MediaRule}. - * @param ruleIdParam The ID of the {@link Rule} to retrieve. - * - * @return The JSON representation of the {@link Rule} identified by the - * provided path. - */ - @GET - @Path(RULE_PATH) - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject getRule( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(StylesRs.MEDIA_RULE_ID) final String mediaRuleIdParam, - @PathParam(RULE_ID) String ruleIdParam) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(mediaRuleIdParam); - Objects.requireNonNull(ruleIdParam); - - final MediaRule mediaRule = stylesRs.findMediaRule(appPath, - pageModelName, - containerKey, - mediaRuleIdParam); - - return stylesJsonMapper.mapRuleToJson(findRule(mediaRule, - ruleIdParam)); - } - - /** - * Creates a new {@link Rule} for a {@link MediaRule}. - * - * @param appPath The path of the {@link CcmApplication} to which - * the {@link PageModel} belongs. - * @param pageModelName The name of the {@link PageModel} to which the - * {@link ContainerModel} belongs. - * @param containerKey The key of the {@link ContainerModel} to which - * the {@link MediaRule} belongs. - * @param mediaRuleIdParam The ID of the {@link MediaRule}. - * @param ruleData The data from which the new {@link Rule} is - * created. - * - * @return The JSON representation of the new {@link Rule}. - */ - @POST - @Path(RULES_PATH) - @Consumes("application/json; charset=utf-8") - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject createRule( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(StylesRs.MEDIA_RULE_ID) final String mediaRuleIdParam, - final JsonObject ruleData) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(mediaRuleIdParam); - Objects.requireNonNull(ruleData); - - final MediaRule mediaRule = stylesRs.findMediaRule(appPath, - pageModelName, - containerKey, - mediaRuleIdParam); - - final Rule rule = new Rule(); - rule.setSelector(ruleData.getString("selector")); - stylesManager.addRuleToMediaRule(rule, mediaRule); - - return stylesJsonMapper.mapRuleToJson(rule); - } - - /** - * Updates an existing {@link Rule} - * - * @param appPath The path of the {@link CcmApplication} to which - * the {@link PageModel} belongs. - * @param pageModelName The name of the {@link PageModel} to which the - * {@link ContainerModel} belongs. - * @param containerKey The key of the {@link ContainerModel} to which - * the {@link MediaRule} belongs. - * @param mediaRuleIdParam The ID of the {@link MediaRule}. - * @param ruleIdParam The ID of the {@link Rule} to update. - * @param ruleData The data from which used to update the - * {@link Rule}. - * - * @return The JSON representation of the updated {@link Rule}. - */ - @PUT - @Path(RULE_PATH) - @Consumes("application/json; charset=utf-8") - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject updateRule( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(StylesRs.MEDIA_RULE_ID) final String mediaRuleIdParam, - @PathParam(RULE_ID) String ruleIdParam, - final JsonObject ruleData) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(mediaRuleIdParam); - Objects.requireNonNull(ruleIdParam); - Objects.requireNonNull(ruleData); - - final MediaRule mediaRule = stylesRs.findMediaRule(appPath, - pageModelName, - containerKey, - mediaRuleIdParam); - - final Rule rule = findRule(mediaRule, ruleIdParam); - rule.setSelector(ruleData.getString("selector")); - stylesManager.addRuleToMediaRule(rule, mediaRule); - - return stylesJsonMapper.mapRuleToJson(rule); - } - - @DELETE - @Path(RULE_PATH) - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public void deleteRule( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(StylesRs.MEDIA_RULE_ID) final String mediaRuleIdParam, - @PathParam(RULE_ID) String ruleIdParam) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(mediaRuleIdParam); - Objects.requireNonNull(ruleIdParam); - - final MediaRule mediaRule = stylesRs.findMediaRule(appPath, - pageModelName, - containerKey, - mediaRuleIdParam); - - final Rule rule = findRule(mediaRule, ruleIdParam); - - stylesManager.removeRuleFromMediaRule(rule, mediaRule); - stylesRepo.deleteRule(rule); - } - - /** - * Retrieves all {@link CssProperty} objects assigned to {@link Rule} which - * is assigned to {@link MediaRule}. - * - * @param appPath The path of the {@link CcmApplication} to which - * the {@link PageModel} belongs. - * @param pageModelName The name of the {@link PageModel} to which the - * {@link ContainerModel} belongs. - * @param containerKey The key of the {@link ContainerModel} to which - * the {@link MediaRule} belongs. - * @param mediaRuleIdParam The ID of the {@link MediaRule}. - * @param ruleIdParam The ID of the {@link Rule} from which the - * {@link CssProperty} objects are retrieved. - * - * @return A JSON array with the JSON representations of the - * {@link CssProperty} objects. - */ - @GET - @Path(PROPERTIES_PATH) - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonArray getProperties( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(StylesRs.MEDIA_RULE_ID) final String mediaRuleIdParam, - @PathParam(RULE_ID) String ruleIdParam) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(mediaRuleIdParam); - Objects.requireNonNull(ruleIdParam); - - final MediaRule mediaRule = stylesRs.findMediaRule(appPath, - pageModelName, - containerKey, - mediaRuleIdParam); - - final Rule rule = findRule(mediaRule, ruleIdParam); - - return stylesJsonMapper.mapPropertiesToJson(rule.getProperties()); - } - - /** - * Retrieve a {@link CssProperty} assigned to {@link Rule} which is assigned - * to {@link MediaRule}. - * - * @param appPath The path of the {@link CcmApplication} to which - * the {@link PageModel} belongs. - * @param pageModelName The name of the {@link PageModel} to which the - * {@link ContainerModel} belongs. - * @param containerKey The key of the {@link ContainerModel} to which - * the {@link MediaRule} belongs. - * @param mediaRuleIdParam The ID of the {@link MediaRule}. - * @param ruleIdParam The ID of the {@link Rule} from which the - * {@link CssProperty} is retrieved. - * @param propertyIdParam The ID of the {@link CssProperty} to retrieve. - * - * @return The JSON representation of the {@link CssProperty} identified by - * the provided path. - */ - @GET - @Path(PROPERTY_PATH) - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject getProperty( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(StylesRs.MEDIA_RULE_ID) final String mediaRuleIdParam, - @PathParam(RULE_ID) final String ruleIdParam, - @PathParam(PROPERTY_ID) final String propertyIdParam) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(mediaRuleIdParam); - Objects.requireNonNull(ruleIdParam); - Objects.requireNonNull(propertyIdParam); - - final MediaRule mediaRule = stylesRs.findMediaRule(appPath, - pageModelName, - containerKey, - mediaRuleIdParam); - - final Rule rule = findRule(mediaRule, ruleIdParam); - final CssProperty property = findProperty(rule, propertyIdParam); - - return stylesJsonMapper.mapCssPropertyToJson(property); - } - - /** - * Creates a new {@link CssProperty} for a {@link Rule} of a - * {@link MediaRule}. - * - * @param appPath The path of the {@link CcmApplication} to which - * the {@link PageModel} belongs. - * @param pageModelName The name of the {@link PageModel} to which the - * {@link ContainerModel} belongs. - * @param containerKey The key of the {@link ContainerModel} to which - * the {@link MediaRule} belongs. - * @param mediaRuleIdParam The ID of the {@link MediaRule}. - * @param ruleIdParam The ID of the {@link Rule} for which the new - * {@link CssProperty} is created. - * @param propertyData The data from which the new {@link CssProperty} - * is created. - * - * @return The JSON representation of the new {@link CssProperty}. - */ - @POST - @Path(PROPERTIES_PATH) - @Consumes("application/json; charset=utf-8") - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject createProperty( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(StylesRs.MEDIA_RULE_ID) final String mediaRuleIdParam, - @PathParam(RULE_ID) String ruleIdParam, - final JsonObject propertyData) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(mediaRuleIdParam); - Objects.requireNonNull(ruleIdParam); - Objects.requireNonNull(propertyData); - - final MediaRule mediaRule = stylesRs.findMediaRule(appPath, - pageModelName, - containerKey, - mediaRuleIdParam); - - final Rule rule = findRule(mediaRule, ruleIdParam); - - final CssProperty property = new CssProperty(); - setCssPropertyData(property, propertyData); - stylesManager.addCssPropertyToRule(property, rule); - - return stylesJsonMapper.mapCssPropertyToJson(property); - } - - /** - * Updates an existing {@link CssProperty} of {@link Rule} of a - * {@link MediaRule}. - * - * @param appPath The path of the {@link CcmApplication} to which - * the {@link PageModel} belongs. - * @param pageModelName The name of the {@link PageModel} to which the - * {@link ContainerModel} belongs. - * @param containerKey The key of the {@link ContainerModel} to which - * the {@link MediaRule} belongs. - * @param mediaRuleIdParam The ID of the {@link MediaRule}. - * @param ruleIdParam The ID of the {@link Rule} to which the - * {@link CssProperty} belongs. - * @param propertyIdParam The ID of the {@link CssProperty} to update. - * @param propertyData The data which is used to update the - * {@link CssProperty}. - * - * @return The JSON representation of the updated {@link CssProperty}. - */ - @PUT - @Path(PROPERTY_PATH) - @Consumes("application/json; charset=utf-8") - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject updateProperty( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(StylesRs.MEDIA_RULE_ID) final String mediaRuleIdParam, - @PathParam(RULE_ID) String ruleIdParam, - @PathParam(PROPERTY_ID) final String propertyIdParam, - final JsonObject propertyData) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(mediaRuleIdParam); - Objects.requireNonNull(ruleIdParam); - Objects.requireNonNull(propertyIdParam); - Objects.requireNonNull(propertyData); - - final MediaRule mediaRule = stylesRs.findMediaRule(appPath, - pageModelName, - containerKey, - mediaRuleIdParam); - - final Rule rule = findRule(mediaRule, ruleIdParam); - - final CssProperty property = findProperty(rule, propertyIdParam); - setCssPropertyData(property, propertyData); - stylesRepo.saveCssProperty(property); - - return stylesJsonMapper.mapCssPropertyToJson(property); - } - - /** - * Deletes a {@link CssProperty} of a {@link Rule} assigned to a - * {@link MediaRule}. - * - * @param appPath The path of the {@link CcmApplication} to which - * the {@link PageModel} belongs. - * @param pageModelName The name of the {@link PageModel} to which the - * {@link ContainerModel} belongs. - * @param containerKey The key of the {@link ContainerModel} to which - * the {@link MediaRule} belongs. - * @param mediaRuleIdParam The ID of the {@link MediaRule}. - * @param ruleIdParam The ID of the {@link Rule} to which the - * {@link CssProperty} belongs. - * @param propertyIdParam The ID of the {@link CssProperty} to delete. - */ - @DELETE - @Path(PROPERTY_PATH) - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public void deleteProperty( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(StylesRs.MEDIA_RULE_ID) final String mediaRuleIdParam, - @PathParam(RULE_ID) String ruleIdParam, - @PathParam(PROPERTY_ID) final String propertyIdParam) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(mediaRuleIdParam); - Objects.requireNonNull(ruleIdParam); - Objects.requireNonNull(propertyIdParam); - - final MediaRule mediaRule = stylesRs.findMediaRule(appPath, - pageModelName, - containerKey, - mediaRuleIdParam); - - final Rule rule = findRule(mediaRule, ruleIdParam); - - final CssProperty property = findProperty(rule, propertyIdParam); - stylesManager.removeCssPropertyFromRule(property, rule); - stylesRepo.deleteCssProperty(property); - } - - /** - * Helper method for finding a {@link CssProperty}. - * - * @param rule The {@link Rule} to which the {@link CssProperty} - * belongs. - * @param propertyIdParam The ID of the {@link CssProperty} to find. - * - * @return The {@link CssProperty}. - */ - private CssProperty findProperty(final Rule rule, - final String propertyIdParam) { - - final long propertyId; - try { - propertyId = Long.parseLong(propertyIdParam); - } catch (NumberFormatException ex) { - throw new WebApplicationException(ex); - } - - return rule - .getProperties() - .stream() - .filter(property -> propertyId == property.getPropertyId()) - .findAny() - .orElseThrow(() -> new NotFoundException()); - } - - /** - * Helper method for finding a {@link Rule} assigned to {@link MediaRule}. - * - * @param mediaRule The {@link MediaRule}. - * @param ruleIdParam The ID of {@link Rule} to find. - * - * @return The {@link Rule}. - */ - private Rule findRule(final MediaRule mediaRule, - final String ruleIdParam) { - - final long ruleId; - try { - ruleId = Long.parseLong(ruleIdParam); - } catch (NumberFormatException ex) { - throw new WebApplicationException(ex); - } - - Objects.requireNonNull(mediaRule); - - return mediaRule - .getRules() - .stream() - .filter(rule -> ruleId == rule.getRuleId()) - .findAny() - .orElseThrow(() -> new NotFoundException()); - } - - /** - * Helper method for updating the values of the properties of - * {@link CssProperty} object from its JSON representation. - * - * @param property The {@link CssProperty}. - * @param propertyData The {@link JsonObject} containing the data. - */ - private void setCssPropertyData(final CssProperty property, - final JsonObject propertyData) { - - Objects.requireNonNull(property); - Objects.requireNonNull(propertyData); - - property.setName(propertyData.getString("name")); - property.setValue(propertyData.getString("value")); - } - -} diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/StylesRs.java b/ccm-core/src/main/java/org/libreccm/pagemodel/rs/StylesRs.java deleted file mode 100644 index 255789262..000000000 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/StylesRs.java +++ /dev/null @@ -1,666 +0,0 @@ -/* - * Copyright (C) 2018 LibreCCM Foundation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ -package org.libreccm.pagemodel.rs; - -import org.libreccm.core.CoreConstants; -import org.libreccm.pagemodel.ContainerModel; -import org.libreccm.pagemodel.PageModel; -import org.libreccm.pagemodel.styles.Dimension; -import org.libreccm.pagemodel.styles.MediaRule; -import org.libreccm.pagemodel.styles.MediaType; -import org.libreccm.pagemodel.styles.Rule; -import org.libreccm.pagemodel.styles.Styles; -import org.libreccm.pagemodel.styles.StylesManager; -import org.libreccm.pagemodel.styles.StylesRepository; -import org.libreccm.pagemodel.styles.Unit; -import org.libreccm.security.AuthorizationRequired; -import org.libreccm.security.RequiresPrivilege; -import org.libreccm.web.CcmApplication; - -import java.util.Objects; - -import javax.enterprise.context.RequestScoped; -import javax.inject.Inject; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.transaction.Transactional; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.NotFoundException; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.WebApplicationException; - -/** - * Provides RESTful endpoints for managing the (CSS) styles of a - * {@link ContainerModel}. - * - * @author Jens Pelzetter - */ -@RequestScoped -@Path(PageModelsApp.STYLES_PATH) -public class StylesRs { - - protected static final String MEDIA_RULE_ID = "mediaRuleId"; - protected static final String RULE_ID = "ruleId"; - - protected static final String MEDIA_RULES_PATH = "/media-rules"; - protected static final String MEDIA_RULE_PATH = MEDIA_RULES_PATH - + "/{" - + MEDIA_RULE_ID - + "}"; - protected static final String RULES_PATH = "/rules"; - protected static final String RULE_PATH = RULES_PATH - + "/{" - + RULE_ID - + "}"; - - @Inject - private PageModelsController controller; - - @Inject - private StylesJsonMapper stylesJsonMapper; - - @Inject - private StylesManager stylesManager; - - @Inject - private StylesRepository stylesRepo; - - /** - * Retrieves all {@link MediaRule}s from the {@link Styles} entity of a - * {@link ContainerModel}. - * - * @param appPath The primary URL of the {@link CcmApplication}. - * @param pageModelName The name of the {@link PageModel}. - * @param containerKey The key of the {@link ContainerModel}. - * - * @return The JSON Array with the JSON representations of all - * {@link MediaRule}s of the {@link ContainerModel} identified by - * the provided path. - */ - @GET - @Path(MEDIA_RULES_PATH) - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonArray getMediaRules( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - - final CcmApplication app = controller.findCcmApplication( - String.format("/%s/", appPath)); - - final PageModel pageModel = controller.findPageModel(app, - pageModelName); - - final ContainerModel container = controller.findContainer(app, - pageModel, - containerKey); - - final Styles styles = container.getStyles(); - - return stylesJsonMapper.mapMediaRulesToJson(styles.getMediaRules()); - - } - - /** - * Retrieves a specific {@link MediaRule} from the {@link Styles} entity of - * a {@link ContainerModel}. - * - * @param appPath The primary URL of the {@link CcmApplication}. - * @param pageModelName The name of the {@link PageModel}. - * @param containerKey The key of the {@link ContainerModel}. - * @param mediaRuleIdParam The ID of the {@link MediaRule} to retrieve. - * - * @return The JSON representation of the {@link MediaRule}. - */ - @GET - @Path(MEDIA_RULE_PATH) - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject getMediaRule( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(MEDIA_RULE_ID) final String mediaRuleIdParam) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(mediaRuleIdParam); - - return stylesJsonMapper - .mapMediaRuleToJson(findMediaRule(appPath, - pageModelName, - containerKey, - mediaRuleIdParam)); - } - - /** - * Creates a new {@link MediaRule}. - * - * @param appPath The primary URL of the {@link CcmApplication}. - * @param pageModelName The name of the {@link PageModel}. - * @param containerKey The key of the {@link ContainerModel}. - * @param mediaRuleData The data for the new {@link MediaRule}. - * - * @return The JSON representation of the new {@link MediaRule}. - */ - @POST - @Path(MEDIA_RULES_PATH) - @Consumes("application/json; charset=utf-8") - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject createMediaRule( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - final JsonObject mediaRuleData) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(mediaRuleData); - - final CcmApplication app = controller.findCcmApplication( - String.format("/%s/", appPath)); - - final PageModel pageModel = controller.findPageModel(app, - pageModelName); - - final ContainerModel container = controller.findContainer(app, - pageModel, - containerKey); - final Styles styles = container.getStyles(); - - final MediaRule mediaRule = new MediaRule(); - setMediaRuleProperties(mediaRuleData, mediaRule); - stylesManager.addMediaRuleToStyles(mediaRule, styles); - - return stylesJsonMapper.mapMediaRuleToJson(mediaRule); - } - - /** - * Update a {@link MediaRule}. - * - * @param appPath The primary URL of the {@link CcmApplication}. - * @param pageModelName The name of the {@link PageModel}. - * @param containerKey The key of the {@link ContainerModel}. - * @param mediaRuleIdParam The ID of the {@link MediaRule} to update. - * @param mediaRuleData The data for updating the {@link MediaRule}. - * - * @return The JSON representation of the updated {@link MediaRule}. - */ - @PUT - @Path(MEDIA_RULE_PATH) - @Consumes("application/json; charset=utf-8") - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject updateMediaRule( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(MEDIA_RULE_ID) final String mediaRuleIdParam, - final JsonObject mediaRuleData) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(mediaRuleIdParam); - Objects.requireNonNull(mediaRuleData); - - final MediaRule mediaRule = findMediaRule(appPath, - pageModelName, - containerKey, - mediaRuleIdParam); - setMediaRuleProperties(mediaRuleData, mediaRule); - stylesRepo.saveMediaRule(mediaRule); - - return stylesJsonMapper.mapMediaRuleToJson(mediaRule); - } - - /** - * Deletes a {@link MediaRule}. - * - * @param appPath The primary URL of the {@link CcmApplication}. - * @param pageModelName The name of the {@link PageModel}. - * @param containerKey The key of the {@link ContainerModel}. - * @param mediaRuleIdParam The ID of the {@link MediaRule} to delete. - */ - @DELETE - @Path(MEDIA_RULE_PATH) - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public void deleteMediaRule( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(MEDIA_RULE_ID) final String mediaRuleIdParam) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(mediaRuleIdParam); - - final CcmApplication app = controller.findCcmApplication( - String.format("/%s/", appPath)); - - final PageModel pageModel = controller.findPageModel(app, - pageModelName); - - final ContainerModel container = controller.findContainer(app, - pageModel, - containerKey); - - final Styles styles = container.getStyles(); - - final MediaRule mediaRule = findMediaRule(pageModel, - container, - mediaRuleIdParam); - stylesManager.removeMediaRuleFromStyles(mediaRule, styles); - } - - /** - * Retrieves all {@link Rule}s from the {@link Styles} entity of a - * {@link ContainerModel}. - * - * @param appPath The primary URL of the {@link CcmApplication}. - * @param pageModelName The name of the {@link PageModel}. - * @param containerKey The key of the {@link ContainerModel}. - * - * @return A JSON array with the JSON representation of all {@link Rule}s of - * the {@link ContainerModel}. - */ - @GET - @Path(RULES_PATH) - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonArray getRules( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - - final CcmApplication app = controller.findCcmApplication( - String.format("/%s/", appPath)); - - final PageModel pageModel = controller.findPageModel(app, - pageModelName); - - final ContainerModel container = controller.findContainer(app, - pageModel, - containerKey); - - final Styles styles = container.getStyles(); - - return stylesJsonMapper.mapRulesToJson(styles.getRules()); - } - - /** - * Retrieves a specific {@link Rule} from the {@link Styles} entity of a - * {@link ContainerModel}. - * - * @param appPath The primary URL of the {@link CcmApplication}. - * @param pageModelName The name of the {@link PageModel}. - * @param containerKey The key of the {@link ContainerModel}. - * @param ruleIdParam The ID of the {@link Rule} to retrieve. - * - * @return The JSON representation of the {@link Rule}. - */ - @GET - @Path(RULE_PATH) - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject getRule( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(RULE_ID) final String ruleIdParam) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(ruleIdParam); - - return stylesJsonMapper - .mapRuleToJson(findRule(appPath, - pageModelName, - containerKey, - ruleIdParam)); - } - - /** - * Creates a new {@link Rule}. - * - * @param appPath The primary URL of the {@link CcmApplication}. - * @param pageModelName The name of the {@link PageModel}. - * @param containerKey The key of the {@link ContainerModel}. - * @param ruleData The data for the new {@link Rule}. - * - * @return The JSON representation of the new {@link Rule}. - */ - @POST - @Path(RULES_PATH) - @Consumes("application/json; charset=utf-8") - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject createRule( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - final JsonObject ruleData) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(ruleData); - - final CcmApplication app = controller.findCcmApplication( - String.format("/%s/", appPath)); - - final PageModel pageModel = controller.findPageModel(app, - pageModelName); - - final ContainerModel container = controller.findContainer(app, - pageModel, - containerKey); - final Styles styles = container.getStyles(); - - final Rule rule = new Rule(); - rule.setSelector(ruleData.getString("selector")); - stylesManager.addRuleToStyles(rule, styles); - - return stylesJsonMapper.mapRuleToJson(rule); - } - - /** - * Updates an existing {@link Rule}. - * - * @param appPath The primary URL of the {@link CcmApplication}. - * @param pageModelName The name of the {@link PageModel}. - * @param containerKey The key of the {@link ContainerModel}. - * @param ruleIdParam The ID of the {@link Rule} to update. - * @param ruleData The data for updating the {@link Rule}. - * - * @return The JSON representation of the updated {@link Rule}. - */ - @PUT - @Path(RULE_PATH) - @Consumes("application/json; charset=utf-8") - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject updateRule( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(RULE_ID) final String ruleIdParam, - final JsonObject ruleData) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(ruleIdParam); - Objects.requireNonNull(ruleData); - - final Rule rule = findRule(appPath, - pageModelName, - containerKey, - ruleIdParam); - rule.setSelector(ruleData.getString("selector")); - stylesRepo.saveRule(rule); - return stylesJsonMapper.mapRuleToJson(rule); - } - - /** - * Deletes a {@link Rule}. - * - * @param appPath The primary URL of the {@link CcmApplication}. - * @param pageModelName The name of the {@link PageModel}. - * @param containerKey The key of the {@link ContainerModel}. - * @param ruleIdParam The ID of the {@link Rule} to delete. - */ - @DELETE - @Path(RULE_PATH) - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public void deleteRule( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(RULE_ID) final String ruleIdParam) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(ruleIdParam); - - final CcmApplication app = controller.findCcmApplication( - String.format("/%s/", appPath)); - - final PageModel pageModel = controller.findPageModel(app, - pageModelName); - - final ContainerModel container = controller.findContainer(app, - pageModel, - containerKey); - - final Styles styles = container.getStyles(); - - final Rule rule = findRule(pageModel, container, ruleIdParam); - stylesManager.removeRuleFromStyles(rule, styles); - } - - /** - * An utility method for finding a {@link MediaRule}. - * - * @param appPath The primary URL of the {@link CcmApplication}. - * @param pageModelName The name of the {@link PageModel}. - * @param containerKey The key of the {@link ContainerModel}. - * @param mediaRuleIdParam The ID of the {@link MediaRule} to find. - * - * @return The {@link MediaRule} with the provided {@code mediaRuleId}. - */ - protected MediaRule findMediaRule(final String appPath, - final String pageModelName, - final String containerKey, - final String mediaRuleIdParam) { - - final CcmApplication app = controller.findCcmApplication( - String.format("/%s/", appPath)); - - final PageModel pageModel = controller.findPageModel(app, - pageModelName); - - final ContainerModel container = controller.findContainer(app, - pageModel, - containerKey); - - return findMediaRule(pageModel, container, mediaRuleIdParam); - } - - /** - * An utility method for finding a {@link MediaRule}. - * - * @param pageModel The {@link PageModel} to which the - * {@link ContainerModel} belongs. - * @param container The {@link ContainerModel} to which the - * {@link MediaRule} belongs. - * @param mediaRuleIdParam The ID of the {@link MediaRule} to find. - * - * @return The {@link MediaRule} with the ID {@code mediaRuleIdParam}. - */ - private MediaRule findMediaRule(final PageModel pageModel, - final ContainerModel container, - final String mediaRuleIdParam) { - - final Styles styles = container.getStyles(); - - final long mediaRuleId; - try { - mediaRuleId = Long.parseLong(mediaRuleIdParam); - } catch (NumberFormatException ex) { - throw new WebApplicationException(String.format( - "The provided mediaRuleId \"%s\" numeric.", mediaRuleIdParam)); - } - - return styles - .getMediaRules() - .stream() - .filter(mediaRule -> mediaRuleId == mediaRule.getMediaRuleId()) - .findAny() - .orElseThrow(() -> new NotFoundException(String.format( - "No MediaRule with ID %d available in the Styles for " - + "Container \"%s\" of PageModel \"%s\".", - mediaRuleId, - container.getKey(), - pageModel.getName()))); - } - - /** - * Utility method for finding a {@link Rule}. - * - * @param appPath The primary URL of the {@link CcmApplication}. - * @param pageModelName The name of the {@link PageModel}. - * @param containerKey The key of the {@link ContainerModel}. - * @param ruleIdParam The ID of the {@link Rule} to find. - * - * @return The {@link Rule} identified by {@code ruleIdParam}. - */ - protected Rule findRule(final String appPath, - final String pageModelName, - final String containerKey, - final String ruleIdParam) { - - final CcmApplication app = controller.findCcmApplication( - String.format("/%s/", appPath)); - - final PageModel pageModel = controller.findPageModel(app, - pageModelName); - - final ContainerModel container = controller.findContainer(app, - pageModel, - containerKey); - - return findRule(pageModel, container, ruleIdParam); - } - - /** - * An utility method for finding a {@link Rule}. - * - * @param pageModel The {@link PageModel} to which the - * {@link ContainerModel} belongs. - * @param container The {@link ContainerModel} to which the {@link Rule} - * belongs. - * @param ruleIdParam The ID of the {@link Rule} to find. - * - * @return The {@link Rule} with the ID {@code ruleIdParam}. - */ - private Rule findRule(final PageModel pageModel, - final ContainerModel container, - final String ruleIdParam) { - - final Styles styles = container.getStyles(); - - final long ruleId; - try { - ruleId = Long.parseLong(ruleIdParam); - } catch (NumberFormatException ex) { - throw new WebApplicationException(String.format( - "The provided mediaRuleId \"%s\" numeric.", ruleIdParam)); - } - - return styles - .getRules() - .stream() - .filter(rule -> ruleId == rule.getRuleId()) - .findAny() - .orElseThrow(() -> new NotFoundException(String.format( - "No Rule with ID %d available in the Styles for " - + "Container \"%s\" of PageModel \"%s\".", - ruleId, - container.getKey(), - pageModel.getName()))); - } - - /** - * Helper method for setting the values of the properties of a - * {@link MediaRule} using the data from a JSON object. - * - * @param mediaRuleData The JSON object providing the data. - * @param mediaRule The {@link MediaRule}. - */ - private void setMediaRuleProperties(final JsonObject mediaRuleData, - final MediaRule mediaRule) { - - Objects.requireNonNull(mediaRuleData); - Objects.requireNonNull(mediaRule); - - final JsonObject mediaQueryData = mediaRuleData - .getJsonObject("mediaQuery"); - final JsonObject maxWidthData = mediaQueryData - .getJsonObject("maxWidth"); - final JsonObject minWidthData = mediaQueryData - .getJsonObject("minWidth"); - - final Dimension maxWidth = new Dimension(); - maxWidth.setUnit(Unit.valueOf(maxWidthData.getString("unit"))); - maxWidth.setValue(maxWidthData.getJsonNumber("value").doubleValue()); - final MediaType mediaType = MediaType.valueOf(mediaQueryData - .getString("mediaType")); - - final Dimension minWidth = new Dimension(); - minWidth.setUnit(Unit.valueOf(minWidthData.getString("unit"))); - minWidth.setValue(minWidthData.getJsonNumber("minWidth").doubleValue()); - - mediaRule.getMediaQuery().setMaxWidth(maxWidth); - mediaRule.getMediaQuery().setMediaType(mediaType); - mediaRule.getMediaQuery().setMinWidth(minWidth); - } - -} diff --git a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/StylesRule.java b/ccm-core/src/main/java/org/libreccm/pagemodel/rs/StylesRule.java deleted file mode 100644 index c396f0437..000000000 --- a/ccm-core/src/main/java/org/libreccm/pagemodel/rs/StylesRule.java +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright (C) 2018 LibreCCM Foundation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ -package org.libreccm.pagemodel.rs; - -import org.libreccm.core.CoreConstants; -import org.libreccm.pagemodel.ContainerModel; -import org.libreccm.pagemodel.styles.CssProperty; -import org.libreccm.pagemodel.styles.Rule; -import org.libreccm.pagemodel.styles.StylesManager; -import org.libreccm.pagemodel.styles.StylesRepository; -import org.libreccm.security.AuthorizationRequired; -import org.libreccm.security.RequiresPrivilege; -import org.libreccm.web.CcmApplication; - -import java.io.Serializable; -import java.util.Objects; - -import javax.enterprise.context.RequestScoped; -import javax.inject.Inject; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.transaction.Transactional; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.NotFoundException; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.WebApplicationException; - -/** - * Provides RESTful endpoints for retrieving, creating, updating and deleting - * {@link Rule} objects. - * - * @author Jens Pelzetter - */ -@RequestScoped -@Path(StylesRs.RULE_PATH) -public class StylesRule implements Serializable { - - private static final long serialVersionUID = -8447970787677773230L; - - protected final static String PROPERTY_ID = "propertyId"; - - protected final static String PROPERTIES_PATH = "/properties"; - protected final static String PROPERTY_PATH = PROPERTIES_PATH - + "/{" - + PROPERTY_ID - + "}"; - - @Inject - private StylesJsonMapper stylesJsonMapper; - - @Inject - private StylesManager stylesManager; - - @Inject - private StylesRepository stylesRepo; - - @Inject - private StylesRs stylesRs; - - /** - * Retrieves all {@link CssProperty} objects of a {@link Rule} assigned to - * the {@link Styles} entity of a {@link ContainerModel}. - * - * @param appPath The primary URL of the {@link CcmApplication} to - * which the {@link PageModel} belongs. - * @param pageModelName The name of the {@link PageModel} to which the - * {@link ContainerModel} belongs. - * @param containerKey The key of the {@link ContainerModel} to which the - * {@link Rule} belongs. - * @param ruleIdParam The ID of the {@link Rule} from which the - * {@link CssProperty} objects are retrieved. - * - * @return A JSON array with the JSON representation of the - * {@link CssProperty} objects of the {@link Rule} identified by the - * provided path. - */ - @GET - @Path(PROPERTIES_PATH) - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonArray getProperties( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(StylesRs.RULE_ID) final String ruleIdParam) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(ruleIdParam); - - final Rule rule = stylesRs.findRule(appPath, - pageModelName, - containerKey, - ruleIdParam); - return stylesJsonMapper.mapPropertiesToJson(rule.getProperties()); - } - - /** - * Retrieves a specific {@link CssProperty} from a {@link Rule} assigned to - * the {@link Styles} entity of a {@link ContainerModel}. - * - * @param appPath The primary URL of the {@link CcmApplication} to - * which the {@link PageModel} belongs. - * @param pageModelName The name of the {@link PageModel} to which the - * {@link ContainerModel} belongs. - * @param containerKey The key of the {@link ContainerModel} to which the - * {@link Rule} belongs. - * @param ruleIdParam The ID of the {@link Rule} to which the - * {@link CssProperty} is assigned. - * @param propertyIdParam The ID of the {@link CssProperty} to retrieve. - * - * @return The JSON representation of the {@link CssProperty}. - */ - @GET - @Path(PROPERTY_PATH) - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject getProperty( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(StylesRs.RULE_ID) final String ruleIdParam, - @PathParam(PROPERTY_ID) final String propertyIdParam) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(ruleIdParam); - Objects.requireNonNull(propertyIdParam); - - final Rule rule = stylesRs.findRule(appPath, - pageModelName, - containerKey, - ruleIdParam); - - return stylesJsonMapper - .mapCssPropertyToJson(findProperty(rule, - propertyIdParam)); - } - - /** - * Creates a new {@link CssProperty} for a {@link Rule} assigned to the - * {@link Styles} entity of a {@link ContainerModel}. - * - * @param appPath The primary URL of the {@link CcmApplication} to - * which the {@link PageModel} belongs. - * @param pageModelName The name of the {@link PageModel} to which the - * {@link ContainerModel} belongs. - * @param containerKey The key of the {@link ContainerModel} to which the - * {@link Rule} belongs. - * @param ruleIdParam The ID of the {@link Rule} to which the - * {@link CssProperty} is assigned. - * @param propertyData The data used to create the new {@link CssProperty}. - * - * @return The JSON representation of the new {@link CssProperty}. - */ - @POST - @Path(PROPERTIES_PATH) - @Consumes("application/json; charset=utf-8") - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject createProperty( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(StylesRs.RULE_ID) final String ruleIdParam, - final JsonObject propertyData) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(ruleIdParam); - Objects.requireNonNull(propertyData); - - final Rule rule = stylesRs.findRule(appPath, - pageModelName, - containerKey, - ruleIdParam); - - final CssProperty property = new CssProperty(); - setCssPropertyData(property, propertyData); - stylesManager.addCssPropertyToRule(property, rule); - - return stylesJsonMapper.mapCssPropertyToJson(property); - } - - /** - * Updates an existing {@link CssProperty} for a {@link Rule} assigned to - * the {@link Styles} entity of a {@link ContainerModel}. - * - * @param appPath The primary URL of the {@link CcmApplication} to - * which the {@link PageModel} belongs. - * @param pageModelName The name of the {@link PageModel} to which the - * {@link ContainerModel} belongs. - * @param containerKey The key of the {@link ContainerModel} to which the - * {@link Rule} belongs. - * @param ruleIdParam The ID of the {@link Rule} to which the - * {@link CssProperty} is assigned. - * @param propertyIdParam The ID of the {@link CssProperty} to update. - * @param propertyData The data used to update the {@link CssProperty}. - * - * @return The JSON representation of the updated {@link CssProperty}. - */ - @PUT - @Path(PROPERTY_PATH) - @Consumes("application/json; charset=utf-8") - @Produces("application/json; charset=utf-8") - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public JsonObject updateProperty( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(StylesRs.RULE_ID) final String ruleIdParam, - @PathParam(PROPERTY_ID) final String propertyIdParam, - final JsonObject propertyData) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(ruleIdParam); - Objects.requireNonNull(propertyIdParam); - Objects.requireNonNull(propertyData); - - final Rule rule = stylesRs.findRule(appPath, - pageModelName, - containerKey, - ruleIdParam); - - final CssProperty property = findProperty(rule, propertyIdParam); - setCssPropertyData(property, propertyData); - stylesRepo.saveCssProperty(property); - - return stylesJsonMapper.mapCssPropertyToJson(property); - } - - /** - * Deletes{@link CssProperty} for a {@link Rule} assigned to the - * {@link Styles} entity of a {@link ContainerModel}. - * - * @param appPath The primary URL of the {@link CcmApplication} to - * which the {@link PageModel} belongs. - * @param pageModelName The name of the {@link PageModel} to which the - * {@link ContainerModel} belongs. - * @param containerKey The key of the {@link ContainerModel} to which the - * {@link Rule} belongs. - * @param ruleIdParam The ID of the {@link Rule} to which the - * {@link CssProperty} is assigned. - * @param propertyIdParam The ID of the {@link CssProperty} to delete. - */ - @DELETE - @Path(PROPERTY_PATH) - @Transactional(Transactional.TxType.REQUIRED) - @AuthorizationRequired - @RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN) - public void deleteProperty( - @PathParam(PageModelsApp.APP_NAME) final String appPath, - @PathParam(PageModelsApp.PAGE_MODEL_NAME) final String pageModelName, - @PathParam(PageModelsApp.CONTAINER_KEY) final String containerKey, - @PathParam(StylesRs.RULE_ID) final String ruleIdParam, - @PathParam(PROPERTY_ID) final String propertyIdParam) { - - Objects.requireNonNull(appPath); - Objects.requireNonNull(pageModelName); - Objects.requireNonNull(containerKey); - Objects.requireNonNull(ruleIdParam); - Objects.requireNonNull(propertyIdParam); - - final Rule rule = stylesRs.findRule(appPath, - pageModelName, - containerKey, - ruleIdParam); - - final CssProperty property = findProperty(rule, propertyIdParam); - stylesManager.removeCssPropertyFromRule(property, rule); - stylesRepo.deleteCssProperty(property); - } - - /** - * Helper method for finding a {@link CssProperty} assigned to {@link Rule}. - * - * @param rule The {@link Rule}. - * @param propertyIdParam The ID of the {@link CssProperty} to find. - * - * @return The {@link CssProperty} identified by {@code propertyIdParam}. - */ - private CssProperty findProperty(final Rule rule, - final String propertyIdParam) { - - Objects.requireNonNull(rule); - Objects.requireNonNull(propertyIdParam); - - final long propertyId; - try { - propertyId = Long.parseLong(propertyIdParam); - } catch (NumberFormatException ex) { - throw new WebApplicationException(ex); - } - - return rule - .getProperties() - .stream() - .filter(property -> propertyId == property.getPropertyId()) - .findAny() - .orElseThrow(() -> new NotFoundException()); - } - - /** - * Helper method for updating a {@link CssProperty} object with data from - * its JSON representation. - * - * @param property The {@link CssProperty}. - * @param propertyData The data. - */ - private void setCssPropertyData(final CssProperty property, - final JsonObject propertyData) { - - Objects.requireNonNull(property); - Objects.requireNonNull(propertyData); - - property.setName(propertyData.getString("name")); - property.setValue(propertyData.getString("value")); - } - -} diff --git a/ccm-core/src/site/resources/ccm-core-api.json b/ccm-core/src/site/resources/ccm-core-api.json index 2e85e1652..3d041bcdf 100644 --- a/ccm-core/src/site/resources/ccm-core-api.json +++ b/ccm-core/src/site/resources/ccm-core-api.json @@ -67,6 +67,99 @@ } } }, + "/api/admin/categories/{domainIdentifier}/{path}" : { + "get" : { + "operationId" : "getCategory_2", + "parameters" : [ { + "name" : "domainIdentifier", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "path", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "default" : { + "description" : "default response", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/CategoryData" + } + } + } + } + } + }, + "put" : { + "operationId" : "updateCategory_2", + "parameters" : [ { + "name" : "domainIdentifier", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "path", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/CategoryData" + } + } + } + }, + "responses" : { + "default" : { + "description" : "default response", + "content" : { + "*/*" : { } + } + } + } + }, + "delete" : { + "operationId" : "deleteCategory_1", + "parameters" : [ { + "name" : "domainIdentifier", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "path", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "default" : { + "description" : "default response", + "content" : { + "*/*" : { } + } + } + } + } + }, "/api/admin/categories/ID-{categoryId}" : { "get" : { "operationId" : "getCategory_1", @@ -122,7 +215,7 @@ } }, "delete" : { - "operationId" : "deleteCategory_1", + "operationId" : "deleteCategory_2", "parameters" : [ { "name" : "categoryId", "in" : "path", @@ -142,102 +235,9 @@ } } }, - "/api/admin/categories/{domainIdentifier}/{path}" : { - "get" : { - "operationId" : "getCategory", - "parameters" : [ { - "name" : "domainIdentifier", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "name" : "path", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "default" : { - "description" : "default response", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/CategoryData" - } - } - } - } - } - }, - "put" : { - "operationId" : "updateCategory_2", - "parameters" : [ { - "name" : "domainIdentifier", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "name" : "path", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - } ], - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/CategoryData" - } - } - } - }, - "responses" : { - "default" : { - "description" : "default response", - "content" : { - "*/*" : { } - } - } - } - }, - "delete" : { - "operationId" : "deleteCategory_2", - "parameters" : [ { - "name" : "domainIdentifier", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "name" : "path", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "default" : { - "description" : "default response", - "content" : { - "*/*" : { } - } - } - } - } - }, "/api/admin/categories/{domainIdentifier}/{path}/subcategories" : { "get" : { - "operationId" : "getSubCategories", + "operationId" : "getSubCategories_2", "parameters" : [ { "name" : "domainIdentifier", "in" : "path", @@ -318,48 +318,9 @@ } } }, - "/api/admin/categories/UUID-{uuid}/objects" : { - "get" : { - "operationId" : "getObjectsInCategory", - "parameters" : [ { - "name" : "uuid", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "name" : "limit", - "in" : "query", - "schema" : { - "type" : "integer", - "format" : "int32" - } - }, { - "name" : "offset", - "in" : "query", - "schema" : { - "type" : "integer", - "format" : "int32" - } - } ], - "responses" : { - "default" : { - "description" : "default response", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ListViewCategorizationData" - } - } - } - } - } - } - }, "/api/admin/categories/{domainIdentifier}/{path}/objects" : { "get" : { - "operationId" : "getObjectsInCategory_1", + "operationId" : "getObjectsInCategory", "parameters" : [ { "name" : "domainIdentifier", "in" : "path", @@ -438,6 +399,45 @@ } } }, + "/api/admin/categories/UUID-{uuid}/objects" : { + "get" : { + "operationId" : "getObjectsInCategory_1", + "parameters" : [ { + "name" : "uuid", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "limit", + "in" : "query", + "schema" : { + "type" : "integer", + "format" : "int32" + } + }, { + "name" : "offset", + "in" : "query", + "schema" : { + "type" : "integer", + "format" : "int32" + } + } ], + "responses" : { + "default" : { + "description" : "default response", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ListViewCategorizationData" + } + } + } + } + } + } + }, "/api/admin/categories/ID-{categoryId}/objects" : { "get" : { "operationId" : "getCategoryObjectsInCategory", @@ -509,7 +509,7 @@ } }, "delete" : { - "operationId" : "removeObjectFromCategory_1", + "operationId" : "removeObjectFromCategory", "parameters" : [ { "name" : "categoryId", "in" : "path", @@ -568,7 +568,7 @@ }, "/api/admin/categories/{domainIdentifier}/{path}/objects/{objectIdentifier}" : { "delete" : { - "operationId" : "removeObjectFromCategory", + "operationId" : "removeObjectFromCategory_1", "parameters" : [ { "name" : "domainIdentifier", "in" : "path", @@ -629,32 +629,15 @@ } } }, - "/api/admin/categories/ID-{categoryId}/subcategories" : { + "/api/admin/categories/UUID-{categoryId}" : { "get" : { - "operationId" : "getSubCategories_1", + "operationId" : "getCategory", "parameters" : [ { "name" : "categoryId", "in" : "path", "required" : true, "schema" : { - "type" : "integer", - "format" : "int64" - } - }, { - "name" : "limit", - "in" : "query", - "schema" : { - "type" : "integer", - "format" : "int32", - "default" : 20 - } - }, { - "name" : "offset", - "in" : "query", - "schema" : { - "type" : "integer", - "format" : "int32", - "default" : 20 + "type" : "string" } } ], "responses" : { @@ -663,7 +646,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/ListViewCategoryData" + "$ref" : "#/components/schemas/CategoryData" } } } @@ -673,7 +656,7 @@ }, "/api/admin/categories/UUID-{categoryUid}/subcategories" : { "get" : { - "operationId" : "getSubCategories_2", + "operationId" : "getSubCategories", "parameters" : [ { "name" : "categoryUuid", "in" : "path", @@ -712,15 +695,32 @@ } } }, - "/api/admin/categories/UUID-{categoryId}" : { + "/api/admin/categories/ID-{categoryId}/subcategories" : { "get" : { - "operationId" : "getCategory_2", + "operationId" : "getSubCategories_1", "parameters" : [ { "name" : "categoryId", "in" : "path", "required" : true, "schema" : { - "type" : "string" + "type" : "integer", + "format" : "int64" + } + }, { + "name" : "limit", + "in" : "query", + "schema" : { + "type" : "integer", + "format" : "int32", + "default" : 20 + } + }, { + "name" : "offset", + "in" : "query", + "schema" : { + "type" : "integer", + "format" : "int32", + "default" : 20 } } ], "responses" : { @@ -729,7 +729,7 @@ "content" : { "application/json" : { "schema" : { - "$ref" : "#/components/schemas/CategoryData" + "$ref" : "#/components/schemas/ListViewCategoryData" } } } @@ -1119,6 +1119,60 @@ } } }, + "/api/admin/groups/{groupIdentifier}/members/{userIdentifier}" : { + "put" : { + "operationId" : "addMember", + "parameters" : [ { + "name" : "groupIdentifier", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "userIdentifier", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "default" : { + "description" : "default response", + "content" : { + "*/*" : { } + } + } + } + }, + "delete" : { + "operationId" : "removeMember", + "parameters" : [ { + "name" : "groupIdentifier", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "userIdentifier", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "default" : { + "description" : "default response", + "content" : { + "*/*" : { } + } + } + } + } + }, "/api/admin/groups/{groupIdentifier}" : { "get" : { "operationId" : "getGroup", @@ -1245,6 +1299,47 @@ } } }, + "/api/admin/groups/{groupIdentifier}/members" : { + "get" : { + "operationId" : "getMembers", + "parameters" : [ { + "name" : "groupIdentifier", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "limit", + "in" : "query", + "schema" : { + "type" : "integer", + "format" : "int32", + "default" : 20 + } + }, { + "name" : "offset", + "in" : "query", + "schema" : { + "type" : "integer", + "format" : "int32", + "default" : 0 + } + } ], + "responses" : { + "default" : { + "description" : "default response", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ListViewGroupUserMembership" + } + } + } + } + } + } + }, "/api/admin/groups/{groupIdentifier}/roles" : { "get" : { "operationId" : "getRoleMemberships", @@ -1327,101 +1422,6 @@ } } }, - "/api/admin/groups/{groupIdentifier}/members/{userIdentifier}" : { - "put" : { - "operationId" : "addMember", - "parameters" : [ { - "name" : "groupIdentifier", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "name" : "userIdentifier", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "default" : { - "description" : "default response", - "content" : { - "*/*" : { } - } - } - } - }, - "delete" : { - "operationId" : "removeMember", - "parameters" : [ { - "name" : "groupIdentifier", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "name" : "userIdentifier", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "default" : { - "description" : "default response", - "content" : { - "*/*" : { } - } - } - } - } - }, - "/api/admin/groups/{groupIdentifier}/members" : { - "get" : { - "operationId" : "getMembers", - "parameters" : [ { - "name" : "groupIdentifier", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "name" : "limit", - "in" : "query", - "schema" : { - "type" : "integer", - "format" : "int32", - "default" : 20 - } - }, { - "name" : "offset", - "in" : "query", - "schema" : { - "type" : "integer", - "format" : "int32", - "default" : 0 - } - } ], - "responses" : { - "default" : { - "description" : "default response", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ListViewGroupUserMembership" - } - } - } - } - } - } - }, "/api/admin/roles/{roleIdentifier}" : { "get" : { "operationId" : "getRole", @@ -1494,9 +1494,9 @@ } } }, - "/api/admin/roles/{roleIdentifier}/permissions/{permissionIdentifier}" : { - "delete" : { - "operationId" : "removePermission", + "/api/admin/roles/{roleIdentifier}/members/{partyIdentifier}" : { + "put" : { + "operationId" : "addMember_1", "parameters" : [ { "name" : "roleIdentifier", "in" : "path", @@ -1505,7 +1505,7 @@ "type" : "string" } }, { - "name" : "permissionIdentifier", + "name" : "partyIdentifier", "in" : "path", "required" : true, "schema" : { @@ -1520,52 +1520,24 @@ } } } - } - }, - "/api/admin/roles" : { - "get" : { - "operationId" : "getRoles", + }, + "delete" : { + "operationId" : "removeMember_1", "parameters" : [ { - "name" : "limit", - "in" : "query", + "name" : "roleIdentifier", + "in" : "path", + "required" : true, "schema" : { - "type" : "integer", - "format" : "int32", - "default" : 20 + "type" : "string" } }, { - "name" : "offset", - "in" : "query", + "name" : "partyIdentifier", + "in" : "path", + "required" : true, "schema" : { - "type" : "integer", - "format" : "int32", - "default" : 0 + "type" : "string" } } ], - "responses" : { - "default" : { - "description" : "default response", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ListViewRoleData" - } - } - } - } - } - }, - "post" : { - "operationId" : "addRole", - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/RoleData" - } - } - } - }, "responses" : { "default" : { "description" : "default response", @@ -1645,60 +1617,6 @@ } } }, - "/api/admin/roles/{roleIdentifier}/members/{partyIdentifier}" : { - "put" : { - "operationId" : "addMember_1", - "parameters" : [ { - "name" : "roleIdentifier", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "name" : "partyIdentifier", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "default" : { - "description" : "default response", - "content" : { - "*/*" : { } - } - } - } - }, - "delete" : { - "operationId" : "removeMember_1", - "parameters" : [ { - "name" : "roleIdentifier", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - }, { - "name" : "partyIdentifier", - "in" : "path", - "required" : true, - "schema" : { - "type" : "string" - } - } ], - "responses" : { - "default" : { - "description" : "default response", - "content" : { - "*/*" : { } - } - } - } - } - }, "/api/admin/roles/{roleIdentifier}/members" : { "get" : { "operationId" : "getMembers_1", @@ -1740,6 +1658,142 @@ } } }, + "/api/admin/roles" : { + "get" : { + "operationId" : "getRoles", + "parameters" : [ { + "name" : "limit", + "in" : "query", + "schema" : { + "type" : "integer", + "format" : "int32", + "default" : 20 + } + }, { + "name" : "offset", + "in" : "query", + "schema" : { + "type" : "integer", + "format" : "int32", + "default" : 0 + } + } ], + "responses" : { + "default" : { + "description" : "default response", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ListViewRoleData" + } + } + } + } + } + }, + "post" : { + "operationId" : "addRole", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/RoleData" + } + } + } + }, + "responses" : { + "default" : { + "description" : "default response", + "content" : { + "*/*" : { } + } + } + } + } + }, + "/api/admin/roles/{roleIdentifier}/permissions/{permissionIdentifier}" : { + "delete" : { + "operationId" : "removePermission", + "parameters" : [ { + "name" : "roleIdentifier", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + }, { + "name" : "permissionIdentifier", + "in" : "path", + "required" : true, + "schema" : { + "type" : "string" + } + } ], + "responses" : { + "default" : { + "description" : "default response", + "content" : { + "*/*" : { } + } + } + } + } + }, + "/api/admin/users" : { + "get" : { + "operationId" : "getUsers", + "parameters" : [ { + "name" : "limit", + "in" : "query", + "schema" : { + "type" : "integer", + "format" : "int32", + "default" : 20 + } + }, { + "name" : "offset", + "in" : "query", + "schema" : { + "type" : "integer", + "format" : "int32", + "default" : 0 + } + } ], + "responses" : { + "default" : { + "description" : "default response", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/ListViewUserData" + } + } + } + } + } + }, + "post" : { + "operationId" : "addUser", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/User" + } + } + } + }, + "responses" : { + "default" : { + "description" : "default response", + "content" : { + "*/*" : { } + } + } + } + } + }, "/api/admin/users/{userIdentifier}" : { "get" : { "operationId" : "getUser", @@ -1812,60 +1866,6 @@ } } }, - "/api/admin/users" : { - "get" : { - "operationId" : "getUsers", - "parameters" : [ { - "name" : "limit", - "in" : "query", - "schema" : { - "type" : "integer", - "format" : "int32", - "default" : 20 - } - }, { - "name" : "offset", - "in" : "query", - "schema" : { - "type" : "integer", - "format" : "int32", - "default" : 0 - } - } ], - "responses" : { - "default" : { - "description" : "default response", - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/ListViewUserData" - } - } - } - } - } - }, - "post" : { - "operationId" : "addUser", - "requestBody" : { - "content" : { - "application/json" : { - "schema" : { - "$ref" : "#/components/schemas/User" - } - } - } - }, - "responses" : { - "default" : { - "description" : "default response", - "content" : { - "*/*" : { } - } - } - } - } - }, "/api/admin/users/{userIdentifier}/roles" : { "get" : { "operationId" : "getRoleMemberships_1", @@ -2521,13 +2521,13 @@ } } }, - "ListViewGroupData" : { + "ListViewGroupUserMembership" : { "type" : "object", "properties" : { "list" : { "type" : "array", "items" : { - "$ref" : "#/components/schemas/GroupData" + "$ref" : "#/components/schemas/GroupUserMembership" } }, "count" : { @@ -2544,13 +2544,13 @@ } } }, - "ListViewGroupUserMembership" : { + "ListViewGroupData" : { "type" : "object", "properties" : { "list" : { "type" : "array", "items" : { - "$ref" : "#/components/schemas/GroupUserMembership" + "$ref" : "#/components/schemas/GroupData" } }, "count" : { @@ -2625,29 +2625,6 @@ } } }, - "ListViewRoleData" : { - "type" : "object", - "properties" : { - "list" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/RoleData" - } - }, - "count" : { - "type" : "integer", - "format" : "int64" - }, - "limit" : { - "type" : "integer", - "format" : "int64" - }, - "offset" : { - "type" : "integer", - "format" : "int64" - } - } - }, "ListViewRolePermission" : { "type" : "object", "properties" : { @@ -2709,90 +2686,13 @@ } } }, - "EmailAddressData" : { - "type" : "object", - "properties" : { - "address" : { - "type" : "string" - }, - "bouncing" : { - "type" : "boolean" - }, - "verified" : { - "type" : "boolean" - } - } - }, - "UserData" : { - "type" : "object", - "properties" : { - "partyId" : { - "type" : "integer", - "format" : "int64" - }, - "uuid" : { - "type" : "string" - }, - "name" : { - "type" : "string" - }, - "givenName" : { - "type" : "string" - }, - "familyName" : { - "type" : "string" - }, - "primaryEmailAddress" : { - "$ref" : "#/components/schemas/EmailAddressData" - }, - "emailAddresses" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/EmailAddressData" - } - }, - "banned" : { - "type" : "boolean" - }, - "passwordResetRequired" : { - "type" : "boolean" - }, - "groupMemberships" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/UserGroupMembership" - } - }, - "roleMemberships" : { - "type" : "array", - "items" : { - "$ref" : "#/components/schemas/PartyRoleMembership" - } - } - } - }, - "UserGroupMembership" : { - "type" : "object", - "properties" : { - "membershipId" : { - "type" : "integer", - "format" : "int64" - }, - "uuid" : { - "type" : "string" - }, - "group" : { - "$ref" : "#/components/schemas/PartyId" - } - } - }, - "ListViewUserData" : { + "ListViewRoleData" : { "type" : "object", "properties" : { "list" : { "type" : "array", "items" : { - "$ref" : "#/components/schemas/UserData" + "$ref" : "#/components/schemas/RoleData" } }, "count" : { @@ -2905,6 +2805,106 @@ "name" : "user", "namespace" : "http://core.libreccm.org" } + }, + "EmailAddressData" : { + "type" : "object", + "properties" : { + "address" : { + "type" : "string" + }, + "bouncing" : { + "type" : "boolean" + }, + "verified" : { + "type" : "boolean" + } + } + }, + "ListViewUserData" : { + "type" : "object", + "properties" : { + "list" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/UserData" + } + }, + "count" : { + "type" : "integer", + "format" : "int64" + }, + "limit" : { + "type" : "integer", + "format" : "int64" + }, + "offset" : { + "type" : "integer", + "format" : "int64" + } + } + }, + "UserData" : { + "type" : "object", + "properties" : { + "partyId" : { + "type" : "integer", + "format" : "int64" + }, + "uuid" : { + "type" : "string" + }, + "name" : { + "type" : "string" + }, + "givenName" : { + "type" : "string" + }, + "familyName" : { + "type" : "string" + }, + "primaryEmailAddress" : { + "$ref" : "#/components/schemas/EmailAddressData" + }, + "emailAddresses" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/EmailAddressData" + } + }, + "banned" : { + "type" : "boolean" + }, + "passwordResetRequired" : { + "type" : "boolean" + }, + "groupMemberships" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/UserGroupMembership" + } + }, + "roleMemberships" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/PartyRoleMembership" + } + } + } + }, + "UserGroupMembership" : { + "type" : "object", + "properties" : { + "membershipId" : { + "type" : "integer", + "format" : "int64" + }, + "uuid" : { + "type" : "string" + }, + "group" : { + "$ref" : "#/components/schemas/PartyId" + } + } } } }