From e07a0a4c4b81588a1a617822b8fe21daf3a195a0 Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Thu, 31 May 2007 03:42:59 +0000 Subject: [PATCH] ML Authentication Issues: - Everyone, including guest, gets explicit full rights to each new cm:mlContainer instance. - The MultilingualContentService better permission checks against the content nodes that go in and out of it. - Changed some of the API return values to be more explicit about whether the cm:mlContainer or cm:mlDocument is required. - Added explicit tests to ensure that even guest is able to manipulate the cm:mlContainer. ML Languages List: - The default value is now punted to the top of the list. Various neatening. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@5816 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../model-specific-services-context.xml | 3 + .../public-services-security-context.xml | 11 +- .../alfresco/repo/audit/AuditServiceTest.java | 4 + .../model/ml/ContentFilterLanguagesMap.java | 22 ++- .../ml/MultilingualContentServiceImpl.java | 81 +++++------ .../ml/tools/EmptyTranslationAspectTest.java | 3 +- .../model/ml/tools/MLContainerTypeTest.java | 3 +- .../MultilingualContentServiceImplTest.java | 136 ++++++++++++------ .../tools/MultilingualDocumentAspectTest.java | 27 ++-- .../repo/version/VersionableAspect.java | 3 +- .../cmr/ml/MultilingualContentService.java | 35 ++--- 11 files changed, 191 insertions(+), 137 deletions(-) diff --git a/config/alfresco/model-specific-services-context.xml b/config/alfresco/model-specific-services-context.xml index 6fc8977884..0778faf5b0 100644 --- a/config/alfresco/model-specific-services-context.xml +++ b/config/alfresco/model-specific-services-context.xml @@ -76,6 +76,9 @@ + + + diff --git a/config/alfresco/public-services-security-context.xml b/config/alfresco/public-services-security-context.xml index 3076522463..7aada6efe8 100644 --- a/config/alfresco/public-services-security-context.xml +++ b/config/alfresco/public-services-security-context.xml @@ -532,18 +532,17 @@ - org.alfresco.service.cmr.ml.MultilingualContentService.getTranslationContainer=ACL_NODE.0.sys:base.Read - org.alfresco.service.cmr.ml.MultilingualContentService.getTranslations=ACL_NODE.0.sys:base.Read - org.alfresco.service.cmr.ml.MultilingualContentService.getTranslationForLocale=ACL_NODE.0.sys:base.Read + org.alfresco.service.cmr.ml.MultilingualContentService.getTranslationContainer=ACL_ALLOW + org.alfresco.service.cmr.ml.MultilingualContentService.getTranslations=ACL_NODE.0.sys:base.Read,AFTER_ACL_NODE.sys:base.Read + org.alfresco.service.cmr.ml.MultilingualContentService.getTranslationForLocale=ACL_NODE.0.sys:base.Read,AFTER_ACL_NODE.sys:base.Read org.alfresco.service.cmr.ml.MultilingualContentService.getMissingTranslations=ACL_ALLOW - org.alfresco.service.cmr.ml.MultilingualContentService.getPivotTranslation=ACL_NODE.0.sys:base.Read + org.alfresco.service.cmr.ml.MultilingualContentService.getPivotTranslation=ACL_NODE.0.sys:base.Read,AFTER_ACL_NODE.sys:base.Read org.alfresco.service.cmr.ml.MultilingualContentService.isTranslation=ACL_NODE.0.sys:base.Read org.alfresco.service.cmr.ml.MultilingualContentService.makeTranslation=ACL_NODE.0.sys:base.Write org.alfresco.service.cmr.ml.MultilingualContentService.unmakeTranslation=ACL_NODE.0.sys:base.Write org.alfresco.service.cmr.ml.MultilingualContentService.addTranslation=ACL_NODE.0.sys:base.Read,ACL_NODE.1.sys:base.Write - org.alfresco.service.cmr.ml.MultilingualContentService.addEmptyTranslation=ACL_NODE.0.sys:base.Read + org.alfresco.service.cmr.ml.MultilingualContentService.addEmptyTranslation=ACL_NODE.0.sys:base.Read,ACL_NODE.0.sys:base.CreateChildren org.alfresco.service.cmr.ml.MultilingualContentService.createEdition=ACL_NODE.0.sys:base.Write - org.alfresco.service.cmr.ml.MultilingualContentService.renameWithMLExtension=ACL_NODE.0.sys:base.Write diff --git a/source/java/org/alfresco/repo/audit/AuditServiceTest.java b/source/java/org/alfresco/repo/audit/AuditServiceTest.java index 00d860e827..05643eaa3e 100644 --- a/source/java/org/alfresco/repo/audit/AuditServiceTest.java +++ b/source/java/org/alfresco/repo/audit/AuditServiceTest.java @@ -52,6 +52,10 @@ import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.util.BaseSpringTest; +/** + * @author Andy Hind + */ +@SuppressWarnings("unused") public class AuditServiceTest extends BaseSpringTest { diff --git a/source/java/org/alfresco/repo/model/ml/ContentFilterLanguagesMap.java b/source/java/org/alfresco/repo/model/ml/ContentFilterLanguagesMap.java index ead3ea0278..6483439728 100644 --- a/source/java/org/alfresco/repo/model/ml/ContentFilterLanguagesMap.java +++ b/source/java/org/alfresco/repo/model/ml/ContentFilterLanguagesMap.java @@ -212,19 +212,29 @@ public class ContentFilterLanguagesMap implements ContentFilterLanguagesService String value = langElem.getValue(); String def = langElem.getAttribute(ATTR_DEFAULT); - orderedLangCodes.add(code); - languagesByCode.put(code, value); - if(def != null && Boolean.parseBoolean(def)) + boolean isDefault = (def != null && Boolean.parseBoolean(def)); + if(isDefault) { if(defaultLanguage != null) { - logger.warn("Ignoring default attribute is not unique le last matched will be used"); + logger.warn("Content filter default language is not unique: " + code); + } + else + { + this.defaultLanguage = code; } - - this.defaultLanguage = code; } + if (defaultLanguage == code) + { + orderedLangCodes.add(0, code); + } + else + { + orderedLangCodes.add(code); + } + } // make the collections read-only diff --git a/source/java/org/alfresco/repo/model/ml/MultilingualContentServiceImpl.java b/source/java/org/alfresco/repo/model/ml/MultilingualContentServiceImpl.java index 45cd5ba658..d145fc6b48 100644 --- a/source/java/org/alfresco/repo/model/ml/MultilingualContentServiceImpl.java +++ b/source/java/org/alfresco/repo/model/ml/MultilingualContentServiceImpl.java @@ -48,6 +48,7 @@ import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.SearchParameters; import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.version.Version; import org.alfresco.service.cmr.version.VersionService; import org.alfresco.service.namespace.NamespaceService; @@ -85,6 +86,7 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic private NodeService nodeService; private SearchService searchService; private VersionService versionService; + private PermissionService permissionService; private SearchParameters searchParametersMLRoot; private ContentFilterLanguagesService contentFilterLanguagesService; private FileFolderService fileFolderService; @@ -133,13 +135,30 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic { NodeRef mlContainerRootNodeRef = getMLContainerRoot(); // Create the container + PropertyMap versionProperties = new PropertyMap(); + versionProperties.put(ContentModel.PROP_AUTO_VERSION, Boolean.FALSE); + versionProperties.put(ContentModel.PROP_INITIAL_VERSION, Boolean.FALSE); ChildAssociationRef assocRef = nodeService.createNode( mlContainerRootNodeRef, ContentModel.ASSOC_CHILDREN, QNAME_ML_CONTAINER, - ContentModel.TYPE_MULTILINGUAL_CONTAINER); - // done - return assocRef.getChildRef(); + ContentModel.TYPE_MULTILINGUAL_CONTAINER, + versionProperties); + NodeRef mlContainerNodeRef = assocRef.getChildRef(); + // TODO: Examine the usage of versioning - why is autoversioning on and used in the UI? +// // The model makes the container versionable by default, but why? +// nodeService.addAspect(mlContainerNodeRef, ContentModel.ASPECT_VERSIONABLE, versionProperties); + // Set the permissions to allow anything by anyone + permissionService.setPermission( + mlContainerNodeRef, + PermissionService.ALL_AUTHORITIES, + PermissionService.ALL_PERMISSIONS, true); + permissionService.setPermission( + mlContainerNodeRef, + PermissionService.GUEST_AUTHORITY, + PermissionService.ALL_PERMISSIONS, true); + // Done + return mlContainerNodeRef; } /** @@ -255,7 +274,8 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic { PropertyMap properties = new PropertyMap(); properties.put(ContentModel.PROP_LOCALE, locale); - nodeService.addAspect(contentNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT, properties); + nodeService.addAspect(contentNodeRef, ContentModel.ASPECT_LOCALIZED, properties); + nodeService.addAspect(contentNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT, null); } else { @@ -341,7 +361,7 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic } /** @inheritDoc */ - public NodeRef makeTranslation(NodeRef contentNodeRef, Locale locale) + public void makeTranslation(NodeRef contentNodeRef, Locale locale) { NodeRef mlContainerNodeRef = makeTranslationImpl(null, contentNodeRef, locale); // done @@ -352,7 +372,6 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic " locale: " + locale + "\n" + " container: " + mlContainerNodeRef); } - return mlContainerNodeRef; } /** @inheritDoc */ @@ -410,32 +429,20 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic } /** @inheritDoc */ - public NodeRef addTranslation(NodeRef newTranslationNodeRef, NodeRef translationOfNodeRef, Locale locale) + public void addTranslation(NodeRef newTranslationNodeRef, NodeRef translationOfNodeRef, Locale locale) { - NodeRef mlContainerNodeRef = null; - // Were we given the translation or the container - QName typeQName = nodeService.getType(translationOfNodeRef); - if (typeQName.equals(ContentModel.TYPE_MULTILINGUAL_CONTAINER)) - { - // We have the container - mlContainerNodeRef = translationOfNodeRef; - } - else - { - // Get the container - mlContainerNodeRef = getOrCreateMLContainer(translationOfNodeRef, false); - } + // Get the container + NodeRef mlContainerNodeRef = getOrCreateMLContainer(translationOfNodeRef, false); // Use the existing container to make the new content into a translation makeTranslationImpl(mlContainerNodeRef, newTranslationNodeRef, locale); // done if (logger.isDebugEnabled()) { logger.debug("Added a translation: \n" + - " Translation of: " + translationOfNodeRef + " of type " + typeQName + "\n" + + " Translation of: " + translationOfNodeRef + "\n" + " New translation: " + newTranslationNodeRef + "\n" + " Locale: " + locale); } - return mlContainerNodeRef; } /** @inheritDoc */ @@ -661,7 +668,7 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic Locale nearestLocale = I18NUtil.getNearestLocale(containerLocale, locales); if (nearestLocale == null) { - // There is pivot translation + // There is no pivot translation return null; } else @@ -675,9 +682,8 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic */ public NodeRef addEmptyTranslation(NodeRef translationOfNodeRef, String name, Locale locale) { - QName typeQName = nodeService.getType(translationOfNodeRef); boolean hasMLAspect = nodeService.hasAspect(translationOfNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT); - if (hasMLAspect || typeQName.equals(ContentModel.TYPE_MULTILINGUAL_CONTAINER)) + if (hasMLAspect) { // Get the pivot translation NodeRef pivotTranslationNodeRef = getPivotTranslation(translationOfNodeRef); @@ -688,22 +694,13 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic } else { - // We use the given translation, provided it is an actual translation - if (!hasMLAspect) - { - throw new IllegalArgumentException( - "The node provided is not associated with a pivot translation " + - "and is not in itself a translation: \n" + - " Translation: " + translationOfNodeRef + "\n" + - " Locale: " + locale); - } + // We use the given translation } } else { throw new IllegalArgumentException( - "Node must have aspect " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + - " or be a " + ContentModel.TYPE_MULTILINGUAL_CONTAINER + ": \n" + + "Node must have aspect " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + ": \n" + " Translation: " + translationOfNodeRef + "\n" + " Locale: " + locale); } @@ -773,7 +770,7 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic if (logger.isDebugEnabled()) { logger.debug("Added an empty translation: \n" + - " Translation of: " + translationOfNodeRef + " of type " + typeQName + "\n" + + " Translation of: " + translationOfNodeRef + "\n" + " New translation: " + newTranslationNodeRef + "\n" + " Locale: " + locale); } @@ -796,6 +793,11 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic this.versionService = versionService; } + public void setPermissionService(PermissionService permissionService) +{ + this.permissionService = permissionService; +} + public void setContentFilterLanguagesService(ContentFilterLanguagesService contentFilterLanguagesService) { this.contentFilterLanguagesService = contentFilterLanguagesService; @@ -805,9 +807,4 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic { this.fileFolderService = fileFolderService; } - - public void renameWithMLExtension(NodeRef translationNodeRef) - { - throw new UnsupportedOperationException(); - } } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/model/ml/tools/EmptyTranslationAspectTest.java b/source/java/org/alfresco/repo/model/ml/tools/EmptyTranslationAspectTest.java index 843b58858a..0a890f904f 100644 --- a/source/java/org/alfresco/repo/model/ml/tools/EmptyTranslationAspectTest.java +++ b/source/java/org/alfresco/repo/model/ml/tools/EmptyTranslationAspectTest.java @@ -108,7 +108,8 @@ public class EmptyTranslationAspectTest extends AbstractMultilingualTestCases { NodeRef empty = null; - NodeRef mlContainer = multilingualContentService.makeTranslation(pivot, Locale.FRENCH); + multilingualContentService.makeTranslation(pivot, Locale.FRENCH); + NodeRef mlContainer = multilingualContentService.getTranslationContainer(pivot); multilingualContentService.addTranslation(otherTranslation, pivot, Locale.KOREAN); empty = multilingualContentService.addEmptyTranslation(pivot, "empty_" + System.currentTimeMillis(), Locale.CHINESE); diff --git a/source/java/org/alfresco/repo/model/ml/tools/MLContainerTypeTest.java b/source/java/org/alfresco/repo/model/ml/tools/MLContainerTypeTest.java index ff2762088c..67830200c7 100644 --- a/source/java/org/alfresco/repo/model/ml/tools/MLContainerTypeTest.java +++ b/source/java/org/alfresco/repo/model/ml/tools/MLContainerTypeTest.java @@ -49,7 +49,8 @@ public class MLContainerTypeTest extends AbstractMultilingualTestCases NodeRef trans3 = createContent(); NodeRef empty = null; - NodeRef mlContainer = multilingualContentService.makeTranslation(trans1, Locale.FRENCH); + multilingualContentService.makeTranslation(trans1, Locale.FRENCH); + NodeRef mlContainer = multilingualContentService.getTranslationContainer(trans1); multilingualContentService.addTranslation(trans2, trans1, Locale.GERMAN); multilingualContentService.addTranslation(trans3, trans1, Locale.ITALIAN); empty = multilingualContentService.addEmptyTranslation(trans1, "EMPTY_" + System.currentTimeMillis(), Locale.JAPANESE); diff --git a/source/java/org/alfresco/repo/model/ml/tools/MultilingualContentServiceImplTest.java b/source/java/org/alfresco/repo/model/ml/tools/MultilingualContentServiceImplTest.java index 7b6fa48960..aff0322815 100644 --- a/source/java/org/alfresco/repo/model/ml/tools/MultilingualContentServiceImplTest.java +++ b/source/java/org/alfresco/repo/model/ml/tools/MultilingualContentServiceImplTest.java @@ -30,11 +30,15 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import net.sf.acegisecurity.Authentication; + import org.alfresco.i18n.I18NUtil; import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; +import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.version.Version; import org.alfresco.service.cmr.version.VersionHistory; @@ -49,45 +53,30 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest public void testMakeTranslation() throws Exception { - NodeRef contentNodeRef = createContent(); + NodeRef chineseContentNodeRef = createContent(); // Turn the content into a translation with the appropriate structures - NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(contentNodeRef, Locale.CHINESE); + multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); + NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef); // Check it assertNotNull("Container not created", mlContainerNodeRef); // Check the container child count assertEquals("Incorrect number of child nodes", 1, nodeService.getChildAssocs(mlContainerNodeRef).size()); } - public void testAddTranslationUsingContainer() throws Exception - { - // Make a container with a single translation - NodeRef chineseContentNodeRef = createContent(); - NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); - // Create some more content - NodeRef frenchContentNodeRef = createContent(); - // Make this a translation of the Chinese - NodeRef newMLContainerNodeRef = multilingualContentService.addTranslation( - frenchContentNodeRef, - mlContainerNodeRef, - Locale.FRENCH); - // Make sure that the original container was used - assertEquals("Existing container should have been used", mlContainerNodeRef, newMLContainerNodeRef); - // Check the container child count - assertEquals("Incorrect number of child nodes", 2, nodeService.getChildAssocs(mlContainerNodeRef).size()); - } - public void testAddTranslationUsingContent() throws Exception { // Make a container with a single translation NodeRef chineseContentNodeRef = createContent(); - NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); + multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); + NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef); // Create some more content NodeRef frenchContentNodeRef = createContent(); // Make this a translation of the Chinese - NodeRef newMLContainerNodeRef = multilingualContentService.addTranslation( + multilingualContentService.addTranslation( frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH); + NodeRef newMLContainerNodeRef = multilingualContentService.getTranslationContainer(frenchContentNodeRef); // Make sure that the original container was used assertEquals("Existing container should have been used", mlContainerNodeRef, newMLContainerNodeRef); // Check the container child count @@ -113,9 +102,9 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest NodeRef nodeRef2 = createContent(); NodeRef nodeRef3 = createContent(); - NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(nodeRef1, loc1); + multilingualContentService.makeTranslation(nodeRef1, loc1); - List missing = multilingualContentService.getMissingTranslations(mlContainerNodeRef, false); + List missing = multilingualContentService.getMissingTranslations(nodeRef1, false); // make sure that the missing language list size is correct assertFalse("Missing Translation Size false. " + @@ -124,13 +113,13 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest // make sure that the missing language list is correct assertFalse("Missing Translation List false. Locale " + loc1 + " found", missing.contains(loc1.toString())); - multilingualContentService.addTranslation(nodeRef2, mlContainerNodeRef, loc2); - multilingualContentService.addTranslation(nodeRef3, mlContainerNodeRef, loc3); + multilingualContentService.addTranslation(nodeRef2, nodeRef1, loc2); + multilingualContentService.addTranslation(nodeRef3, nodeRef1, loc3); + // Add the missing translations in + missing = multilingualContentService.getMissingTranslations(nodeRef1, false); - missing = multilingualContentService.getMissingTranslations(mlContainerNodeRef, false); - - // make sure that the missing language list size is correct + // Make sure that the missing language list size is correct assertFalse("Missing Translation Size false. " + "Real size : " + missing.size() + ". Normal Size " + (langListSize - 3), missing.size() != (langListSize - 3)); @@ -141,29 +130,30 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest public void testGetTranslationForLocale() throws Exception { NodeRef chineseContentNodeRef = createContent(); - NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); + multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); NodeRef frenchContentNodeRef = createContent(); multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH); // Get the chinese translation assertEquals("Chinese translation should be present", chineseContentNodeRef, - multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.CHINESE)); + multilingualContentService.getTranslationForLocale(chineseContentNodeRef, Locale.CHINESE)); // Get the french translation assertEquals("French translation should be present", frenchContentNodeRef, - multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.FRENCH)); + multilingualContentService.getTranslationForLocale(chineseContentNodeRef, Locale.FRENCH)); // The Italian should return the pivot assertEquals("French translation should be present", chineseContentNodeRef, - multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.ITALIAN)); + multilingualContentService.getTranslationForLocale(chineseContentNodeRef, Locale.ITALIAN)); } @SuppressWarnings("unused") public void testGetPivotTranslation() throws Exception { NodeRef chineseContentNodeRef = createContent(); - NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); + multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); + NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef); // make sure that the pivot language is set assertNotNull("Pivot language not set", nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE)); @@ -189,10 +179,10 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest public void testCreateEmptyTranslation() throws Exception { NodeRef chineseContentNodeRef = createContent("Document.txt"); - NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); + multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); // This should use the pivot language - NodeRef emptyNodeRef = multilingualContentService.addEmptyTranslation(mlContainerNodeRef, "Document.txt", Locale.CANADA); + NodeRef emptyNodeRef = multilingualContentService.addEmptyTranslation(chineseContentNodeRef, "Document.txt", Locale.CANADA); // Ensure that the empty translation is not null assertNotNull("The creation of the empty document failed ", emptyNodeRef); @@ -215,7 +205,7 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest public void testCreateEmptyTranslationNames() throws Exception { NodeRef chineseContentNodeRef = createContent("Document.txt"); - NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); + multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); NodeRef koreanContentNodeRef = createContent("Document_ko.txt"); multilingualContentService.addTranslation(koreanContentNodeRef, chineseContentNodeRef, Locale.KOREAN); // Create with a null name, and off a non-pivot just to be sure @@ -227,14 +217,14 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest assertEquals("Empty translation name not generated correctly.", "Document_en_CA.txt", nullName); // Create with the same name NodeRef sameNameNodeRef = multilingualContentService.addEmptyTranslation( - mlContainerNodeRef, + chineseContentNodeRef, "Document.txt", Locale.CANADA_FRENCH); String sameName = fileFolderService.getFileInfo(sameNameNodeRef).getName(); assertEquals("Empty translation name not generated correctly.", "Document_fr_CA.txt", sameName); // Create with a different name NodeRef differentNameNodeRef = multilingualContentService.addEmptyTranslation( - mlContainerNodeRef, + chineseContentNodeRef, "Document2.txt", Locale.JAPANESE); String differentName = fileFolderService.getFileInfo(differentNameNodeRef).getName(); @@ -249,9 +239,11 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest NodeRef frenchContentNodeRef = createContent(); NodeRef japaneseContentNodeRef = createContent(); // Add to container - NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); - multilingualContentService.addTranslation(frenchContentNodeRef, mlContainerNodeRef, Locale.FRENCH); - multilingualContentService.addTranslation(japaneseContentNodeRef, mlContainerNodeRef, Locale.JAPANESE); + multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); + multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH); + multilingualContentService.addTranslation(japaneseContentNodeRef, chineseContentNodeRef, Locale.JAPANESE); + + NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef); // Check the container child count assertEquals("Incorrect number of child nodes", 3, nodeService.getChildAssocs(mlContainerNodeRef).size()); @@ -290,4 +282,64 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest int count = translationsByLocale.size(); } } + + public void testGetTranslationContainerPermissions() throws Exception + { + // Grant the guest user rights to our working folder + PermissionService permissionService = serviceRegistry.getPermissionService(); + AuthenticationComponent authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent"); + permissionService.setPermission( + folderNodeRef, + PermissionService.GUEST_AUTHORITY, + PermissionService.ALL_PERMISSIONS, + true); + // Get the current authentication + Authentication authentication = authenticationComponent.getCurrentAuthentication(); + try + { + authenticationComponent.setGuestUserAsCurrentUser(); + // Create some documents + NodeRef chineseContentNodeRef = createContent(); + // Make a translation + multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); + multilingualContentService.getTranslationContainer(chineseContentNodeRef); + } + finally + { + try { authenticationComponent.setCurrentAuthentication(authentication); } catch (Throwable e) {} + } + } + + /** + * Check whether non-admin users can take part in ML document manipulation + */ + public void testPermissions() throws Exception + { + // Grant the guest user rights to our working folder + PermissionService permissionService = serviceRegistry.getPermissionService(); + AuthenticationComponent authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent"); + permissionService.setPermission( + folderNodeRef, + PermissionService.GUEST_AUTHORITY, + PermissionService.ALL_PERMISSIONS, + true); + // Get the current authentication + Authentication authentication = authenticationComponent.getCurrentAuthentication(); + try + { + authenticationComponent.setGuestUserAsCurrentUser(); + // Create some documents + NodeRef chineseContentNodeRef = createContent(); + NodeRef frenchContentNodeRef = createContent(); + // Do ML work + multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); + multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH); + multilingualContentService.addEmptyTranslation(chineseContentNodeRef, null, Locale.JAPANESE); + multilingualContentService.createEdition(chineseContentNodeRef); + } + finally + { + try { authenticationComponent.setCurrentAuthentication(authentication); } catch (Throwable e) {} + } + } } diff --git a/source/java/org/alfresco/repo/model/ml/tools/MultilingualDocumentAspectTest.java b/source/java/org/alfresco/repo/model/ml/tools/MultilingualDocumentAspectTest.java index f41d43778a..fd64cbde97 100644 --- a/source/java/org/alfresco/repo/model/ml/tools/MultilingualDocumentAspectTest.java +++ b/source/java/org/alfresco/repo/model/ml/tools/MultilingualDocumentAspectTest.java @@ -44,7 +44,8 @@ public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCase public void testCopy() throws Exception { NodeRef original = createContent(); - NodeRef mlContainer = multilingualContentService.makeTranslation(original, Locale.FRENCH); + multilingualContentService.makeTranslation(original, Locale.FRENCH); + NodeRef mlContainer = multilingualContentService.getTranslationContainer(original); NodeRef copy = fileFolderService.copy(original, nodeService.getPrimaryParent(original).getParentRef(), "COPY" + System.currentTimeMillis()).getNodeRef(); @@ -67,7 +68,7 @@ public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCase NodeRef parent = nodeService.getPrimaryParent(trad1).getParentRef(); - NodeRef mlContainer = multilingualContentService.makeTranslation(trad1, Locale.FRENCH); + multilingualContentService.makeTranslation(trad1, Locale.FRENCH); multilingualContentService.addTranslation(trad2, trad1, Locale.GERMAN); multilingualContentService.addTranslation(trad3, trad1, Locale.ITALIAN); @@ -76,7 +77,7 @@ public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCase // Ensure that the deleted node is romoved from its space assertEquals("The deleted node must be removed to the space", 2, nodeService.getChildAssocs(parent).size()); // Ensure that the mlContainer doesn't keep an association to the deleted node - assertEquals("The deleted node must be removed to the child associations of the mlContainer", 2, multilingualContentService.getTranslations(mlContainer).size()); + assertEquals("The deleted node must be removed to the child associations of the mlContainer", 2, multilingualContentService.getTranslations(trad1).size()); // retore the deleted node NodeRef restoredNode = nodeArchiveService.restoreArchivedNode(nodeArchiveService.getArchivedNode(trad3)).getRestoredNodeRef(); @@ -84,21 +85,17 @@ public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCase // Ensure that the restored node is restored to it s original space assertEquals("The restored node must be restaured to the the space", 3, nodeService.getChildAssocs(parent).size()); // Ensure that the restored node is not linked to the mlContainer - assertEquals("The restored node would not be restaured to the mlContainer", 2, multilingualContentService.getTranslations(mlContainer).size()); + assertEquals("The restored node would not be restaured to the mlContainer", 2, multilingualContentService.getTranslations(trad1).size()); // Ensure that the restored node doesn't keep the mlDocument aspect assertFalse("The restored node can't keep the multilingual aspect", nodeService.hasAspect(restoredNode, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT)); -// DH: The locale is stored on an aspect that is independent of the ML model. -// It is therefore not possible to remove the locale just because the node -// is being unhooked from the ML structures -// // Ensure that the restored node doesn't keep the locale property -// assertNull("The restaured node can't keep the locale property", nodeService.getProperty(restoredNode, ContentModel.PROP_LOCALE)); } public void testDeletePivot() throws Exception { NodeRef pivot = createContent(); NodeRef trans1 = createContent(); - NodeRef mlContainer = multilingualContentService.makeTranslation(pivot, Locale.FRENCH); + multilingualContentService.makeTranslation(pivot, Locale.FRENCH); + NodeRef mlContainer = multilingualContentService.getTranslationContainer(pivot); multilingualContentService.addTranslation(trans1, pivot, Locale.KOREAN); //nodeService.deleteNode(trans1); @@ -112,16 +109,13 @@ public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCase assertTrue("The last translation would not be removed", nodeService.exists(trans1)); // Ensure that trans1 has no mlDocument aspect assertFalse("The last translation can't keep the multilingual aspect", nodeService.hasAspect(trans1, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT)); -// DH: Here too, the sys:locale property must be left alone as it is independent of the -// ML model -// // Ensure that trans1 has no locale propety -// assertNull("The last translation can't keep the locale property", nodeService.getProperty(trans1, ContentModel.PROP_LOCALE)); } public void testDeleteLastNode() throws Exception { NodeRef pivot = createContent(); - NodeRef mlContainer = multilingualContentService.makeTranslation(pivot, Locale.FRENCH); + multilingualContentService.makeTranslation(pivot, Locale.FRENCH); + NodeRef mlContainer = multilingualContentService.getTranslationContainer(pivot); nodeService.deleteNode(pivot); @@ -139,7 +133,8 @@ public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCase { NodeRef pivot = createContent(); NodeRef trans1 = createContent(); - NodeRef mlContainer = multilingualContentService.makeTranslation(pivot, Locale.FRENCH); + multilingualContentService.makeTranslation(pivot, Locale.FRENCH); + NodeRef mlContainer = multilingualContentService.getTranslationContainer(pivot); multilingualContentService.addTranslation(trans1, pivot, Locale.KOREAN); // modify the locale for the translation diff --git a/source/java/org/alfresco/repo/version/VersionableAspect.java b/source/java/org/alfresco/repo/version/VersionableAspect.java index 20b5d7360d..e9f155b311 100644 --- a/source/java/org/alfresco/repo/version/VersionableAspect.java +++ b/source/java/org/alfresco/repo/version/VersionableAspect.java @@ -198,7 +198,8 @@ public class VersionableAspect implements ContentServicePolicies.OnContentUpdate if (initialVersion == true) { - Map versionedNodeRefs = (Map)AlfrescoTransactionSupport.getResource(KEY_VERSIONED_NODEREFS); + @SuppressWarnings("unchecked") + Map versionedNodeRefs = (Map) AlfrescoTransactionSupport.getResource(KEY_VERSIONED_NODEREFS); if (versionedNodeRefs == null || versionedNodeRefs.containsKey(nodeRef) == false) { // Queue create version action diff --git a/source/java/org/alfresco/service/cmr/ml/MultilingualContentService.java b/source/java/org/alfresco/service/cmr/ml/MultilingualContentService.java index 8e9082188d..68be4dcee3 100644 --- a/source/java/org/alfresco/service/cmr/ml/MultilingualContentService.java +++ b/source/java/org/alfresco/service/cmr/ml/MultilingualContentService.java @@ -42,16 +42,6 @@ import org.alfresco.service.cmr.repository.NodeRef; @PublicService public interface MultilingualContentService { - /** - * Rename an existing sys:localized by adding locale suffixes to the base name. - * Where there are name clashes with existing documents, a numerical naming scheme will be - * adopted. - * - * @param localizedNodeRef An existing sys:localized - */ - @Auditable(key = Auditable.Key.ARG_0, parameters = {"localizedNodeRef"}) - void renameWithMLExtension(NodeRef localizedNodeRef); - /** * Checks whether an existing document is part of a translation group. * @@ -66,12 +56,11 @@ public interface MultilingualContentService * creating a cm:mlContainer parent. If it is already a translation, then nothing is done. * * @param contentNodeRef An existing cm:content - * @return Returns the cm:mlContainer translation parent * * @see org.alfresco.model.ContentModel#ASPECT_MULTILINGUAL_DOCUMENT */ @Auditable(key = Auditable.Key.ARG_0, parameters = {"contentNodeRef", "locale"}) - NodeRef makeTranslation(NodeRef contentNodeRef, Locale locale); + void makeTranslation(NodeRef contentNodeRef, Locale locale); /** * Removes the node from any associated translations. If the translation is the @@ -87,14 +76,15 @@ public interface MultilingualContentService * as necessary. * * @param newTranslationNodeRef An existing cm:content - * @param translationOfNodeRef An existing cm:mlDocument or cm:mlContainer - * @return Returns the cm:mlContainer translation parent + * @param translationOfNodeRef An existing cm:mlDocument */ @Auditable(key = Auditable.Key.ARG_0, parameters = {"newTranslationNodeRef", "translationOfNodeRef", "locale"}) - NodeRef addTranslation(NodeRef newTranslationNodeRef, NodeRef translationOfNodeRef, Locale locale); + void addTranslation(NodeRef newTranslationNodeRef, NodeRef translationOfNodeRef, Locale locale); /** + * Convenience method for super user. * + * @param translationNodeRef An existing cm:mlDocument * @return Returns the cm:mlContainer translation parent */ @Auditable(key = Auditable.Key.ARG_0, parameters = {"translationNodeRef"}) @@ -139,12 +129,12 @@ public interface MultilingualContentService /** - * Given cm:mlDocument or a cm:mlContainer, this node returns each - * locale that the node hasn't a translation yet. + * Given a cm:mlDocument or cm:mlContainer this node returns each locale for + * which there isn't a translation. * - * @param localizedNodeRef the cm:mlDocument or the cm:mlContainer - * @param addThisNodeLocale if true, add the locale of the given cm:mlDocument in the list. - * @return + * @param localizedNodeRef the cm:mlDocument or cm:mlContainer + * @param addThisNodeLocale if true, add the locale of the given cm:mlDocument in the list. + * @return Returns a list of missng locales */ @Auditable(key = Auditable.Key.ARG_0, parameters = {"localizedNodeRef", "addThisNodeLocale"}) List getMissingTranslations(NodeRef localizedNodeRef, boolean addThisNodeLocale); @@ -155,7 +145,8 @@ public interface MultilingualContentService * for the translations is stored on the parent, and the child that has the same locale is the * pivot translation. * - * @param nodeRef a cm:mlDocument + * @param nodeRef a cm:mlDocument translation or cm:mlContainer translation + * container * @return Returns a corresponding cm:mlDocument that matches the locale of * of the cm:mlContainer. null is returned if there is no * pivot translation. @@ -174,7 +165,7 @@ public interface MultilingualContentService *

* The necessary translation structures will be created as necessary. * - * @param translationOfNodeRef An existing cm:mlDocument or cm:mlContainer + * @param translationOfNodeRef An existing cm:mlDocument * @param name The name of the file to create, or null to use * the default naming convention. * @return Returns the new created cm:mlEmptyTranslation