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": 
"&#x270f;",
+                                                                       
"prefix": "/cms/usergenerated/review.html"
+                                                               },
+                                                               "delete": {
+                                                                       
"jcr:primaryType": "nt:unstructured",
+                                                                       
"modal": true,
+                                                                       
"title": "Delete User Generated Content",
+                                                                       "text": 
"&times;",
+                                                                       
"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": 
"&#x270f;",
+                                                                       
"prefix": "/cms/folder/edit.html"
+                                                               },
+                                                               "movecopy": {
+                                                                       
"jcr:primaryType": "nt:unstructured",
+                                                                       
"modal": true,
+                                                                       
"title": "Move / Copy Folder",
+                                                                       "text": 
"&#x21c6;",
+                                                                       
"prefix": "/cms/shared/movecopy.html"
+                                                               },
+                                                               "delete": {
+                                                                       
"jcr:primaryType": "nt:unstructured",
+                                                                       
"title": "Delete Folder",
+                                                                       "text": 
"&times;",
+                                                                       
"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

Reply via email to