From 51949661236a32c4fe0976275765687d076bcb94 Mon Sep 17 00:00:00 2001 From: Roy Wetherall Date: Thu, 1 May 2008 16:48:30 +0000 Subject: [PATCH] Site Service CRUD API's (Java, JavaScript and REST), unit test methods added to JS API to help unit test JS API's git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@8986 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/script-services-context.xml | 6 + .../repo/jscript/ScriptTestUtils.java | 99 ++++++++++++++ .../org/alfresco/repo/site/SiteService.java | 6 + .../alfresco/repo/site/SiteServiceImpl.java | 129 +++++++++++++----- .../repo/site/SiteServiceImplTest.java | 77 ++++++++++- .../repo/site/script/ScriptSiteService.java | 23 +++- .../org/alfresco/repo/site/script/Site.java | 102 +++++++++++++- .../repo/site/script/test_siteService.js | 70 ++++++---- 8 files changed, 440 insertions(+), 72 deletions(-) create mode 100644 source/java/org/alfresco/repo/jscript/ScriptTestUtils.java diff --git a/config/alfresco/script-services-context.xml b/config/alfresco/script-services-context.xml index 862d5ede77..48520eb01b 100644 --- a/config/alfresco/script-services-context.xml +++ b/config/alfresco/script-services-context.xml @@ -59,6 +59,12 @@ + + + test + + + actions diff --git a/source/java/org/alfresco/repo/jscript/ScriptTestUtils.java b/source/java/org/alfresco/repo/jscript/ScriptTestUtils.java new file mode 100644 index 0000000000..e393043abe --- /dev/null +++ b/source/java/org/alfresco/repo/jscript/ScriptTestUtils.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.jscript; + +import org.alfresco.error.AlfrescoRuntimeException; + + +/** + * @author Roy Wetherall + */ +public class ScriptTestUtils extends BaseScopableProcessorExtension +{ + public void assertEquals(Object expected, Object value, String message) + { + if (expected.equals(value) == false) + { + if (message == null) + { + message = "Expected value '" + expected + "' was '" + value + "'"; + } + throw new AlfrescoRuntimeException(message); + } + } + + public void assertNotNull(Object value, String message) + { + if (value == null) + { + if (message == null) + { + message = "Unexpected null value encountered."; + } + throw new AlfrescoRuntimeException(message); + } + } + + public void assertNull(Object value, String message) + { + if (value != null) + { + if (message == null) + { + message = "Unexpected non-null value encountered."; + } + throw new AlfrescoRuntimeException(message); + } + } + + public void assertTrue(boolean value, String message) + { + if (value == false) + { + if (message == null) + { + message = "Value is not True"; + } + throw new AlfrescoRuntimeException(message); + } + } + + public void assertFalse(boolean value, String message) + { + if (value == true) + { + if (message == null) + { + message = "Value is not False"; + } + throw new AlfrescoRuntimeException(message); + } + } + + public void fail(String message) + { + throw new AlfrescoRuntimeException(message); + } +} diff --git a/source/java/org/alfresco/repo/site/SiteService.java b/source/java/org/alfresco/repo/site/SiteService.java index 4c2e0a3b7f..caae0e6f4a 100644 --- a/source/java/org/alfresco/repo/site/SiteService.java +++ b/source/java/org/alfresco/repo/site/SiteService.java @@ -33,4 +33,10 @@ public interface SiteService */ // TODO audit information List listSites(String nameFilter, String sitePresetFilter); + + SiteInfo getSite(String shortName); + + void updateSite(SiteInfo siteInfo); + + void deleteSite(String shortName); } diff --git a/source/java/org/alfresco/repo/site/SiteServiceImpl.java b/source/java/org/alfresco/repo/site/SiteServiceImpl.java index edb92a4362..76a6640142 100644 --- a/source/java/org/alfresco/repo/site/SiteServiceImpl.java +++ b/source/java/org/alfresco/repo/site/SiteServiceImpl.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.repo.avm.AVMRepository; import org.alfresco.repo.security.authentication.AuthenticationComponent; @@ -47,6 +48,7 @@ import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.util.AbstractLifecycleBean; +import org.alfresco.util.ISO9075; import org.alfresco.util.PropertyMap; import org.springframework.context.ApplicationEvent; @@ -105,28 +107,10 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic public SiteInfo createSite(String sitePreset, String shortName, String title, String description, boolean isPublic) { - // TODO: - // 1. Check that the site preset exists - // 2. Check that the short name of the site isn't a duplicate - // 3. AVM create: - // 3a. Find the site preset AVM folder - // 3b. Create a new site folder in the correct location (named by the short name) - // 3c. Copy the contents of the site preset folder into the new site folder - // 3d. Mangle files as needed during copy ?? - // 4. DM create: - // 4a. Find the site preset DM folder ?? - // 4b. Create a new site in the correct location (named by short name) - // 4c. Set meta-data - // 4d. Set up memberships (copying from site preset DM folder??) - // 4e. Set up another details (rules) on site from DM preset folder ?? - // 5. Return created site information - - - - // 4. DM create .. create the DM object that represents the site + /// TODO check for shortname duplicates // Get the site parent node reference - NodeRef siteParent = getDMSiteParent(shortName); + NodeRef siteParent = getSiteParent(shortName); // Create the site node PropertyMap properties = new PropertyMap(4); @@ -148,32 +132,32 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic this.permissionService.setPermission(siteNodeRef, PermissionService.ALL_AUTHORITIES, SITE_CONSUMER, true); } - // 5. Return created site information + // Return created site information SiteInfo siteInfo = new SiteInfo(sitePreset, shortName, title, description, isPublic); return siteInfo; } - private NodeRef getDMSiteParent(String shortName) + private NodeRef getSiteParent(String shortName) { // TODO // For now just return the site root, later we may build folder structure based on the shortname to // spread the sites about - return getDMSiteRoot(); + return getSiteRoot(); } - private NodeRef getDMSiteRoot() + private NodeRef getSiteRoot() { // Get the root 'sites' folder ResultSet resultSet = this.searchService.query(SITE_DM_STORE, SearchService.LANGUAGE_LUCENE, "PATH:\"cm:sites\""); if (resultSet.length() == 0) { // TODO - throw new RuntimeException("No root sites folder exists"); + throw new AlfrescoRuntimeException("No root sites folder exists"); } else if (resultSet.length() != 1) { // TODO - throw new RuntimeException("More than one root sites folder exists"); + throw new AlfrescoRuntimeException("More than one root sites folder exists"); } NodeRef sitesRoot = resultSet.getNodeRef(0); @@ -188,12 +172,10 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic // TODO // - take into consideration the filters set // - take into consideration that the sites may not just be in a flat list under the site root - // - should we be taking the list from the AVM store, since we can have an AVM site pointing to - // the default DM data site // TODO // For now just return the list of sites present under the site root - NodeRef siteRoot = getDMSiteRoot(); + NodeRef siteRoot = getSiteRoot(); List assocs = this.nodeService.getChildAssocs(siteRoot, ContentModel.ASSOC_CONTAINS, RegexQNamePattern.MATCH_ALL); List result = new ArrayList(assocs.size()); for (ChildAssociationRef assoc : assocs) @@ -214,6 +196,15 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic String description = (String)properties.get(ContentModel.PROP_DESCRIPTION); // Determine whether the space is public or not + boolean isPublic = isSitePublic(siteNodeRef); + + // Create and return the site information + SiteInfo siteInfo = new SiteInfo(sitePreset, shortName, title, description, isPublic); + return siteInfo; + } + + private boolean isSitePublic(NodeRef siteNodeRef) + { boolean isPublic = false; Set permissions = this.permissionService.getAllSetPermissions(siteNodeRef); for (AccessPermission permission : permissions) @@ -225,10 +216,84 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic break; } } + return isPublic; + } + + /** + * @see org.alfresco.repo.site.SiteService#getSite(java.lang.String) + */ + public SiteInfo getSite(String shortName) + { + SiteInfo result = null; - // Create and return the site information - SiteInfo siteInfo = new SiteInfo(sitePreset, shortName, title, description, isPublic); - return siteInfo; + // Get the site node + NodeRef siteNodeRef = getSiteNodeRef(shortName); + if (siteNodeRef != null) + { + // Create the site info + result = createSiteInfo(siteNodeRef); + } + + // Return the site information + return result; + } + + private NodeRef getSiteNodeRef(String shortName) + { + NodeRef result = null; + ResultSet resultSet = this.searchService.query(SITE_DM_STORE, SearchService.LANGUAGE_LUCENE, "PATH:\"cm:sites/cm:" + ISO9075.encode(shortName) + "\""); + if (resultSet.length() == 1) + { + result = resultSet.getNodeRef(0); + } + return result; + } + + public void updateSite(SiteInfo siteInfo) + { + NodeRef siteNodeRef = getSiteNodeRef(siteInfo.getShortName()); + if (siteNodeRef == null) + { + throw new AlfrescoRuntimeException("Can not update site " + siteInfo.getShortName() + " because it does not exist."); + } + + // Note: the site preset and short name can not be updated + + // Update the properties of the site + Map properties = this.nodeService.getProperties(siteNodeRef); + properties.put(ContentModel.PROP_TITLE, siteInfo.getTitle()); + properties.put(ContentModel.PROP_DESCRIPTION, siteInfo.getDescription()); + this.nodeService.setProperties(siteNodeRef, properties); + + // Update the isPublic flag + boolean isPublic = isSitePublic(siteNodeRef); + if (isPublic != siteInfo.getIsPublic()); + { + if (siteInfo.getIsPublic() == true) + { + // Add the permission + this.permissionService.setPermission(siteNodeRef, PermissionService.ALL_AUTHORITIES, SITE_CONSUMER, true); + } + else + { + // Remove the permission + this.permissionService.deletePermission(siteNodeRef, PermissionService.ALL_AUTHORITIES, SITE_CONSUMER); + } + } + } + + /** + * @see org.alfresco.repo.site.SiteService#deleteSite(java.lang.String) + */ + public void deleteSite(String shortName) + { + NodeRef siteNodeRef = getSiteNodeRef(shortName); + if (siteNodeRef == null) + { + throw new AlfrescoRuntimeException("Can not delete site " + shortName + " because it does not exist."); + } + + this.nodeService.deleteNode(siteNodeRef); } /** diff --git a/source/java/org/alfresco/repo/site/SiteServiceImplTest.java b/source/java/org/alfresco/repo/site/SiteServiceImplTest.java index c26642d52c..a8e086735d 100644 --- a/source/java/org/alfresco/repo/site/SiteServiceImplTest.java +++ b/source/java/org/alfresco/repo/site/SiteServiceImplTest.java @@ -27,6 +27,7 @@ package org.alfresco.repo.site; import java.util.HashMap; import java.util.List; +import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.jscript.ClasspathScriptLocation; import org.alfresco.service.cmr.repository.ScriptLocation; import org.alfresco.service.cmr.repository.ScriptService; @@ -129,16 +130,78 @@ public class SiteServiceImplTest extends BaseAlfrescoSpringTest } + public void testGetSite() + { + // Get a site that isn't there + SiteInfo siteInfo = this.siteService.getSite("testGetSite"); + assertNull(siteInfo); + + // Create a test site + this.siteService.createSite(TEST_SITE_PRESET, "testGetSite", TEST_TITLE, TEST_DESCRIPTION, true); + + // Get the test site + siteInfo = this.siteService.getSite("testGetSite"); + assertNotNull(siteInfo); + checkSiteInfo(siteInfo, TEST_SITE_PRESET, "testGetSite", TEST_TITLE, TEST_DESCRIPTION, true); + } + + public void testUpdateSite() + { + SiteInfo siteInfo = new SiteInfo(TEST_SITE_PRESET, "testUpdateSite", "changedTitle", "changedDescription", false); + + // update a site that isn't there + try + { + this.siteService.updateSite(siteInfo); + fail("Shouldn't be able to update a site that does not exist"); + } + catch (AlfrescoRuntimeException exception) + { + // Expected + } + + // Create a test site + this.siteService.createSite(TEST_SITE_PRESET, "testUpdateSite", TEST_TITLE, TEST_DESCRIPTION, true); + + // Update the details of the site + this.siteService.updateSite(siteInfo); + siteInfo = this.siteService.getSite("testUpdateSite"); + checkSiteInfo(siteInfo, TEST_SITE_PRESET, "testUpdateSite", "changedTitle", "changedDescription", false); + + // Update the permission again + siteInfo.setIsPublic(true); + this.siteService.updateSite(siteInfo); + checkSiteInfo(siteInfo, TEST_SITE_PRESET, "testUpdateSite", "changedTitle", "changedDescription", true); + } + + public void testDeleteSite() + { + // delete a site that isn't there + try + { + this.siteService.deleteSite("testDeleteSite"); + fail("Shouldn't be able to delete a site that does not exist"); + } + catch (AlfrescoRuntimeException exception) + { + // Expected + } + + // Create a test site + this.siteService.createSite(TEST_SITE_PRESET, "testUpdateSite", TEST_TITLE, TEST_DESCRIPTION, true); + assertNotNull(this.siteService.getSite("testUpdateSite")); + + // Delete the site + this.siteService.deleteSite("testUpdateSite"); + assertNull(this.siteService.getSite("testUpdateSite")); + } + + // == Test the JavaScript API == + public void testJSAPI() throws Exception { ScriptLocation location = new ClasspathScriptLocation("org/alfresco/repo/site/script/test_siteService.js"); - String result = (String)this.scriptService.executeScript(location, new HashMap(0)); - - // Check the result and fail if message returned - if (result != null && result.length() != 0) - { - fail("The site service text JS script failed: " + result); - } + this.scriptService.executeScript(location, new HashMap(0)); } } diff --git a/source/java/org/alfresco/repo/site/script/ScriptSiteService.java b/source/java/org/alfresco/repo/site/script/ScriptSiteService.java index 41f590badd..285b28988a 100644 --- a/source/java/org/alfresco/repo/site/script/ScriptSiteService.java +++ b/source/java/org/alfresco/repo/site/script/ScriptSiteService.java @@ -67,7 +67,7 @@ public class ScriptSiteService extends BaseScopableProcessorExtension public Site createSite(String sitePreset, String shortName, String title, String descripion, boolean isPublic) { SiteInfo siteInfo = this.siteService.createSite(sitePreset, shortName, title, descripion, isPublic); - return new Site(siteInfo); + return new Site(this.siteService, siteInfo); } /** @@ -86,8 +86,27 @@ public class ScriptSiteService extends BaseScopableProcessorExtension List sites = new ArrayList(siteInfos.size()); for (SiteInfo siteInfo : siteInfos) { - sites.add(new Site(siteInfo)); + sites.add(new Site(this.siteService, siteInfo)); } return sites; } + + /** + * Get a site for a provided site short name. + *

+ * Returns null if the site does not exist. + * + * @param shortName short name of the site + * @return Site the site, null if does not exist + */ + public Site getSite(String shortName) + { + Site site = null; + SiteInfo siteInfo = this.siteService.getSite(shortName); + if (siteInfo != null) + { + site = new Site(this.siteService, siteInfo); + } + return site; + } } diff --git a/source/java/org/alfresco/repo/site/script/Site.java b/source/java/org/alfresco/repo/site/script/Site.java index e36f546459..9e121dda97 100644 --- a/source/java/org/alfresco/repo/site/script/Site.java +++ b/source/java/org/alfresco/repo/site/script/Site.java @@ -27,6 +27,7 @@ package org.alfresco.repo.site.script; import java.io.Serializable; import org.alfresco.repo.site.SiteInfo; +import org.alfresco.repo.site.SiteService; /** * @author Roy Wetherall @@ -34,42 +35,133 @@ import org.alfresco.repo.site.SiteInfo; public class Site implements Serializable { private static final long serialVersionUID = 8013569574120957923L; - + + /** Site information */ private SiteInfo siteInfo; - public Site(SiteInfo siteInfo) + /** Site service */ + private SiteService siteService; + + /** Indicates whether there are any outstanding changes that need to be saved */ + private boolean isDirty = false; + + /** + * Constructor + * + * @param siteInfo site information + */ + /*package*/ Site(SiteService siteService, SiteInfo siteInfo) { + this.siteService = siteService; this.siteInfo = siteInfo; } + /** + * Get the site preset + * + * @return String the site preset + */ public String getSitePreset() { return this.siteInfo.getSitePreset(); } + /** + * Set the short name + * + * @return String the short name + */ public String getShortName() { return this.siteInfo.getShortName(); } + /** + * Get the title + * + * @return String the site title + */ public String getTitle() { return this.siteInfo.getTitle(); } - // TODO set title + /** + * Set the title + * + * @param title the title + */ + public void setTitle(String title) + { + this.isDirty = true; + this.siteInfo.setTitle(title); + } + /** + * Get the description + * + * @return String the description + */ public String getDescription() { return this.siteInfo.getDescription(); } - // TODO set description + /** + * Set the description + * + * @param description the description + */ + public void setDescription(String description) + { + this.isDirty = true; + this.siteInfo.setDescription(description); + } + /** + * Gets whether the site is public or not + * + * @return true is public false otherwise + */ public boolean getIsPublic() { return this.siteInfo.getIsPublic(); } - // TODO set isPublic + /** + * Set whether the site is public or not + * + * @param isPublic true the site is public false otherwise + */ + public void setIsPublic(boolean isPublic) + { + this.isDirty = true; + this.siteInfo.setIsPublic(isPublic); + } + + /** + * Saves any outstanding updates to the site details. + *

+ * If properties of the site are changed and save is not called, those changes will be lost. + */ + public void save() + { + if (this.isDirty == true) + { + // Update the site details + this.siteService.updateSite(this.siteInfo); + + // Reset the dirty flag + this.isDirty = false; + } + } + + /** + * Deletes the site + */ + public void deleteSite() + { + // Delete the site + this.siteService.deleteSite(this.siteInfo.getShortName()); + } } diff --git a/source/java/org/alfresco/repo/site/script/test_siteService.js b/source/java/org/alfresco/repo/site/script/test_siteService.js index 6271f43104..5bc162dee9 100644 --- a/source/java/org/alfresco/repo/site/script/test_siteService.js +++ b/source/java/org/alfresco/repo/site/script/test_siteService.js @@ -1,29 +1,47 @@ -var failure = ""; - -// Try and create a site -var site = siteService.createSite("sitePreset", "siteShortName", "siteTitle", "siteDescription", true); - -// Check that the site details are correct -if (site.sitePreset != "sitePreset") +function checkSite(site, sitePreset, shortName, title, description, isPublic) { - failure += "\nSite preset is not set on created site"; -} -if (site.shortName != "siteShortName") -{ - failure += "\nSite short name is not set on created site"; -} -if (site.title != "siteTitle") -{ - failure += "\nSite title is not set on created site"; -} -if (site.description != "siteDescription") -{ - failure += "\nSite description is not set on created site"; -} -if (site.isPublic != true) -{ - failure += "\nCreated site should be marked public"; + test.assertNotNull(site, "Site should not be null"); + test.assertEquals(sitePreset, site.sitePreset, "Site preset incorrect for site " + shortName); + test.assertEquals(shortName, site.shortName, "Site shortname incorrect"); + test.assertEquals(title, site.title, "Site title incorrect for site " + shortName); + test.assertEquals(description, site.description, "Site description incorrect for site " + shortName); + test.assertEquals(isPublic, site.isPublic, "Site ispublic incorrect for site " + shortName); } -// Return the failure message -failure; \ No newline at end of file +function testCRUD() +{ + // Try and get a site that doesn't exist + var site = siteService.getSite("siteShortName"); + test.assertNull(site, "Site should not have been found."); + + // Try and create a site + site = siteService.createSite("sitePreset", "siteShortName", "siteTitle", "siteDescription", true); + checkSite(site, "sitePreset", "siteShortName", "siteTitle", "siteDescription", true); + + // Try and get the created site + site = siteService.getSite("siteShortName"); + checkSite(site, "sitePreset", "siteShortName", "siteTitle", "siteDescription", true); + + // Try and update the values of the site + site.title = "abc123abc"; + site.description = "abc123abc"; + site.isPublic = false; + checkSite(site, "sitePreset", "siteShortName", "abc123abc", "abc123abc", false); + site.save(); + site = siteService.getSite("siteShortName"); + checkSite(site, "sitePreset", "siteShortName", "abc123abc", "abc123abc", false); + + // Delete the site + site.deleteSite(); + site = siteService.getSite("siteShortName"); + test.assertNull(site, ""); +} + +function testListSites() +{ + // TODO +} + +// Execute test's +testCRUD(); +testListSites(); \ No newline at end of file