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
This commit is contained in:
Derek Hulley
2007-05-31 03:42:59 +00:00
parent cc2705ef49
commit e07a0a4c4b
11 changed files with 191 additions and 137 deletions

View File

@@ -76,6 +76,9 @@
<property name="versionService"> <property name="versionService">
<ref bean="versionService" /> <ref bean="versionService" />
</property> </property>
<property name="permissionService">
<ref bean="permissionService" />
</property>
<property name="contentFilterLanguagesService"> <property name="contentFilterLanguagesService">
<ref bean="contentFilterLanguagesService" /> <ref bean="contentFilterLanguagesService" />
</property> </property>

View File

@@ -532,18 +532,17 @@
<property name="afterInvocationManager"><ref local="afterInvocationManager"/></property> <property name="afterInvocationManager"><ref local="afterInvocationManager"/></property>
<property name="objectDefinitionSource"> <property name="objectDefinitionSource">
<value> <value>
org.alfresco.service.cmr.ml.MultilingualContentService.getTranslationContainer=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 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 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.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.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.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.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.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.createEdition=ACL_NODE.0.sys:base.Write
org.alfresco.service.cmr.ml.MultilingualContentService.renameWithMLExtension=ACL_NODE.0.sys:base.Write
</value> </value>
</property> </property>
</bean> </bean>

View File

@@ -52,6 +52,10 @@ import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.util.BaseSpringTest; import org.alfresco.util.BaseSpringTest;
/**
* @author Andy Hind
*/
@SuppressWarnings("unused")
public class AuditServiceTest extends BaseSpringTest public class AuditServiceTest extends BaseSpringTest
{ {

View File

@@ -212,20 +212,30 @@ public class ContentFilterLanguagesMap implements ContentFilterLanguagesService
String value = langElem.getValue(); String value = langElem.getValue();
String def = langElem.getAttribute(ATTR_DEFAULT); String def = langElem.getAttribute(ATTR_DEFAULT);
orderedLangCodes.add(code);
languagesByCode.put(code, value); languagesByCode.put(code, value);
if(def != null && Boolean.parseBoolean(def)) boolean isDefault = (def != null && Boolean.parseBoolean(def));
if(isDefault)
{ {
if(defaultLanguage != null) 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 // make the collections read-only
this.orderedLangCodes = Collections.unmodifiableList(this.orderedLangCodes); this.orderedLangCodes = Collections.unmodifiableList(this.orderedLangCodes);

View File

@@ -48,6 +48,7 @@ import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchParameters; import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService; 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.Version;
import org.alfresco.service.cmr.version.VersionService; import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
@@ -85,6 +86,7 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
private NodeService nodeService; private NodeService nodeService;
private SearchService searchService; private SearchService searchService;
private VersionService versionService; private VersionService versionService;
private PermissionService permissionService;
private SearchParameters searchParametersMLRoot; private SearchParameters searchParametersMLRoot;
private ContentFilterLanguagesService contentFilterLanguagesService; private ContentFilterLanguagesService contentFilterLanguagesService;
private FileFolderService fileFolderService; private FileFolderService fileFolderService;
@@ -133,13 +135,30 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
{ {
NodeRef mlContainerRootNodeRef = getMLContainerRoot(); NodeRef mlContainerRootNodeRef = getMLContainerRoot();
// Create the container // 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( ChildAssociationRef assocRef = nodeService.createNode(
mlContainerRootNodeRef, mlContainerRootNodeRef,
ContentModel.ASSOC_CHILDREN, ContentModel.ASSOC_CHILDREN,
QNAME_ML_CONTAINER, QNAME_ML_CONTAINER,
ContentModel.TYPE_MULTILINGUAL_CONTAINER); ContentModel.TYPE_MULTILINGUAL_CONTAINER,
// done versionProperties);
return assocRef.getChildRef(); 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(); PropertyMap properties = new PropertyMap();
properties.put(ContentModel.PROP_LOCALE, locale); 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 else
{ {
@@ -341,7 +361,7 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
} }
/** @inheritDoc */ /** @inheritDoc */
public NodeRef makeTranslation(NodeRef contentNodeRef, Locale locale) public void makeTranslation(NodeRef contentNodeRef, Locale locale)
{ {
NodeRef mlContainerNodeRef = makeTranslationImpl(null, contentNodeRef, locale); NodeRef mlContainerNodeRef = makeTranslationImpl(null, contentNodeRef, locale);
// done // done
@@ -352,7 +372,6 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
" locale: " + locale + "\n" + " locale: " + locale + "\n" +
" container: " + mlContainerNodeRef); " container: " + mlContainerNodeRef);
} }
return mlContainerNodeRef;
} }
/** @inheritDoc */ /** @inheritDoc */
@@ -410,32 +429,20 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
} }
/** @inheritDoc */ /** @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 // Get the container
mlContainerNodeRef = getOrCreateMLContainer(translationOfNodeRef, false); NodeRef mlContainerNodeRef = getOrCreateMLContainer(translationOfNodeRef, false);
}
// Use the existing container to make the new content into a translation // Use the existing container to make the new content into a translation
makeTranslationImpl(mlContainerNodeRef, newTranslationNodeRef, locale); makeTranslationImpl(mlContainerNodeRef, newTranslationNodeRef, locale);
// done // done
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Added a translation: \n" + logger.debug("Added a translation: \n" +
" Translation of: " + translationOfNodeRef + " of type " + typeQName + "\n" + " Translation of: " + translationOfNodeRef + "\n" +
" New translation: " + newTranslationNodeRef + "\n" + " New translation: " + newTranslationNodeRef + "\n" +
" Locale: " + locale); " Locale: " + locale);
} }
return mlContainerNodeRef;
} }
/** @inheritDoc */ /** @inheritDoc */
@@ -661,7 +668,7 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
Locale nearestLocale = I18NUtil.getNearestLocale(containerLocale, locales); Locale nearestLocale = I18NUtil.getNearestLocale(containerLocale, locales);
if (nearestLocale == null) if (nearestLocale == null)
{ {
// There is pivot translation // There is no pivot translation
return null; return null;
} }
else else
@@ -675,9 +682,8 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
*/ */
public NodeRef addEmptyTranslation(NodeRef translationOfNodeRef, String name, Locale locale) public NodeRef addEmptyTranslation(NodeRef translationOfNodeRef, String name, Locale locale)
{ {
QName typeQName = nodeService.getType(translationOfNodeRef);
boolean hasMLAspect = nodeService.hasAspect(translationOfNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT); boolean hasMLAspect = nodeService.hasAspect(translationOfNodeRef, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT);
if (hasMLAspect || typeQName.equals(ContentModel.TYPE_MULTILINGUAL_CONTAINER)) if (hasMLAspect)
{ {
// Get the pivot translation // Get the pivot translation
NodeRef pivotTranslationNodeRef = getPivotTranslation(translationOfNodeRef); NodeRef pivotTranslationNodeRef = getPivotTranslation(translationOfNodeRef);
@@ -688,22 +694,13 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
} }
else else
{ {
// We use the given translation, provided it is an actual translation // We use the given 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);
}
} }
} }
else else
{ {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Node must have aspect " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + "Node must have aspect " + ContentModel.ASPECT_MULTILINGUAL_DOCUMENT + ": \n" +
" or be a " + ContentModel.TYPE_MULTILINGUAL_CONTAINER + ": \n" +
" Translation: " + translationOfNodeRef + "\n" + " Translation: " + translationOfNodeRef + "\n" +
" Locale: " + locale); " Locale: " + locale);
} }
@@ -773,7 +770,7 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Added an empty translation: \n" + logger.debug("Added an empty translation: \n" +
" Translation of: " + translationOfNodeRef + " of type " + typeQName + "\n" + " Translation of: " + translationOfNodeRef + "\n" +
" New translation: " + newTranslationNodeRef + "\n" + " New translation: " + newTranslationNodeRef + "\n" +
" Locale: " + locale); " Locale: " + locale);
} }
@@ -796,6 +793,11 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
this.versionService = versionService; this.versionService = versionService;
} }
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
public void setContentFilterLanguagesService(ContentFilterLanguagesService contentFilterLanguagesService) public void setContentFilterLanguagesService(ContentFilterLanguagesService contentFilterLanguagesService)
{ {
this.contentFilterLanguagesService = contentFilterLanguagesService; this.contentFilterLanguagesService = contentFilterLanguagesService;
@@ -805,9 +807,4 @@ public class MultilingualContentServiceImpl implements MultilingualContentServic
{ {
this.fileFolderService = fileFolderService; this.fileFolderService = fileFolderService;
} }
public void renameWithMLExtension(NodeRef translationNodeRef)
{
throw new UnsupportedOperationException();
}
} }

View File

@@ -108,7 +108,8 @@ public class EmptyTranslationAspectTest extends AbstractMultilingualTestCases {
NodeRef empty = null; 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); multilingualContentService.addTranslation(otherTranslation, pivot, Locale.KOREAN);
empty = multilingualContentService.addEmptyTranslation(pivot, "empty_" + System.currentTimeMillis(), Locale.CHINESE); empty = multilingualContentService.addEmptyTranslation(pivot, "empty_" + System.currentTimeMillis(), Locale.CHINESE);

View File

@@ -49,7 +49,8 @@ public class MLContainerTypeTest extends AbstractMultilingualTestCases
NodeRef trans3 = createContent(); NodeRef trans3 = createContent();
NodeRef empty = null; 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(trans2, trans1, Locale.GERMAN);
multilingualContentService.addTranslation(trans3, trans1, Locale.ITALIAN); multilingualContentService.addTranslation(trans3, trans1, Locale.ITALIAN);
empty = multilingualContentService.addEmptyTranslation(trans1, "EMPTY_" + System.currentTimeMillis(), Locale.JAPANESE); empty = multilingualContentService.addEmptyTranslation(trans1, "EMPTY_" + System.currentTimeMillis(), Locale.JAPANESE);

View File

@@ -30,11 +30,15 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import net.sf.acegisecurity.Authentication;
import org.alfresco.i18n.I18NUtil; import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel; 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.ContentData;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; 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.Version;
import org.alfresco.service.cmr.version.VersionHistory; import org.alfresco.service.cmr.version.VersionHistory;
@@ -49,45 +53,30 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest
public void testMakeTranslation() throws Exception public void testMakeTranslation() throws Exception
{ {
NodeRef contentNodeRef = createContent(); NodeRef chineseContentNodeRef = createContent();
// Turn the content into a translation with the appropriate structures // 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 // Check it
assertNotNull("Container not created", mlContainerNodeRef); assertNotNull("Container not created", mlContainerNodeRef);
// Check the container child count // Check the container child count
assertEquals("Incorrect number of child nodes", 1, nodeService.getChildAssocs(mlContainerNodeRef).size()); 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 public void testAddTranslationUsingContent() throws Exception
{ {
// Make a container with a single translation // Make a container with a single translation
NodeRef chineseContentNodeRef = createContent(); NodeRef chineseContentNodeRef = createContent();
NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef);
// Create some more content // Create some more content
NodeRef frenchContentNodeRef = createContent(); NodeRef frenchContentNodeRef = createContent();
// Make this a translation of the Chinese // Make this a translation of the Chinese
NodeRef newMLContainerNodeRef = multilingualContentService.addTranslation( multilingualContentService.addTranslation(
frenchContentNodeRef, frenchContentNodeRef,
chineseContentNodeRef, chineseContentNodeRef,
Locale.FRENCH); Locale.FRENCH);
NodeRef newMLContainerNodeRef = multilingualContentService.getTranslationContainer(frenchContentNodeRef);
// Make sure that the original container was used // Make sure that the original container was used
assertEquals("Existing container should have been used", mlContainerNodeRef, newMLContainerNodeRef); assertEquals("Existing container should have been used", mlContainerNodeRef, newMLContainerNodeRef);
// Check the container child count // Check the container child count
@@ -113,9 +102,9 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest
NodeRef nodeRef2 = createContent(); NodeRef nodeRef2 = createContent();
NodeRef nodeRef3 = createContent(); NodeRef nodeRef3 = createContent();
NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(nodeRef1, loc1); multilingualContentService.makeTranslation(nodeRef1, loc1);
List<Locale> missing = multilingualContentService.getMissingTranslations(mlContainerNodeRef, false); List<Locale> missing = multilingualContentService.getMissingTranslations(nodeRef1, 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. " + assertFalse("Missing Translation Size false. " +
@@ -124,13 +113,13 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest
// make sure that the missing language list is correct // make sure that the missing language list is correct
assertFalse("Missing Translation List false. Locale " + loc1 + " found", missing.contains(loc1.toString())); assertFalse("Missing Translation List false. Locale " + loc1 + " found", missing.contains(loc1.toString()));
multilingualContentService.addTranslation(nodeRef2, mlContainerNodeRef, loc2); multilingualContentService.addTranslation(nodeRef2, nodeRef1, loc2);
multilingualContentService.addTranslation(nodeRef3, mlContainerNodeRef, loc3); 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. " + assertFalse("Missing Translation Size false. " +
"Real size : " + missing.size() + ". Normal Size " + (langListSize - 3), missing.size() != (langListSize - 3)); "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 public void testGetTranslationForLocale() throws Exception
{ {
NodeRef chineseContentNodeRef = createContent(); NodeRef chineseContentNodeRef = createContent();
NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
NodeRef frenchContentNodeRef = createContent(); NodeRef frenchContentNodeRef = createContent();
multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH); multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
// Get the chinese translation // Get the chinese translation
assertEquals("Chinese translation should be present", assertEquals("Chinese translation should be present",
chineseContentNodeRef, chineseContentNodeRef,
multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.CHINESE)); multilingualContentService.getTranslationForLocale(chineseContentNodeRef, Locale.CHINESE));
// Get the french translation // Get the french translation
assertEquals("French translation should be present", assertEquals("French translation should be present",
frenchContentNodeRef, frenchContentNodeRef,
multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.FRENCH)); multilingualContentService.getTranslationForLocale(chineseContentNodeRef, Locale.FRENCH));
// The Italian should return the pivot // The Italian should return the pivot
assertEquals("French translation should be present", assertEquals("French translation should be present",
chineseContentNodeRef, chineseContentNodeRef,
multilingualContentService.getTranslationForLocale(mlContainerNodeRef, Locale.ITALIAN)); multilingualContentService.getTranslationForLocale(chineseContentNodeRef, Locale.ITALIAN));
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
public void testGetPivotTranslation() throws Exception public void testGetPivotTranslation() throws Exception
{ {
NodeRef chineseContentNodeRef = createContent(); 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 // make sure that the pivot language is set
assertNotNull("Pivot language not set", nodeService.getProperty(mlContainerNodeRef, ContentModel.PROP_LOCALE)); 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 public void testCreateEmptyTranslation() throws Exception
{ {
NodeRef chineseContentNodeRef = createContent("Document.txt"); NodeRef chineseContentNodeRef = createContent("Document.txt");
NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
// This should use the pivot language // 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 // Ensure that the empty translation is not null
assertNotNull("The creation of the empty document failed ", emptyNodeRef); assertNotNull("The creation of the empty document failed ", emptyNodeRef);
@@ -215,7 +205,7 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest
public void testCreateEmptyTranslationNames() throws Exception public void testCreateEmptyTranslationNames() throws Exception
{ {
NodeRef chineseContentNodeRef = createContent("Document.txt"); NodeRef chineseContentNodeRef = createContent("Document.txt");
NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
NodeRef koreanContentNodeRef = createContent("Document_ko.txt"); NodeRef koreanContentNodeRef = createContent("Document_ko.txt");
multilingualContentService.addTranslation(koreanContentNodeRef, chineseContentNodeRef, Locale.KOREAN); multilingualContentService.addTranslation(koreanContentNodeRef, chineseContentNodeRef, Locale.KOREAN);
// Create with a null name, and off a non-pivot just to be sure // 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); assertEquals("Empty translation name not generated correctly.", "Document_en_CA.txt", nullName);
// Create with the same name // Create with the same name
NodeRef sameNameNodeRef = multilingualContentService.addEmptyTranslation( NodeRef sameNameNodeRef = multilingualContentService.addEmptyTranslation(
mlContainerNodeRef, chineseContentNodeRef,
"Document.txt", "Document.txt",
Locale.CANADA_FRENCH); Locale.CANADA_FRENCH);
String sameName = fileFolderService.getFileInfo(sameNameNodeRef).getName(); String sameName = fileFolderService.getFileInfo(sameNameNodeRef).getName();
assertEquals("Empty translation name not generated correctly.", "Document_fr_CA.txt", sameName); assertEquals("Empty translation name not generated correctly.", "Document_fr_CA.txt", sameName);
// Create with a different name // Create with a different name
NodeRef differentNameNodeRef = multilingualContentService.addEmptyTranslation( NodeRef differentNameNodeRef = multilingualContentService.addEmptyTranslation(
mlContainerNodeRef, chineseContentNodeRef,
"Document2.txt", "Document2.txt",
Locale.JAPANESE); Locale.JAPANESE);
String differentName = fileFolderService.getFileInfo(differentNameNodeRef).getName(); String differentName = fileFolderService.getFileInfo(differentNameNodeRef).getName();
@@ -249,9 +239,11 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest
NodeRef frenchContentNodeRef = createContent(); NodeRef frenchContentNodeRef = createContent();
NodeRef japaneseContentNodeRef = createContent(); NodeRef japaneseContentNodeRef = createContent();
// Add to container // Add to container
NodeRef mlContainerNodeRef = multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE); multilingualContentService.makeTranslation(chineseContentNodeRef, Locale.CHINESE);
multilingualContentService.addTranslation(frenchContentNodeRef, mlContainerNodeRef, Locale.FRENCH); multilingualContentService.addTranslation(frenchContentNodeRef, chineseContentNodeRef, Locale.FRENCH);
multilingualContentService.addTranslation(japaneseContentNodeRef, mlContainerNodeRef, Locale.JAPANESE); multilingualContentService.addTranslation(japaneseContentNodeRef, chineseContentNodeRef, Locale.JAPANESE);
NodeRef mlContainerNodeRef = multilingualContentService.getTranslationContainer(chineseContentNodeRef);
// Check the container child count // Check the container child count
assertEquals("Incorrect number of child nodes", 3, nodeService.getChildAssocs(mlContainerNodeRef).size()); assertEquals("Incorrect number of child nodes", 3, nodeService.getChildAssocs(mlContainerNodeRef).size());
@@ -290,4 +282,64 @@ public class MultilingualContentServiceImplTest extends AbstractMultilingualTest
int count = translationsByLocale.size(); 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) {}
}
}
} }

View File

@@ -44,7 +44,8 @@ public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCase
public void testCopy() throws Exception public void testCopy() throws Exception
{ {
NodeRef original = createContent(); NodeRef original = createContent();
NodeRef mlContainer = multilingualContentService.makeTranslation(original, Locale.FRENCH); multilingualContentService.makeTranslation(original, Locale.FRENCH);
NodeRef mlContainer = multilingualContentService.getTranslationContainer(original);
NodeRef copy = NodeRef copy =
fileFolderService.copy(original, nodeService.getPrimaryParent(original).getParentRef(), "COPY" + System.currentTimeMillis()).getNodeRef(); 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 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(trad2, trad1, Locale.GERMAN);
multilingualContentService.addTranslation(trad3, trad1, Locale.ITALIAN); 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 // 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()); 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 // 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 // retore the deleted node
NodeRef restoredNode = nodeArchiveService.restoreArchivedNode(nodeArchiveService.getArchivedNode(trad3)).getRestoredNodeRef(); 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 // 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()); 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 // 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 // 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)); 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 public void testDeletePivot() throws Exception
{ {
NodeRef pivot = createContent(); NodeRef pivot = createContent();
NodeRef trans1 = 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); multilingualContentService.addTranslation(trans1, pivot, Locale.KOREAN);
//nodeService.deleteNode(trans1); //nodeService.deleteNode(trans1);
@@ -112,16 +109,13 @@ public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCase
assertTrue("The last translation would not be removed", nodeService.exists(trans1)); assertTrue("The last translation would not be removed", nodeService.exists(trans1));
// Ensure that trans1 has no mlDocument aspect // Ensure that trans1 has no mlDocument aspect
assertFalse("The last translation can't keep the multilingual aspect", nodeService.hasAspect(trans1, ContentModel.ASPECT_MULTILINGUAL_DOCUMENT)); 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 public void testDeleteLastNode() throws Exception
{ {
NodeRef pivot = createContent(); NodeRef pivot = createContent();
NodeRef mlContainer = multilingualContentService.makeTranslation(pivot, Locale.FRENCH); multilingualContentService.makeTranslation(pivot, Locale.FRENCH);
NodeRef mlContainer = multilingualContentService.getTranslationContainer(pivot);
nodeService.deleteNode(pivot); nodeService.deleteNode(pivot);
@@ -139,7 +133,8 @@ public class MultilingualDocumentAspectTest extends AbstractMultilingualTestCase
{ {
NodeRef pivot = createContent(); NodeRef pivot = createContent();
NodeRef trans1 = 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); multilingualContentService.addTranslation(trans1, pivot, Locale.KOREAN);
// modify the locale for the translation // modify the locale for the translation

View File

@@ -198,7 +198,8 @@ public class VersionableAspect implements ContentServicePolicies.OnContentUpdate
if (initialVersion == true) if (initialVersion == true)
{ {
Map<NodeRef, NodeRef> versionedNodeRefs = (Map)AlfrescoTransactionSupport.getResource(KEY_VERSIONED_NODEREFS); @SuppressWarnings("unchecked")
Map<NodeRef, NodeRef> versionedNodeRefs = (Map<NodeRef, NodeRef>) AlfrescoTransactionSupport.getResource(KEY_VERSIONED_NODEREFS);
if (versionedNodeRefs == null || versionedNodeRefs.containsKey(nodeRef) == false) if (versionedNodeRefs == null || versionedNodeRefs.containsKey(nodeRef) == false)
{ {
// Queue create version action // Queue create version action

View File

@@ -42,16 +42,6 @@ import org.alfresco.service.cmr.repository.NodeRef;
@PublicService @PublicService
public interface MultilingualContentService public interface MultilingualContentService
{ {
/**
* Rename an existing <b>sys:localized</b> 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 <b>sys:localized</b>
*/
@Auditable(key = Auditable.Key.ARG_0, parameters = {"localizedNodeRef"})
void renameWithMLExtension(NodeRef localizedNodeRef);
/** /**
* Checks whether an existing document is part of a translation group. * Checks whether an existing document is part of a translation group.
* *
@@ -66,12 +56,11 @@ public interface MultilingualContentService
* creating a <b>cm:mlContainer</b> parent. If it is already a translation, then nothing is done. * creating a <b>cm:mlContainer</b> parent. If it is already a translation, then nothing is done.
* *
* @param contentNodeRef An existing <b>cm:content</b> * @param contentNodeRef An existing <b>cm:content</b>
* @return Returns the <b>cm:mlContainer</b> translation parent
* *
* @see org.alfresco.model.ContentModel#ASPECT_MULTILINGUAL_DOCUMENT * @see org.alfresco.model.ContentModel#ASPECT_MULTILINGUAL_DOCUMENT
*/ */
@Auditable(key = Auditable.Key.ARG_0, parameters = {"contentNodeRef", "locale"}) @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 * Removes the node from any associated translations. If the translation is the
@@ -87,14 +76,15 @@ public interface MultilingualContentService
* as necessary. * as necessary.
* *
* @param newTranslationNodeRef An existing <b>cm:content</b> * @param newTranslationNodeRef An existing <b>cm:content</b>
* @param translationOfNodeRef An existing <b>cm:mlDocument</b> or <b>cm:mlContainer</b> * @param translationOfNodeRef An existing <b>cm:mlDocument</b>
* @return Returns the <b>cm:mlContainer</b> translation parent
*/ */
@Auditable(key = Auditable.Key.ARG_0, parameters = {"newTranslationNodeRef", "translationOfNodeRef", "locale"}) @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 <b>cm:mlDocument</b>
* @return Returns the <b>cm:mlContainer</b> translation parent * @return Returns the <b>cm:mlContainer</b> translation parent
*/ */
@Auditable(key = Auditable.Key.ARG_0, parameters = {"translationNodeRef"}) @Auditable(key = Auditable.Key.ARG_0, parameters = {"translationNodeRef"})
@@ -139,12 +129,12 @@ public interface MultilingualContentService
/** /**
* Given <b>cm:mlDocument</b> or a <b>cm:mlContainer</b>, this node returns each * Given a <b>cm:mlDocument</b> or <b>cm:mlContainer</b> this node returns each locale for
* locale that the node hasn't a translation yet. * which there isn't a translation.
* *
* @param localizedNodeRef the <b>cm:mlDocument</b> or the <b>cm:mlContainer</b> * @param localizedNodeRef the <b>cm:mlDocument</b> or <b>cm:mlContainer</b>
* @param addThisNodeLocale if true, add the locale of the given <b>cm:mlDocument</b> in the list. * @param addThisNodeLocale if true, add the locale of the given <b>cm:mlDocument</b> in the list.
* @return * @return Returns a list of missng locales
*/ */
@Auditable(key = Auditable.Key.ARG_0, parameters = {"localizedNodeRef", "addThisNodeLocale"}) @Auditable(key = Auditable.Key.ARG_0, parameters = {"localizedNodeRef", "addThisNodeLocale"})
List<Locale> getMissingTranslations(NodeRef localizedNodeRef, boolean addThisNodeLocale); List<Locale> 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 * for the translations is stored on the parent, and the child that has the same locale is the
* pivot translation. * pivot translation.
* *
* @param nodeRef a <b>cm:mlDocument</b> * @param nodeRef a <b>cm:mlDocument</b> translation or <b>cm:mlContainer</b> translation
* container
* @return Returns a corresponding <b>cm:mlDocument</b> that matches the locale of * @return Returns a corresponding <b>cm:mlDocument</b> that matches the locale of
* of the <b>cm:mlContainer</b>. <tt>null</tt> is returned if there is no * of the <b>cm:mlContainer</b>. <tt>null</tt> is returned if there is no
* pivot translation. * pivot translation.
@@ -174,7 +165,7 @@ public interface MultilingualContentService
* <p/> * <p/>
* The necessary translation structures will be created as necessary. * The necessary translation structures will be created as necessary.
* *
* @param translationOfNodeRef An existing <b>cm:mlDocument</b> or <b>cm:mlContainer</b> * @param translationOfNodeRef An existing <b>cm:mlDocument</b>
* @param name The name of the file to create, or <tt>null</tt> to use * @param name The name of the file to create, or <tt>null</tt> to use
* the default naming convention. * the default naming convention.
* @return Returns the new created <b>cm:mlEmptyTranslation</b> * @return Returns the new created <b>cm:mlEmptyTranslation</b>