This is an automated email from the ASF dual-hosted git repository. dklco pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-app-cms.git
commit a9fdada31e4f6596f6cb81ecb57f551267aa88c1 Author: Dan Klco <[email protected]> AuthorDate: Tue Jul 17 16:11:11 2018 -0400 Adding support for User Generated Content --- builder/src/main/provisioning/cms.txt | 16 ++ .../java/org/apache/sling/cms/CMSConstants.java | 5 + .../cms/core/usergenerated/UGCBucketConfig.java | 87 +++++++++++ .../usergenerated/UserGeneratedContentService.java | 53 +++++++ .../usergenerated/impl/ApproveUGCOperation.java | 119 +++++++++++++++ .../impl/UserGeneratedContentConfig.java | 35 +++++ .../impl/UserGeneratedContentServiceImpl.java | 123 +++++++++++++++ .../main/resources/OSGI-INF/l10n/bundle.properties | 16 +- pom.xml | 18 +-- .../resources/SLING-INF/nodetypes/nodetypes.cnd | 11 ++ .../cms/suffixproperty/suffixproperty.jsp | 25 +++ .../jcr_root/libs/sling-cms/content/start.json | 10 ++ .../sling-cms/content/usergenerated/content.json | 168 +++++++++++++++++++++ .../sling-cms/content/usergenerated/review.json | 83 ++++++++++ 14 files changed, 759 insertions(+), 10 deletions(-) diff --git a/builder/src/main/provisioning/cms.txt b/builder/src/main/provisioning/cms.txt index ca71f22..757b336 100644 --- a/builder/src/main/provisioning/cms.txt +++ b/builder/src/main/provisioning/cms.txt @@ -32,9 +32,25 @@ set ACL for sling-rewriter allow jcr:read on / end + + create path (sling:OrderedFolder) /etc/usergenerated + set ACL for everyone + allow jcr:read on /etc/usergenerated + end + + # sling-ugc + create service user sling-ugc + + set ACL for sling-ugc + allow jcr:all on /etc/usergenerated + end [configurations] org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-sling.rewriter user.mapping=[ "org.apache.sling.rewriter\=sling-rewriter" + ] + org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-sling.ugc + user.mapping=[ + "org.apache.sling.cms.core:sling-ugc\=sling-ugc" ] \ No newline at end of file diff --git a/core/src/main/java/org/apache/sling/cms/CMSConstants.java b/core/src/main/java/org/apache/sling/cms/CMSConstants.java index 3a77cef..dc62676 100644 --- a/core/src/main/java/org/apache/sling/cms/CMSConstants.java +++ b/core/src/main/java/org/apache/sling/cms/CMSConstants.java @@ -62,6 +62,11 @@ public class CMSConstants { public static final String NT_SITE = NAMESPACE + ":Site"; /** + * User Generated Content node type. + */ + public static final String NT_UGC = NAMESPACE + ":UGC"; + + /** * Description attribute name */ public static final String PN_DESCRIPTION = "jcr:description"; diff --git a/core/src/main/java/org/apache/sling/cms/core/usergenerated/UGCBucketConfig.java b/core/src/main/java/org/apache/sling/cms/core/usergenerated/UGCBucketConfig.java new file mode 100644 index 0000000..1b3e962 --- /dev/null +++ b/core/src/main/java/org/apache/sling/cms/core/usergenerated/UGCBucketConfig.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sling.cms.core.usergenerated; + +import org.apache.sling.cms.core.usergenerated.UserGeneratedContentService.APPROVE_ACTION; +import org.apache.sling.cms.core.usergenerated.UserGeneratedContentService.CONTENT_TYPE; + +/* + * Simple POJO for providing the required data for a UGC bucket + */ +public class UGCBucketConfig { + + private CONTENT_TYPE contentType; + private int pathDepth = -1; + private String bucket; + private APPROVE_ACTION action; + + /** + * @return the contentType + */ + public CONTENT_TYPE getContentType() { + return contentType; + } + + /** + * @param contentType the contentType to set + */ + public void setContentType(CONTENT_TYPE contentType) { + this.contentType = contentType; + } + + /** + * @return the pathDepth + */ + public int getPathDepth() { + return pathDepth; + } + + /** + * @param pathDepth the pathDepth to set + */ + public void setPathDepth(int pathDepth) { + this.pathDepth = pathDepth; + } + + /** + * @return the bucket + */ + public String getBucket() { + return bucket; + } + + /** + * @param bucket the bucket to set + */ + public void setBucket(String bucket) { + this.bucket = bucket; + } + + /** + * @return the action + */ + public APPROVE_ACTION getAction() { + return action; + } + + /** + * @param action the action to set + */ + public void setAction(APPROVE_ACTION action) { + this.action = action; + } +} diff --git a/core/src/main/java/org/apache/sling/cms/core/usergenerated/UserGeneratedContentService.java b/core/src/main/java/org/apache/sling/cms/core/usergenerated/UserGeneratedContentService.java new file mode 100644 index 0000000..062ebe9 --- /dev/null +++ b/core/src/main/java/org/apache/sling/cms/core/usergenerated/UserGeneratedContentService.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sling.cms.core.usergenerated; + +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.Resource; + +/** + * Service for creating User Generated Content + */ +public interface UserGeneratedContentService { + + public enum APPROVE_ACTION { + move, publish + } + + enum CONTENT_TYPE { + comment, forum_post, reply, blog_post, contact_form, signup, message, other + }; + + /** + * Creates a new container for adding user generated content which should be + * published when approvated. The UGC content should be added as a child of this + * container. + * + * @param request the request for which this was initiated + * @param bucketConfig the configuration for the UGC bucket + * @param preview the preview of the UGC to be displayed to the approving + * user + * @param targetPath the path to which to move the content if this should be + * moved when approved, may be null + * @return the new UGC Container + * @throws PersistenceException an exception occurs creating the UGC Container + */ + Resource createUGCContainer(SlingHttpServletRequest request, UGCBucketConfig bucketConfig, String preview, + String targetPath) throws PersistenceException; + +} diff --git a/core/src/main/java/org/apache/sling/cms/core/usergenerated/impl/ApproveUGCOperation.java b/core/src/main/java/org/apache/sling/cms/core/usergenerated/impl/ApproveUGCOperation.java new file mode 100644 index 0000000..975c63c --- /dev/null +++ b/core/src/main/java/org/apache/sling/cms/core/usergenerated/impl/ApproveUGCOperation.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sling.cms.core.usergenerated.impl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.jackrabbit.JcrConstants; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.ModifiableValueMap; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceUtil; +import org.apache.sling.cms.core.usergenerated.UserGeneratedContentService.APPROVE_ACTION; +import org.apache.sling.jcr.resource.JcrResourceConstants; +import org.apache.sling.servlets.post.Modification; +import org.apache.sling.servlets.post.PostOperation; +import org.apache.sling.servlets.post.PostResponse; +import org.apache.sling.servlets.post.SlingPostProcessor; +import org.osgi.service.component.annotations.Component; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The <code>ApproveUGCOperation</code> class will approve a piece of UGC, + * moving or publishing it as appropriate + */ +@Component(immediate = true, service = { PostOperation.class }, property = PostOperation.PROP_OPERATION_NAME + + "=ugcapprove") +public class ApproveUGCOperation implements PostOperation { + + private static final Logger log = LoggerFactory.getLogger(ApproveUGCOperation.class); + + @Override + public void run(SlingHttpServletRequest request, PostResponse response, SlingPostProcessor[] processors) { + + log.trace("run"); + + try { + // calculate the paths + String path = request.getResource().getPath(); + response.setPath(path); + + log.debug("Approving UGC {}", path); + + final List<Modification> changes = new ArrayList<>(); + // perform the approval + String targetPath = request.getResource().getValueMap().get("targetpath", String.class); + APPROVE_ACTION action = APPROVE_ACTION + .valueOf(request.getResource().getValueMap().get("approveaction", String.class)); + if (action == APPROVE_ACTION.move) { + ResourceUtil.getOrCreateResource(request.getResourceResolver(), targetPath, new HashMap<String, Object>() { + private static final long serialVersionUID = 1L; + { + put(JcrConstants.JCR_PRIMARYTYPE, JcrResourceConstants.NT_SLING_FOLDER); + } + }, JcrResourceConstants.NT_SLING_FOLDER, false); + for (Resource resource : request.getResource().getChildren()) { + log.debug("Moving {} to {}", resource.getPath(), targetPath); + changes.add(Modification.onMoved(resource.getPath(), targetPath)); + request.getResourceResolver().move(resource.getPath(), targetPath); + } + changes.add(Modification.onDeleted(request.getResource().getPath())); + request.getResourceResolver().delete(request.getResource()); + } else { + ModifiableValueMap mvm = request.getResource().adaptTo(ModifiableValueMap.class); + mvm.put("published", true); + changes.add(Modification.onModified(request.getResource().getPath())); + } + + // invoke processors + if (processors != null) { + for (SlingPostProcessor processor : processors) { + processor.process(request, changes); + } + } + + // check modifications for remaining postfix and store the base path + final Map<String, String> modificationSourcesContainingPostfix = new HashMap<>(); + final Set<String> allModificationSources = new HashSet<>(changes.size()); + for (final Modification modification : changes) { + final String source = modification.getSource(); + if (source != null) { + allModificationSources.add(source); + final int atIndex = source.indexOf('@'); + if (atIndex > 0) { + modificationSourcesContainingPostfix.put(source.substring(0, atIndex), source); + } + } + } + request.getResourceResolver().commit(); + + } catch ( + + Exception e) { + log.error("Exception during response processing.", e); + response.setError(e); + + } + } +} diff --git a/core/src/main/java/org/apache/sling/cms/core/usergenerated/impl/UserGeneratedContentConfig.java b/core/src/main/java/org/apache/sling/cms/core/usergenerated/impl/UserGeneratedContentConfig.java new file mode 100644 index 0000000..049ce6d --- /dev/null +++ b/core/src/main/java/org/apache/sling/cms/core/usergenerated/impl/UserGeneratedContentConfig.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sling.cms.core.usergenerated.impl; + +import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.AttributeType; + +/** + * Configuration for the User Generated Content handling service + */ +@ObjectClassDefinition(name = "%ugc.name", description = "%ugc.description", localization = "OSGI-INF/l10n/bundle") +public @interface UserGeneratedContentConfig { + + @AttributeDefinition(name = "%ugcRoot.name", description = "%ugcRoot.description", defaultValue = "/etc/usergenerated") + String ugcRoot(); + + @AttributeDefinition(name = "%defaultPathDepth.name", description = "%defaultPathDepth.description", type = AttributeType.INTEGER) + int defaultPathDepth() default 1; + +} diff --git a/core/src/main/java/org/apache/sling/cms/core/usergenerated/impl/UserGeneratedContentServiceImpl.java b/core/src/main/java/org/apache/sling/cms/core/usergenerated/impl/UserGeneratedContentServiceImpl.java new file mode 100644 index 0000000..f0be9c3 --- /dev/null +++ b/core/src/main/java/org/apache/sling/cms/core/usergenerated/impl/UserGeneratedContentServiceImpl.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sling.cms.core.usergenerated.impl; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.lang.StringUtils; +import org.apache.jackrabbit.JcrConstants; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.LoginException; +import org.apache.sling.api.resource.PersistenceException; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.ResourceResolverFactory; +import org.apache.sling.api.resource.ResourceUtil; +import org.apache.sling.cms.CMSConstants; +import org.apache.sling.cms.core.usergenerated.UGCBucketConfig; +import org.apache.sling.cms.core.usergenerated.UserGeneratedContentService; +import org.apache.sling.jcr.resource.JcrResourceConstants; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Component(service = UserGeneratedContentService.class) +@Designate(ocd = UserGeneratedContentConfig.class) +public class UserGeneratedContentServiceImpl implements UserGeneratedContentService { + + private static final Logger log = LoggerFactory.getLogger(UserGeneratedContentServiceImpl.class); + + @Reference + private ResourceResolverFactory factory; + private UserGeneratedContentConfig config; + + private ResourceResolver serviceResolver; + + @Activate + public void activate(UserGeneratedContentConfig config) throws LoginException { + this.config = config; + + log.debug("Connecting with service user"); + Map<String, Object> serviceParams = new HashMap<String, Object>(); + serviceParams.put(ResourceResolverFactory.SUBSERVICE, "sling-ugc"); + serviceResolver = factory.getServiceResourceResolver(serviceParams); + } + + @Deactivate + public void deactivate() { + if (serviceResolver != null) { + serviceResolver.close(); + } + } + + @Override + public Resource createUGCContainer(SlingHttpServletRequest request, UGCBucketConfig bucketConfig, String preview, + String targetPath) throws PersistenceException { + + serviceResolver.refresh(); + + Resource resource = null; + + log.debug("Creating content of type {} in bucket {}", bucketConfig.getContentType().toString(), + bucketConfig.getBucket()); + Map<String, Object> resourceProperties = new HashMap<String, Object>(); + resourceProperties.put(JcrConstants.JCR_PRIMARYTYPE, CMSConstants.NT_UGC); + resourceProperties.put("approveaction", bucketConfig.getAction().toString()); + resourceProperties.put("contenttype", bucketConfig.getContentType().toString()); + resourceProperties.put("preview", preview); + resourceProperties.put("published", false); + resourceProperties.put("referrer", request.getHeader("referer")); + if (StringUtils.isNotBlank(targetPath)) { + resourceProperties.put("targetpath", targetPath); + } + resourceProperties.put("user", request.getResourceResolver().getUserID()); + resourceProperties.put("useragent", request.getHeader("User-Agent")); + resourceProperties.put("userip", request.getRemoteAddr()); + + String contentPath = generatePath(bucketConfig); + log.debug("Creating article contents {}", contentPath); + resource = ResourceUtil.getOrCreateResource(serviceResolver, contentPath, resourceProperties, + JcrResourceConstants.NT_SLING_ORDERED_FOLDER, true); + + return resource; + } + + private String generatePath(UGCBucketConfig bucketConfig) { + String uuid = UUID.randomUUID().toString(); + int depth = bucketConfig.getPathDepth(); + if (depth == -1) { + depth = config.defaultPathDepth(); + } + String[] pathSegments = new String[depth]; + for (int i = 0; i < pathSegments.length; i++) { + pathSegments[i] = String.valueOf(uuid.charAt(i)); + } + if (pathSegments.length > 0) { + return config.ugcRoot() + "/" + bucketConfig.getBucket() + "/" + StringUtils.join(pathSegments, "/") + "/" + + uuid; + } else { + return config.ugcRoot() + "/" + bucketConfig.getBucket() + "/" + uuid; + } + } + +} diff --git a/core/src/main/resources/OSGI-INF/l10n/bundle.properties b/core/src/main/resources/OSGI-INF/l10n/bundle.properties index c35d1be..29359f2 100644 --- a/core/src/main/resources/OSGI-INF/l10n/bundle.properties +++ b/core/src/main/resources/OSGI-INF/l10n/bundle.properties @@ -62,4 +62,18 @@ nodes when using the Property Name Hint Name Generator replacement.char.name=Replacement Character replacement.char.description=A character with which to replace any non-allowed \ -characters in the name \ No newline at end of file +characters in the name + +# User Generated Content +ugc.name=User Generated Content +ugc.description=Service for creating buckets of User Generated Content + +ugcRoot.name=UGC Root +ugcRoot.description=The root resource under which the User Generated Content \ +should be saved + +defaultPathDepth.name=Default Path Depth +defaultPathDepth.description=The default path depth for UGC content to be stored \ +under the bucket. This will be sliced off the UUID, so if you had a UUID of 123 \ +a bucket of bob and a path depth of 1, this would yield a path like: bob/1/123. \ +This can be overridden by the path depth in the UGCBucketConfig. \ No newline at end of file diff --git a/pom.xml b/pom.xml index ccd3a75..2b49ce5 100644 --- a/pom.xml +++ b/pom.xml @@ -43,15 +43,15 @@ <module>reference</module> <module>builder</module> </modules> - - - <scm> - <connection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-app-cms.git</connection> - <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-app-cms.git</developerConnection> - <url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-app-cms.git</url> - <tag>HEAD</tag> - </scm> + + + <scm> + <connection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-app-cms.git</connection> + <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-app-cms.git</developerConnection> + <url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-app-cms.git</url> + <tag>HEAD</tag> + </scm> <dependencyManagement> <dependencies> @@ -70,7 +70,7 @@ <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.api</artifactId> - <version>2.8.0</version> + <version>2.18.0</version> <scope>provided</scope> </dependency> <dependency> diff --git a/ui/src/main/resources/SLING-INF/nodetypes/nodetypes.cnd b/ui/src/main/resources/SLING-INF/nodetypes/nodetypes.cnd index 8ce0cf1..a3d3731 100644 --- a/ui/src/main/resources/SLING-INF/nodetypes/nodetypes.cnd +++ b/ui/src/main/resources/SLING-INF/nodetypes/nodetypes.cnd @@ -74,3 +74,14 @@ - jcr:lastModifiedBy (string) - jcr:title (string) + * (sling:Taxonomy) = sling:Taxonomy version + +[sling:UGC] > nt:unstructured + - approveaction (string) + - contenttype (string) + - finalpath (string) + - preview (string) + - published (boolean) + - referrer (string) + - user (string) + - useragent (string) + - userip (string) diff --git a/ui/src/main/resources/jcr_root/libs/sling-cms/components/cms/suffixproperty/suffixproperty.jsp b/ui/src/main/resources/jcr_root/libs/sling-cms/components/cms/suffixproperty/suffixproperty.jsp new file mode 100644 index 0000000..5ed7d5c --- /dev/null +++ b/ui/src/main/resources/jcr_root/libs/sling-cms/components/cms/suffixproperty/suffixproperty.jsp @@ -0,0 +1,25 @@ +<%-- /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ --%> + <%@include file="/libs/sling-cms/global.jsp"%> + <div> + <strong> + <sling:encode value="${properties.label}" mode="HTML" />: + </strong><br/> + <sling:encode value="${slingRequest.requestPathInfo.suffixResource.valueMap[properties.property]}" mode="HTML" /> + </div> \ No newline at end of file diff --git a/ui/src/main/resources/jcr_root/libs/sling-cms/content/start.json b/ui/src/main/resources/jcr_root/libs/sling-cms/content/start.json index 30e3189..aac49ac 100644 --- a/ui/src/main/resources/jcr_root/libs/sling-cms/content/start.json +++ b/ui/src/main/resources/jcr_root/libs/sling-cms/content/start.json @@ -56,6 +56,16 @@ "query": "SELECT * FROM [sling:OrderedFolder] AS s WHERE ISCHILDNODE(s,'/conf') ORDER BY NAME()", "title": "Configuration" }, + "usergeneratednav": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/contentnav", + "createPath": "/cms/folder/create.html/etc/usergenerated", + "createFolder": "Bucket", + "prefix": "/cms/usergenerated", + "itemPrefix": "/cms/usergenerated/content.html", + "query": "SELECT * FROM [sling:OrderedFolder] AS s WHERE ISCHILDNODE(s,'/etc/usergenerated') ORDER BY NAME()", + "title": "User Generated" + }, "toolsnav": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "sling-cms/components/cms/staticnav", diff --git a/ui/src/main/resources/jcr_root/libs/sling-cms/content/usergenerated/content.json b/ui/src/main/resources/jcr_root/libs/sling-cms/content/usergenerated/content.json new file mode 100644 index 0000000..77a21ea --- /dev/null +++ b/ui/src/main/resources/jcr_root/libs/sling-cms/content/usergenerated/content.json @@ -0,0 +1,168 @@ +{ + "jcr:primaryType": "sling:Page", + "jcr:content": { + "sling:resourceType": "sling-cms/components/pages/base", + "jcr:title": "User Generated Content", + "jcr:primaryType": "nt:unstructured", + "container": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/general/container", + "contentactions": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/contentactions", + "actions": { + "folder": { + "jcr:primaryType": "nt:unstructured", + "label": "Bucket", + "prefix": "/cms/folder/create.html" + } + } + }, + "contentbreadcrumb": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/contentbreadcrumb", + "depth": 2, + "prefix": "/cms/usergenerated/content.html", + "titleProp": "jcr:content/jcr:title" + }, + "contenttable": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/contenttable", + "columns": { + "jcr:primaryType": "nt:unstructured", + "name": { + "jcr:primaryType": "nt:unstructured", + "title": "Name" + }, + "title": { + "jcr:primaryType": "nt:unstructured", + "title": "Title" + }, + "published": { + "jcr:primaryType": "nt:unstructured", + "title": "Published" + }, + "type": { + "jcr:primaryType": "nt:unstructured", + "title": "Type" + }, + "lastModified": { + "jcr:primaryType": "nt:unstructured", + "title": "Last Modified" + }, + "actions": { + "jcr:primaryType": "nt:unstructured", + "title": "Actions" + } + }, + "types": { + "jcr:primaryType": "nt:unstructured", + "sling:UGC":{ + "jcr:primaryType": "nt:unstructured", + "columns": { + "jcr:primaryType": "nt:unstructured", + "name": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/columns/name" + }, + "title": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/columns/text", + "property": "jcr:content/jcr:title", + "type": "String" + }, + "publish": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/columns/publish" + }, + "type": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/columns/static", + "value": "UGC" + }, + "lastModified": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/columns/lastmodified" + }, + "actions": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/columns/actions", + "edit": { + "jcr:primaryType": "nt:unstructured", + "modal": false, + "title": "Review User Generated Content", + "text": "✏", + "prefix": "/cms/usergenerated/review.html" + }, + "delete": { + "jcr:primaryType": "nt:unstructured", + "modal": true, + "title": "Delete User Generated Content", + "text": "×", + "prefix": "/cms/shared/delete.html" + } + } + } + }, + "sling:OrderedFolder":{ + "jcr:primaryType": "nt:unstructured", + "columns": { + "jcr:primaryType": "nt:unstructured", + "name": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/columns/name", + "link": true, + "prefix": "/cms/usergenerated/content.html" + }, + "title": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/columns/text", + "property": "jcr:content/jcr:title", + "type": "String" + }, + "publish": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/columns/publish" + }, + "type": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/columns/static", + "value": "Folder" + }, + "lastModified": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/columns/lastmodified", + "subPath": "jcr:content/" + }, + "actions": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/columns/actions", + "edit": { + "jcr:primaryType": "nt:unstructured", + "modal": true, + "title": "Edit Folder", + "text": "✏", + "prefix": "/cms/folder/edit.html" + }, + "movecopy": { + "jcr:primaryType": "nt:unstructured", + "modal": true, + "title": "Move / Copy Folder", + "text": "⇆", + "prefix": "/cms/shared/movecopy.html" + }, + "delete": { + "jcr:primaryType": "nt:unstructured", + "title": "Delete Folder", + "text": "×", + "prefix": "/cms/shared/delete.html", + "modal": true + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/ui/src/main/resources/jcr_root/libs/sling-cms/content/usergenerated/review.json b/ui/src/main/resources/jcr_root/libs/sling-cms/content/usergenerated/review.json new file mode 100644 index 0000000..7ef5836 --- /dev/null +++ b/ui/src/main/resources/jcr_root/libs/sling-cms/content/usergenerated/review.json @@ -0,0 +1,83 @@ +{ + "jcr:primaryType": "sling:Page", + "jcr:content": { + "sling:resourceType": "sling-cms/components/pages/base", + "jcr:title": "Review User Generated Content", + "jcr:primaryType": "nt:unstructured", + "container": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/general/container", + "richtext": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/general/richtext", + "text": "<h3>Review User Generated Content</h3>" + }, + "preview": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/suffixproperty", + "label": "Preview", + "property": "preview" + }, + "contenttype": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/suffixproperty", + "label": "Content Type", + "property": "contenttype" + }, + "referrer": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/suffixproperty", + "label": "Referrer", + "property": "referrer" + }, + "user": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/suffixproperty", + "label": "User", + "property": "user" + }, + "useragent": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/suffixproperty", + "label": "User Agent", + "property": "useragent" + }, + "userip": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/cms/suffixproperty", + "label": "User IP", + "property": "userip" + }, + "slingform": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/editor/slingform", + "button": "Approve Content", + "fields": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/general/container", + "title": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/editor/fields/hidden", + "name": ":operation", + "value": "ugcapprove" + } + } + }, + "deleteform": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/editor/slingform", + "button": "Delete Content", + "fields": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/general/container", + "title": { + "jcr:primaryType": "nt:unstructured", + "sling:resourceType": "sling-cms/components/editor/fields/hidden", + "name": ":operation", + "value": "delete" + } + } + } + } + } +} \ No newline at end of file
