diff --git a/LTS-CHANGELOG.adoc b/LTS-CHANGELOG.adoc index 14ac2e9b4d..2a3cacbc64 100644 --- a/LTS-CHANGELOG.adoc +++ b/LTS-CHANGELOG.adoc @@ -20,6 +20,8 @@ All fixes and changes in LTS releases will be released the next minor release. C [[v1.10.24]] == 1.10.24 (TBD) +icon:check[] REST: New endpoints have been added for retrieving referenced projects for schema/microschema. + icon:check[] REST: The documentation of the generic parameter `fields` has been fixed. Now `fields` works over the Language entities as well, the values are `uuid`,`name`,`languageTag`,`nativeName`. icon:check[] GraphQL. Some of (micro)schema fields related queries rely on the target (micro)schema having at least one field, crashing in HTTP 500 otherwise. This has now been fixed. diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/MicroschemaCrudHandler.java b/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/MicroschemaCrudHandler.java index 44c1ad2701..04519332e6 100644 --- a/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/MicroschemaCrudHandler.java +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/MicroschemaCrudHandler.java @@ -5,6 +5,7 @@ import static com.gentics.mesh.core.rest.error.Errors.error; import static com.gentics.mesh.rest.Messages.message; import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN; +import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; import static io.netty.handler.codec.http.HttpResponseStatus.NO_CONTENT; import static io.netty.handler.codec.http.HttpResponseStatus.OK; @@ -21,6 +22,9 @@ import com.gentics.mesh.core.data.dao.BranchDao; import com.gentics.mesh.core.data.dao.MicroschemaDao; import com.gentics.mesh.core.data.dao.UserDao; +import com.gentics.mesh.core.data.page.Page; +import com.gentics.mesh.core.data.page.PageTransformer; +import com.gentics.mesh.core.data.page.impl.DynamicStreamPageImpl; import com.gentics.mesh.core.data.project.HibProject; import com.gentics.mesh.core.data.schema.HibMicroschema; import com.gentics.mesh.core.data.schema.HibMicroschemaVersion; @@ -29,15 +33,19 @@ import com.gentics.mesh.core.db.Database; import com.gentics.mesh.core.endpoint.handler.AbstractCrudHandler; import com.gentics.mesh.core.rest.MeshEvent; +import com.gentics.mesh.core.rest.error.NotModifiedException; import com.gentics.mesh.core.rest.microschema.impl.MicroschemaModelImpl; import com.gentics.mesh.core.rest.microschema.impl.MicroschemaResponse; import com.gentics.mesh.core.rest.schema.MicroschemaModel; import com.gentics.mesh.core.rest.schema.change.impl.SchemaChangesListModel; +import com.gentics.mesh.core.result.Result; import com.gentics.mesh.core.verticle.handler.HandlerUtilities; import com.gentics.mesh.core.verticle.handler.WriteLock; import com.gentics.mesh.json.JsonUtil; +import com.gentics.mesh.parameter.PagingParameters; import com.gentics.mesh.parameter.SchemaUpdateParameters; import com.gentics.mesh.util.UUIDUtil; +import com.gentics.mesh.util.ValidationUtil; import dagger.Lazy; @@ -52,13 +60,16 @@ public class MicroschemaCrudHandler extends AbstractCrudHandler boot, HandlerUtilities utils, - WriteLock writeLock, ProjectMicroschemaLoadAllActionImpl projectMicroschemaLoadAllAction, MicroschemaDAOActions microschemaActions) { + WriteLock writeLock, ProjectMicroschemaLoadAllActionImpl projectMicroschemaLoadAllAction, MicroschemaDAOActions microschemaActions, PageTransformer pageTransformer) { super(db, utils, writeLock, microschemaActions); this.comparator = comparator; this.boot = boot; this.projectMicroschemaLoadAllAction = projectMicroschemaLoadAllAction; + this.pageTransformer = pageTransformer; } @Override @@ -251,4 +262,36 @@ public void handleRemoveMicroschemaFromProject(InternalActionContext ac, String } }, () -> ac.send(NO_CONTENT)); } + + /** + * Handle the request for the project, linked to the schema with the given UUID. + * + * @param ac + * @param microschemaUuid + */ + public void handleGetLinkedProjects(InternalActionContext ac, String microschemaUuid) { + validateParameter(microschemaUuid, "microschemaUuid"); + + PagingParameters pagingInfo = ac.getPagingParameters(); + ValidationUtil.validate(pagingInfo); + + utils.syncTx(ac, tx -> { + MicroschemaDao microschemaDao = tx.microschemaDao(); + UserDao userDao = tx.userDao(); + HibMicroschema microschema = microschemaDao.loadObjectByUuid(ac, microschemaUuid, READ_PERM); + + Result result = microschemaDao.findLinkedProjects(microschema); + Page page = new DynamicStreamPageImpl<>(result.stream().filter(p -> userDao.hasPermission(ac.getUser(), p, READ_PERM)), pagingInfo); + + // Handle etag + if (ac.getGenericParameters().getETag()) { + String etag = pageTransformer.getETag(page, ac); + ac.setEtag(etag, true); + if (ac.matches(etag, true)) { + throw new NotModifiedException(); + } + } + return pageTransformer.transformToRestSync(page, ac, 0); + }, m -> ac.send(m, OK)); + } } diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/MicroschemaEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/MicroschemaEndpoint.java index 8f4b0e2f1c..aa031f6c5e 100644 --- a/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/MicroschemaEndpoint.java +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/microschema/MicroschemaEndpoint.java @@ -22,9 +22,10 @@ import com.gentics.mesh.auth.MeshAuthChainImpl; import com.gentics.mesh.context.InternalActionContext; import com.gentics.mesh.core.db.Database; +import com.gentics.mesh.core.endpoint.RolePermissionHandlingEndpoint; import com.gentics.mesh.core.endpoint.admin.LocalConfigApi; import com.gentics.mesh.etc.config.MeshOptions; -import com.gentics.mesh.core.endpoint.RolePermissionHandlingEndpoint; +import com.gentics.mesh.parameter.impl.GenericParametersImpl; import com.gentics.mesh.parameter.impl.PagingParametersImpl; import com.gentics.mesh.parameter.impl.VersioningParametersImpl; import com.gentics.mesh.rest.InternalEndpointRoute; @@ -62,6 +63,7 @@ public void registerEndPoints() { addReadHandlers(); addUpdateHandler(); addDeleteHandler(); + addMiscHandlers(); addRolePermissionHandler("microschemaUuid", MICROSCHEMA_UUID, "microschema", crudHandler, false); } @@ -193,4 +195,25 @@ private void addCreateHandler() { crudHandler.handleCreate(wrap(rc)); }, isOrderedBlockingHandlers()); } + + private void addMiscHandlers() { + InternalEndpointRoute readOne = createRoute(); + readOne.path("/:microschemaUuid/projects"); + readOne.addUriParameter("microschemaUuid", "Uuid of the microschema.", MICROSCHEMA_UUID); + readOne.method(GET); + readOne.description("Load the projects, attached to the microschema with the given uuid."); + readOne.exampleResponse(OK, projectExamples.getProjectListResponse(), "Loaded projects."); + readOne.addQueryParameters(GenericParametersImpl.class); + readOne.addQueryParameters(PagingParametersImpl.class); + readOne.produces(APPLICATION_JSON); + readOne.blockingHandler(rc -> { + String uuid = rc.request().params().get("microschemaUuid"); + if (StringUtils.isEmpty(uuid)) { + rc.next(); + } else { + InternalActionContext ac = wrap(rc); + crudHandler.handleGetLinkedProjects(ac, uuid); + } + }, false); + } } diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/schema/SchemaCrudHandler.java b/core/src/main/java/com/gentics/mesh/core/endpoint/schema/SchemaCrudHandler.java index 81b3bb57bc..e5e679d280 100644 --- a/core/src/main/java/com/gentics/mesh/core/endpoint/schema/SchemaCrudHandler.java +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/schema/SchemaCrudHandler.java @@ -24,6 +24,9 @@ import com.gentics.mesh.core.data.dao.PersistingSchemaDao; import com.gentics.mesh.core.data.dao.SchemaDao; import com.gentics.mesh.core.data.dao.UserDao; +import com.gentics.mesh.core.data.page.Page; +import com.gentics.mesh.core.data.page.PageTransformer; +import com.gentics.mesh.core.data.page.impl.DynamicStreamPageImpl; import com.gentics.mesh.core.data.perm.InternalPermission; import com.gentics.mesh.core.data.project.HibProject; import com.gentics.mesh.core.data.schema.HibMicroschema; @@ -34,18 +37,22 @@ import com.gentics.mesh.core.db.Database; import com.gentics.mesh.core.endpoint.handler.AbstractCrudHandler; import com.gentics.mesh.core.rest.MeshEvent; +import com.gentics.mesh.core.rest.error.NotModifiedException; import com.gentics.mesh.core.rest.schema.FieldSchema; import com.gentics.mesh.core.rest.schema.MicronodeFieldSchema; import com.gentics.mesh.core.rest.schema.SchemaModel; import com.gentics.mesh.core.rest.schema.change.impl.SchemaChangesListModel; import com.gentics.mesh.core.rest.schema.impl.SchemaResponse; import com.gentics.mesh.core.rest.schema.impl.SchemaUpdateRequest; +import com.gentics.mesh.core.result.Result; import com.gentics.mesh.core.verticle.handler.HandlerUtilities; import com.gentics.mesh.core.verticle.handler.WriteLock; import com.gentics.mesh.json.JsonUtil; +import com.gentics.mesh.parameter.PagingParameters; import com.gentics.mesh.parameter.SchemaUpdateParameters; import com.gentics.mesh.search.index.node.NodeIndexHandlerImpl; import com.gentics.mesh.util.UUIDUtil; +import com.gentics.mesh.util.ValidationUtil; import dagger.Lazy; @@ -62,15 +69,18 @@ public class SchemaCrudHandler extends AbstractCrudHandler boot, HandlerUtilities utils, NodeIndexHandlerImpl nodeIndexHandler, WriteLock writeLock, ProjectSchemaLoadAllActionImpl projectSchemaDAOActions, - SchemaDAOActions schemaActions) { + SchemaDAOActions schemaActions, PageTransformer pageTransformer) { super(db, utils, writeLock, schemaActions); this.comparator = comparator; this.boot = boot; this.nodeIndexHandler = nodeIndexHandler; this.projectSchemaDAOActions = projectSchemaDAOActions; + this.pageTransformer = pageTransformer; } /** @@ -329,4 +339,35 @@ public void handleApplySchemaChanges(InternalActionContext ac, String schemaUuid } + /** + * Handle the request for the project, linked to the schema with the given UUID. + * + * @param ac + * @param schemaUuid + */ + public void handleGetLinkedProjects(InternalActionContext ac, String schemaUuid) { + validateParameter(schemaUuid, "schemaUuid"); + + PagingParameters pagingInfo = ac.getPagingParameters(); + ValidationUtil.validate(pagingInfo); + + utils.syncTx(ac, tx -> { + SchemaDao schemaDao = tx.schemaDao(); + UserDao userDao = tx.userDao(); + HibSchema schema = schemaDao.loadObjectByUuid(ac, schemaUuid, READ_PERM); + + Result result = schemaDao.findLinkedProjects(schema); + Page page = new DynamicStreamPageImpl<>(result.stream().filter(p -> userDao.hasPermission(ac.getUser(), p, READ_PERM)), pagingInfo); + + // Handle etag + if (ac.getGenericParameters().getETag()) { + String etag = pageTransformer.getETag(page, ac); + ac.setEtag(etag, true); + if (ac.matches(etag, true)) { + throw new NotModifiedException(); + } + } + return pageTransformer.transformToRestSync(page, ac, 0); + }, m -> ac.send(m, OK)); + } } diff --git a/core/src/main/java/com/gentics/mesh/core/endpoint/schema/SchemaEndpoint.java b/core/src/main/java/com/gentics/mesh/core/endpoint/schema/SchemaEndpoint.java index 75198ce6ff..5246dc823c 100644 --- a/core/src/main/java/com/gentics/mesh/core/endpoint/schema/SchemaEndpoint.java +++ b/core/src/main/java/com/gentics/mesh/core/endpoint/schema/SchemaEndpoint.java @@ -66,6 +66,7 @@ public void registerEndPoints() { addCreateHandler(); addUpdateHandler(); addDeleteHandler(); + addMiscHandlers(); addRolePermissionHandler("schemaUuid", SCHEMA_VEHICLE_UUID, "schema", crudHandler, false); } @@ -202,6 +203,26 @@ private void addReadHandlers() { InternalActionContext ac = wrap(rc); crudHandler.handleReadList(ac); }, false); + } + private void addMiscHandlers() { + InternalEndpointRoute readOne = createRoute(); + readOne.path("/:schemaUuid/projects"); + readOne.addUriParameter("schemaUuid", "Uuid of the schema.", SCHEMA_VEHICLE_UUID); + readOne.method(GET); + readOne.description("Load the projects, attached to the schema with the given uuid."); + readOne.exampleResponse(OK, projectExamples.getProjectListResponse(), "Loaded projects."); + readOne.addQueryParameters(GenericParametersImpl.class); + readOne.addQueryParameters(PagingParametersImpl.class); + readOne.produces(APPLICATION_JSON); + readOne.blockingHandler(rc -> { + String uuid = rc.request().params().get("schemaUuid"); + if (StringUtils.isEmpty(uuid)) { + rc.next(); + } else { + InternalActionContext ac = wrap(rc); + crudHandler.handleGetLinkedProjects(ac, uuid); + } + }, false); } } diff --git a/core/src/main/java/com/gentics/mesh/rest/MeshLocalClientImpl.java b/core/src/main/java/com/gentics/mesh/rest/MeshLocalClientImpl.java index c292f52230..fd7239ddde 100644 --- a/core/src/main/java/com/gentics/mesh/rest/MeshLocalClientImpl.java +++ b/core/src/main/java/com/gentics/mesh/rest/MeshLocalClientImpl.java @@ -528,6 +528,22 @@ public MeshRequest findSchemas(String projectName, Parameter return new MeshLocalRequestImpl<>(ac.getFuture()); } + @Override + public MeshRequest findSchemaProjects(String uuid, ParameterProvider... parameters) { + LocalActionContextImpl ac = createContext(ProjectListResponse.class, parameters); + ac.setParameter("schemaUuid", uuid); + schemaCrudHandler.handleGetLinkedProjects(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + + @Override + public MeshRequest findMicroschemaProjects(String uuid, ParameterProvider... parameters) { + LocalActionContextImpl ac = createContext(ProjectListResponse.class, parameters); + ac.setParameter("microschemaUuid", uuid); + microschemaCrudHandler.handleGetLinkedProjects(ac, uuid); + return new MeshLocalRequestImpl<>(ac.getFuture()); + } + @Override public MeshRequest assignMicroschemaToProject(String projectName, String microschemaUuid) { LocalActionContextImpl ac = createContext(MicroschemaResponse.class); diff --git a/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/ContainerDao.java b/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/ContainerDao.java index a034556e39..8f617c0d4e 100644 --- a/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/ContainerDao.java +++ b/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/ContainerDao.java @@ -191,4 +191,12 @@ public interface ContainerDao< * @param batch */ void unassign(SC schema, HibProject project, EventQueueBatch batch); + + /** + * Find all projects which reference the schema. + * + * @param schema + * @return + */ + Result findLinkedProjects(SC schema); } diff --git a/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/SchemaDao.java b/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/SchemaDao.java index 2b2e90c7db..ab59ee8f44 100644 --- a/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/SchemaDao.java +++ b/mdm/api/src/main/java/com/gentics/mesh/core/data/dao/SchemaDao.java @@ -103,14 +103,6 @@ default HibSchema create(SchemaVersionModel schema, HibUser creator) throws Mesh */ Result getNodes(HibSchema schema); - /** - * Find all projects which reference the schema. - * - * @param schema - * @return - */ - Result findLinkedProjects(HibSchema schema); - /** * Load all nodes, accessible in the given branch with Read Published permission. * diff --git a/mdm/common/src/main/java/com/gentics/mesh/core/data/dao/PersistingMicroschemaDao.java b/mdm/common/src/main/java/com/gentics/mesh/core/data/dao/PersistingMicroschemaDao.java index 4aaf365aa9..e9a9eb2203 100644 --- a/mdm/common/src/main/java/com/gentics/mesh/core/data/dao/PersistingMicroschemaDao.java +++ b/mdm/common/src/main/java/com/gentics/mesh/core/data/dao/PersistingMicroschemaDao.java @@ -92,12 +92,7 @@ default HibMicroschemaVersion fromReference(HibProject project, MicroschemaRefer return fromReference(project, reference, null); } - /** - * Find all projects which reference the schema. - * - * @param schema - * @return - */ + @Override default Result findLinkedProjects(HibMicroschema schema) { return new TraversalResult<>(Tx.get().projectDao() .findAll().stream().filter(project -> isLinkedToProject(schema, project))); diff --git a/mdm/common/src/main/java/com/gentics/mesh/core/data/dao/PersistingSchemaDao.java b/mdm/common/src/main/java/com/gentics/mesh/core/data/dao/PersistingSchemaDao.java index 329ad5bf9d..c88ade5ec3 100644 --- a/mdm/common/src/main/java/com/gentics/mesh/core/data/dao/PersistingSchemaDao.java +++ b/mdm/common/src/main/java/com/gentics/mesh/core/data/dao/PersistingSchemaDao.java @@ -223,12 +223,7 @@ default HibSchema create(SchemaVersionModel schema, HibUser creator, String uuid return mergeIntoPersisted(container); } - /** - * Find all projects which reference the schema. - * - * @param schema - * @return - */ + @Override default Result findLinkedProjects(HibSchema schema) { return new TraversalResult<>(Tx.get().projectDao() .findAll().stream().filter(project -> isLinkedToProject(schema, project))); diff --git a/mdm/common/src/main/java/com/gentics/mesh/core/migration/impl/MigrationStatusHandlerImpl.java b/mdm/common/src/main/java/com/gentics/mesh/core/migration/impl/MigrationStatusHandlerImpl.java index 1cfbd5b49b..7235d9d10b 100644 --- a/mdm/common/src/main/java/com/gentics/mesh/core/migration/impl/MigrationStatusHandlerImpl.java +++ b/mdm/common/src/main/java/com/gentics/mesh/core/migration/impl/MigrationStatusHandlerImpl.java @@ -18,8 +18,8 @@ import com.gentics.mesh.core.endpoint.migration.MigrationStatusHandler; import com.gentics.mesh.core.migration.MigrationAbortedException; import com.gentics.mesh.core.rest.job.JobStatus; - import com.gentics.mesh.core.rest.job.JobWarningList; + import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; @@ -32,7 +32,8 @@ public class MigrationStatusHandlerImpl implements MigrationStatusHandler { private MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - private HibBranchVersionAssignment versionEdge; + private Object versionEdgeId; + private Class versionEdgeClass; private long completionCount = 0; @@ -54,15 +55,16 @@ private MigrationStatusHandler commit(HibJob job) { if (status == null) { status = job.getStatus(); } - if (versionEdge != null) { - versionEdge = CommonTx.get().load(versionEdge.getId(), versionEdge.getClass()); - versionEdge.setMigrationStatus(status); + if (versionEdgeId != null && versionEdgeClass != null) { + HibBranchVersionAssignment versionEdge = CommonTx.get().load(versionEdgeId, versionEdgeClass); + if (versionEdge != null) { + versionEdge.setMigrationStatus(status); + } } job.setCompletionCount(completionCount); job.setStatus(status); - Database db = CommonTx.get().data().mesh().database(); - db.tx().commit(); + Tx.maybeGet().ifPresent(Tx::commit); return this; } @@ -135,7 +137,8 @@ public MigrationStatusHandler error(Throwable error, String failureMessage) { @Override public void setVersionEdge(HibBranchVersionAssignment versionEdge) { - this.versionEdge = versionEdge; + this.versionEdgeId = versionEdge.getId(); + this.versionEdgeClass = versionEdge.getClass(); } @Override diff --git a/mdm/orientdb-api/src/main/java/com/gentics/mesh/core/data/dao/MicroschemaDaoWrapper.java b/mdm/orientdb-api/src/main/java/com/gentics/mesh/core/data/dao/MicroschemaDaoWrapper.java index 013edce367..0a68fb05fc 100644 --- a/mdm/orientdb-api/src/main/java/com/gentics/mesh/core/data/dao/MicroschemaDaoWrapper.java +++ b/mdm/orientdb-api/src/main/java/com/gentics/mesh/core/data/dao/MicroschemaDaoWrapper.java @@ -1,10 +1,19 @@ package com.gentics.mesh.core.data.dao; +import com.gentics.mesh.core.data.root.MicroschemaRoot; import com.gentics.mesh.core.data.schema.HibMicroschema; +import com.gentics.mesh.core.result.Result; /** * DAO for {@link HibMicroschema} operations. */ public interface MicroschemaDaoWrapper extends PersistingMicroschemaDao { + /** + * Return a list of all microschema container roots to which the microschema container was added. + * + * @return + */ + Result getRoots(HibMicroschema schema); + } diff --git a/mdm/orientdb-api/src/main/java/com/gentics/mesh/core/data/root/MicroschemaRoot.java b/mdm/orientdb-api/src/main/java/com/gentics/mesh/core/data/root/MicroschemaRoot.java index ac7705e2fd..ae647128b1 100644 --- a/mdm/orientdb-api/src/main/java/com/gentics/mesh/core/data/root/MicroschemaRoot.java +++ b/mdm/orientdb-api/src/main/java/com/gentics/mesh/core/data/root/MicroschemaRoot.java @@ -1,7 +1,9 @@ package com.gentics.mesh.core.data.root; +import com.gentics.mesh.core.data.project.HibProject; import com.gentics.mesh.core.data.schema.HibMicroschema; import com.gentics.mesh.core.data.schema.Microschema; +import com.gentics.mesh.core.result.Result; import com.gentics.mesh.event.EventQueueBatch; /** @@ -24,4 +26,18 @@ public interface MicroschemaRoot extends RootVertex { * @return */ boolean contains(HibMicroschema microschema); + + /** + * Get the project. + * + * @return project + */ + HibProject getProject(); + + /** + * Return a list of all microschema container roots to which the microschema container was added. + * + * @return + */ + Result getRoots(Microschema schema); } diff --git a/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/dao/impl/MicroschemaDaoWrapperImpl.java b/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/dao/impl/MicroschemaDaoWrapperImpl.java index 2c89bf5a6a..f5179ed19d 100644 --- a/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/dao/impl/MicroschemaDaoWrapperImpl.java +++ b/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/dao/impl/MicroschemaDaoWrapperImpl.java @@ -3,6 +3,7 @@ import static com.gentics.mesh.core.data.util.HibClassConverter.toGraph; import java.util.Map; +import java.util.Objects; import java.util.function.Predicate; import java.util.stream.Stream; @@ -200,8 +201,12 @@ public HibMicroschemaVersion findVersionByUuid(HibMicroschema schema, String ver @Override public Result findLinkedProjects(HibMicroschema schema) { - return new TraversalResult<>(boot.get().meshRoot().getProjectRoot() - .findAll().stream().filter(project -> project.getMicroschemaContainerRoot().contains(schema))); + return new TraversalResult<>(getRoots(schema).stream().map(root -> root.getProject()).filter(Objects::nonNull)); + } + + @Override + public Result getRoots(HibMicroschema schema) { + return boot.get().meshRoot().getMicroschemaContainerRoot().getRoots(toGraph(schema)); } @Override diff --git a/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/dao/impl/SchemaDaoWrapperImpl.java b/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/dao/impl/SchemaDaoWrapperImpl.java index 92212bcadd..6ed9b2b5e3 100644 --- a/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/dao/impl/SchemaDaoWrapperImpl.java +++ b/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/dao/impl/SchemaDaoWrapperImpl.java @@ -146,7 +146,7 @@ public Result findDraftFieldContainers(HibSchem @Override public Result findLinkedProjects(HibSchema schema) { - return new TraversalResult<>(getRoots(schema).stream().map(root -> root.getProject())); + return new TraversalResult<>(getRoots(schema).stream().map(root -> root.getProject()).filter(Objects::nonNull)); } @Override diff --git a/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/root/impl/MicroschemaContainerRootImpl.java b/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/root/impl/MicroschemaContainerRootImpl.java index fc545dce62..72c18af046 100644 --- a/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/root/impl/MicroschemaContainerRootImpl.java +++ b/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/root/impl/MicroschemaContainerRootImpl.java @@ -1,5 +1,6 @@ package com.gentics.mesh.core.data.root.impl; +import static com.gentics.mesh.core.data.relationship.GraphRelationships.HAS_MICROSCHEMA_ROOT; import static com.gentics.mesh.core.data.relationship.GraphRelationships.HAS_SCHEMA_CONTAINER_ITEM; import static com.gentics.mesh.core.data.util.HibClassConverter.toGraph; import static com.gentics.mesh.madl.index.EdgeIndexDefinition.edgeIndex; @@ -12,9 +13,12 @@ import com.gentics.mesh.context.BulkActionContext; import com.gentics.mesh.core.data.container.impl.MicroschemaContainerImpl; import com.gentics.mesh.core.data.generic.MeshVertexImpl; +import com.gentics.mesh.core.data.impl.ProjectImpl; +import com.gentics.mesh.core.data.project.HibProject; import com.gentics.mesh.core.data.root.MicroschemaRoot; import com.gentics.mesh.core.data.schema.HibMicroschema; import com.gentics.mesh.core.data.schema.Microschema; +import com.gentics.mesh.core.result.Result; import com.gentics.mesh.event.EventQueueBatch; /** @@ -69,4 +73,14 @@ public boolean contains(HibMicroschema microschema) { public Microschema create() { return getGraph().addFramedVertex(MicroschemaContainerImpl.class); } + + @Override + public HibProject getProject() { + return in(HAS_MICROSCHEMA_ROOT).has(ProjectImpl.class).nextOrDefaultExplicit(ProjectImpl.class, null); + } + + @Override + public Result getRoots(Microschema microschema) { + return microschema.in(HAS_SCHEMA_CONTAINER_ITEM, MicroschemaContainerRootImpl.class); + } } diff --git a/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/root/impl/ProjectMicroschemaContainerRootImpl.java b/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/root/impl/ProjectMicroschemaContainerRootImpl.java index 18b59cc74c..054e833a0a 100644 --- a/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/root/impl/ProjectMicroschemaContainerRootImpl.java +++ b/mdm/orientdb-wrapper/src/main/java/com/gentics/mesh/core/data/root/impl/ProjectMicroschemaContainerRootImpl.java @@ -1,12 +1,8 @@ package com.gentics.mesh.core.data.root.impl; -import static com.gentics.mesh.core.data.relationship.GraphRelationships.HAS_MICROSCHEMA_ROOT; - import com.gentics.madl.index.IndexHandler; import com.gentics.madl.type.TypeHandler; import com.gentics.mesh.core.data.generic.MeshVertexImpl; -import com.gentics.mesh.core.data.impl.ProjectImpl; -import com.gentics.mesh.core.data.project.HibProject; /** * Project specific implementation of microschema container root. @@ -22,13 +18,4 @@ public class ProjectMicroschemaContainerRootImpl extends MicroschemaContainerRoo public static void init(TypeHandler type, IndexHandler index) { type.createVertexType(ProjectMicroschemaContainerRootImpl.class, MeshVertexImpl.class); } - - /** - * Get the project. - * - * @return project - */ - protected HibProject getProject() { - return in(HAS_MICROSCHEMA_ROOT).has(ProjectImpl.class).nextOrDefaultExplicit(ProjectImpl.class, null); - } } diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/MeshRestHttpClientImpl.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/MeshRestHttpClientImpl.java index c141ef78ab..ebc252c8b7 100644 --- a/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/MeshRestHttpClientImpl.java +++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/impl/MeshRestHttpClientImpl.java @@ -401,6 +401,18 @@ public MeshRequest findSchemas(String projectName, Parameter return prepareRequest(GET, "/" + encodeSegment(projectName) + "/schemas" + getQuery(parameters), SchemaListResponse.class); } + @Override + public MeshRequest findSchemaProjects(String schemaUuid, ParameterProvider... parameters) { + Objects.requireNonNull(schemaUuid, "schemaUuid must not be null"); + return prepareRequest(GET, "/schemas/" + schemaUuid + "/projects" + getQuery(parameters), ProjectListResponse.class); + } + + @Override + public MeshRequest findMicroschemaProjects(String microschemaUuid, ParameterProvider... parameters) { + Objects.requireNonNull(microschemaUuid, "microschemaUuid must not be null"); + return prepareRequest(GET, "/microschemas/" + microschemaUuid + "/projects" + getQuery(parameters), ProjectListResponse.class); + } + @Override public MeshRequest assignMicroschemaToProject(String projectName, String microschemaUuid) { Objects.requireNonNull(projectName, "projectName must not be null"); diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/MicroschemaClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/MicroschemaClientMethods.java index 08e95c87cc..8d48fb2107 100644 --- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/MicroschemaClientMethods.java +++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/MicroschemaClientMethods.java @@ -7,6 +7,8 @@ import com.gentics.mesh.core.rest.microschema.impl.MicroschemaCreateRequest; import com.gentics.mesh.core.rest.microschema.impl.MicroschemaResponse; import com.gentics.mesh.core.rest.microschema.impl.MicroschemaUpdateRequest; +import com.gentics.mesh.core.rest.project.ProjectListResponse; +import com.gentics.mesh.core.rest.schema.MicroschemaListResponse; import com.gentics.mesh.core.rest.schema.MicroschemaModel; import com.gentics.mesh.core.rest.schema.change.impl.SchemaChangesListModel; import com.gentics.mesh.parameter.ParameterProvider; @@ -109,4 +111,46 @@ public interface MicroschemaClientMethods { * @return mesh request */ MeshRequest revokeMicroschemaRolePermissions(String uuid, ObjectPermissionRevokeRequest request); + + /** + * Assign a microschema to the project + * + * @param projectName + * project name + * @param microschemaUuid + * microschema uuid + * @return + */ + MeshRequest assignMicroschemaToProject(String projectName, String microschemaUuid); + + /** + * Unassign a microschema from the project + * + * @param projectName + * project name + * @param microschemaUuid + * microschema uuid + * @return + */ + MeshRequest unassignMicroschemaFromProject(String projectName, String microschemaUuid); + + /** + * Find all microschemas assigned to the project + * + * @param projectName + * project name + * @param parameters + * @return + */ + MeshRequest findMicroschemas(String projectName, ParameterProvider... parameters); + + /** + * Find all projects assigned to the microschema + * + * @param uuid + * microschema UUID + * @param parameters + * @return + */ + MeshRequest findMicroschemaProjects(String uuid, ParameterProvider... parameters); } diff --git a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/SchemaClientMethods.java b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/SchemaClientMethods.java index 50519357e2..b08b444ee2 100644 --- a/rest-client/src/main/java/com/gentics/mesh/rest/client/method/SchemaClientMethods.java +++ b/rest-client/src/main/java/com/gentics/mesh/rest/client/method/SchemaClientMethods.java @@ -4,7 +4,7 @@ import com.gentics.mesh.core.rest.common.ObjectPermissionGrantRequest; import com.gentics.mesh.core.rest.common.ObjectPermissionResponse; import com.gentics.mesh.core.rest.common.ObjectPermissionRevokeRequest; -import com.gentics.mesh.core.rest.microschema.impl.MicroschemaResponse; +import com.gentics.mesh.core.rest.project.ProjectListResponse; import com.gentics.mesh.core.rest.schema.MicroschemaListResponse; import com.gentics.mesh.core.rest.schema.SchemaListResponse; import com.gentics.mesh.core.rest.schema.SchemaModel; @@ -142,36 +142,14 @@ public interface SchemaClientMethods { MeshRequest findSchemas(String projectName, ParameterProvider... parameters); /** - * Assign a microschema to the project + * Find all projects assigned to the schema * - * @param projectName - * project name - * @param microschemaUuid - * microschema uuid - * @return - */ - MeshRequest assignMicroschemaToProject(String projectName, String microschemaUuid); - - /** - * Unassign a microschema from the project - * - * @param projectName - * project name - * @param microschemaUuid - * microschema uuid - * @return - */ - MeshRequest unassignMicroschemaFromProject(String projectName, String microschemaUuid); - - /** - * Find all microschemas assigned to the project - * - * @param projectName - * project name + * @param uuid + * schema UUID * @param parameters * @return */ - MeshRequest findMicroschemas(String projectName, ParameterProvider... parameters); + MeshRequest findSchemaProjects(String uuid, ParameterProvider... parameters); /** * Get the role permissions on the schema diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/core/schema/MicroschemaEndpointTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/core/schema/MicroschemaEndpointTest.java index 09bcbd3c87..1bff027503 100644 --- a/tests/tests-core/src/main/java/com/gentics/mesh/core/schema/MicroschemaEndpointTest.java +++ b/tests/tests-core/src/main/java/com/gentics/mesh/core/schema/MicroschemaEndpointTest.java @@ -20,9 +20,11 @@ import static io.netty.handler.codec.http.HttpResponseStatus.CONFLICT; import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN; import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.junit.Ignore; @@ -42,6 +44,9 @@ import com.gentics.mesh.core.rest.node.NodeCreateRequest; import com.gentics.mesh.core.rest.node.NodeResponse; import com.gentics.mesh.core.rest.node.field.list.impl.MicronodeFieldListImpl; +import com.gentics.mesh.core.rest.project.ProjectCreateRequest; +import com.gentics.mesh.core.rest.project.ProjectListResponse; +import com.gentics.mesh.core.rest.project.ProjectResponse; import com.gentics.mesh.core.rest.schema.ListFieldSchema; import com.gentics.mesh.core.rest.schema.MicroschemaModel; import com.gentics.mesh.core.rest.schema.impl.MicroschemaReferenceImpl; @@ -49,6 +54,7 @@ import com.gentics.mesh.core.rest.schema.impl.SchemaReferenceImpl; import com.gentics.mesh.core.rest.schema.impl.SchemaResponse; import com.gentics.mesh.json.JsonUtil; +import com.gentics.mesh.parameter.impl.PagingParametersImpl; import com.gentics.mesh.parameter.impl.RolePermissionParametersImpl; import com.gentics.mesh.parameter.impl.VersioningParametersImpl; import com.gentics.mesh.test.MeshTestSetting; @@ -502,4 +508,91 @@ public void testConflictingNameWithSchema() throws InterruptedException { client().createSchema(schemaRequest).blockingAwait(); call(() -> client().createMicroschema(microSchemaRequest), CONFLICT, "schema_conflicting_name", "test"); } + + @Test + public void testReadAssignedProjects() { + String microschemaUuid = tx(tx -> { + return microschemaContainer("vcard").getUuid(); + }); + ProjectListResponse projects = call(() -> client().findMicroschemaProjects(microschemaUuid)); + assertNotNull(projects.getData()); + assertThat(projects.getData()).hasSize(1); + } + + @Test + public void testReadAssignedProjectsFalseMicroschema() { + call(() -> client().findMicroschemaProjects("bogus"), NOT_FOUND, "object_not_found_for_uuid", "bogus"); + } + + @Test + public void testReadJustAssignedProject() { + String microschemaUuid = tx(tx -> { + return microschemaContainer("vcard").getUuid(); + }); + ProjectListResponse projects = client().createProject(new ProjectCreateRequest().setSchemaRef("folder").setName("MicroschemaAssignmentTest")).toSingle() + .flatMap(project -> client().assignMicroschemaToProject(project.getName(), microschemaUuid).toSingle()) + .flatMap(unused -> client().findMicroschemaProjects(microschemaUuid).toSingle()) + .blockingGet(); + assertNotNull(projects.getData()); + assertThat(projects.getData().stream().map(ProjectResponse::getName)).contains("MicroschemaAssignmentTest"); + } + + @Test + public void testReadJustUnassignedProject() { + testReadJustAssignedProject(); + + String microschemaUuid = tx(tx -> { + return microschemaContainer("vcard").getUuid(); + }); + ProjectListResponse projects = client().unassignMicroschemaFromProject("MicroschemaAssignmentTest", microschemaUuid).toSingle() + .flatMap(unused -> client().findMicroschemaProjects(microschemaUuid).toSingle()) + .blockingGet(); + assertNotNull(projects.getData()); + assertThat(projects.getData().stream().map(ProjectResponse::getName)).doesNotContain("MicroschemaAssignmentTest"); + } + + @Test + public void testReadNotPermittedProject() { + testReadJustAssignedProject(); + + String microschemaUuid = tx(tx -> { + assertTrue(tx.roleDao().revokePermissions(role(), tx.projectDao().findByName("MicroschemaAssignmentTest"), READ_PERM)); + String uuid = microschemaContainer("vcard").getUuid(); + tx.success(); + return uuid; + }); + ProjectListResponse projects = call(() -> client().findMicroschemaProjects(microschemaUuid)); + assertNotNull(projects.getData()); + assertThat(projects.getData().stream().map(ProjectResponse::getName)).doesNotContain("MicroschemaAssignmentTest"); + } + + @Test + public void testReadProjectsOfNotPermittedMicroschema() { + testReadJustAssignedProject(); + + String microschemaUuid = tx(tx -> { + HibMicroschema microschema = microschemaContainer("vcard"); + assertTrue(tx.roleDao().revokePermissions(role(), microschema, READ_PERM)); + String uuid = microschema.getUuid(); + tx.success(); + return uuid; + }); + call(() -> client().findMicroschemaProjects(microschemaUuid), FORBIDDEN, "error_missing_perm", microschemaUuid, "read"); + } + + @Test + public void testReadPagedProjects() { + String microschemaUuid = tx(tx -> { + return microschemaContainer("vcard").getUuid(); + }); + Observable.range(0, 7) + .flatMapSingle(index -> client().createProject(new ProjectCreateRequest().setSchemaRef("folder").setName("MicroschemaAssignmentPagingTest" + index)).toSingle()) + .flatMapSingle(project -> client().assignMicroschemaToProject(project.getName(), microschemaUuid).toSingle()) + .ignoreElements() + .blockingAwait(); + + ProjectListResponse projects = call(() -> client().findMicroschemaProjects(microschemaUuid, new PagingParametersImpl(2, 5L))); + assertNotNull(projects.getData()); + assertThat(projects.getData()).hasSize(3); + } } diff --git a/tests/tests-core/src/main/java/com/gentics/mesh/core/schema/SchemaEndpointTest.java b/tests/tests-core/src/main/java/com/gentics/mesh/core/schema/SchemaEndpointTest.java index c739661714..c17584987a 100644 --- a/tests/tests-core/src/main/java/com/gentics/mesh/core/schema/SchemaEndpointTest.java +++ b/tests/tests-core/src/main/java/com/gentics/mesh/core/schema/SchemaEndpointTest.java @@ -41,6 +41,7 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.IntStream; import org.junit.After; import org.junit.Ignore; @@ -52,6 +53,7 @@ import com.gentics.mesh.core.data.dao.RoleDao; import com.gentics.mesh.core.data.dao.SchemaDao; import com.gentics.mesh.core.data.node.HibNode; +import com.gentics.mesh.core.data.schema.HibMicroschema; import com.gentics.mesh.core.data.schema.HibSchema; import com.gentics.mesh.core.data.schema.HibSchemaVersion; import com.gentics.mesh.core.db.CommonTx; @@ -70,7 +72,10 @@ import com.gentics.mesh.core.rest.job.JobStatus; import com.gentics.mesh.core.rest.microschema.impl.MicroschemaCreateRequest; import com.gentics.mesh.core.rest.microschema.impl.MicroschemaResponse; +import com.gentics.mesh.core.rest.project.ProjectCreateRequest; +import com.gentics.mesh.core.rest.project.ProjectListResponse; import com.gentics.mesh.core.rest.project.ProjectReference; +import com.gentics.mesh.core.rest.project.ProjectResponse; import com.gentics.mesh.core.rest.schema.MicroschemaReference; import com.gentics.mesh.core.rest.schema.SchemaListResponse; import com.gentics.mesh.core.rest.schema.SchemaModel; @@ -305,6 +310,93 @@ public void testReadByUUID() throws Exception { } } + @Test + public void testReadAssignedProjects() { + String schemaUuid = tx(tx -> { + return schemaContainer("content").getUuid(); + }); + ProjectListResponse projects = call(() -> client().findSchemaProjects(schemaUuid)); + assertNotNull(projects.getData()); + assertThat(projects.getData()).hasSize(1); + } + + @Test + public void testReadAssignedProjectsFalseSchema() { + call(() -> client().findSchemaProjects("bogus"), NOT_FOUND, "object_not_found_for_uuid", "bogus"); + } + + @Test + public void testReadJustAssignedProject() { + String schemaUuid = tx(tx -> { + return schemaContainer("content").getUuid(); + }); + ProjectListResponse projects = client().createProject(new ProjectCreateRequest().setSchemaRef("folder").setName("SchemaAssignmentTest")).toSingle() + .flatMap(project -> client().assignSchemaToProject(project.getName(), schemaUuid).toSingle()) + .flatMap(unused -> client().findSchemaProjects(schemaUuid).toSingle()) + .blockingGet(); + assertNotNull(projects.getData()); + assertThat(projects.getData().stream().map(ProjectResponse::getName)).contains("SchemaAssignmentTest"); + } + + @Test + public void testReadPagedProjects() { + String schemaUuid = tx(tx -> { + return schemaContainer("content").getUuid(); + }); + Observable.range(0, 7) + .flatMapSingle(index -> client().createProject(new ProjectCreateRequest().setSchemaRef("folder").setName("SchemaAssignmentPagingTest" + index)).toSingle()) + .flatMapSingle(project -> client().assignSchemaToProject(project.getName(), schemaUuid).toSingle()) + .ignoreElements() + .blockingAwait(); + + ProjectListResponse projects = call(() -> client().findSchemaProjects(schemaUuid, new PagingParametersImpl(2, 5L))); + assertNotNull(projects.getData()); + assertThat(projects.getData()).hasSize(3); + } + + @Test + public void testReadJustUnassignedProject() { + testReadJustAssignedProject(); + + String schemaUuid = tx(tx -> { + return schemaContainer("content").getUuid(); + }); + ProjectListResponse projects = client().unassignSchemaFromProject("SchemaAssignmentTest", schemaUuid).toSingle() + .flatMap(unused -> client().findSchemaProjects(schemaUuid).toSingle()) + .blockingGet(); + assertNotNull(projects.getData()); + assertThat(projects.getData().stream().map(ProjectResponse::getName)).doesNotContain("SchemaAssignmentTest"); + } + + @Test + public void testReadNotPermittedProject() { + testReadJustAssignedProject(); + + String schemaUuid = tx(tx -> { + assertTrue(tx.roleDao().revokePermissions(role(), tx.projectDao().findByName("SchemaAssignmentTest"), READ_PERM)); + String uuid = schemaContainer("content").getUuid(); + tx.success(); + return uuid; + }); + ProjectListResponse projects = call(() -> client().findSchemaProjects(schemaUuid)); + assertNotNull(projects.getData()); + assertThat(projects.getData().stream().map(ProjectResponse::getName)).doesNotContain("SchemaAssignmentTest"); + } + + @Test + public void testReadProjectsOfNotPermittedSchema() { + testReadJustAssignedProject(); + + String schemaUuid = tx(tx -> { + HibSchema schema = schemaContainer("content"); + assertTrue(tx.roleDao().revokePermissions(role(), schema, READ_PERM)); + String uuid = schema.getUuid(); + tx.success(); + return uuid; + }); + call(() -> client().findSchemaProjects(schemaUuid), FORBIDDEN, "error_missing_perm", schemaUuid, "read"); + } + @Test public void testReadVersion() { String uuid = tx(() -> schemaContainer("content").getUuid());