Merged BRANCHES/DEV/V4.1-BUG-FIX to HEAD:

43124: Merged BRANCHES/DEV/FEATURES/CLOUD1_DISCUSSIONS to BRANCHES/DEV/V4.1-BUG-FIX:
        43059: CLOUD-864: Use base node ref, instead of tenant specific node ref for building list of replies (ALF-16498)


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@43125 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jan Vonka
2012-10-26 09:30:15 +00:00
parent b794365eaa
commit de47da1766
4 changed files with 233 additions and 13 deletions

View File

@@ -106,9 +106,9 @@
<property name="contentService" ref="ContentService"/> <property name="contentService" ref="ContentService"/>
<property name="taggingService" ref="TaggingService"/> <property name="taggingService" ref="TaggingService"/>
<property name="namespaceService" ref="NamespaceService"/> <property name="namespaceService" ref="NamespaceService"/>
<property name="fileFolderService" ref="FileFolderService"/>
<property name="transactionService" ref="transactionService" /> <property name="transactionService" ref="transactionService" />
<property name="cannedQueryRegistry" ref="discussionCannedQueryRegistry" /> <property name="cannedQueryRegistry" ref="discussionCannedQueryRegistry" />
<property name="tenantService" ref="tenantService"/>
</bean> </bean>
</beans> </beans>

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2011 Alfresco Software Limited. * Copyright (C) 2005-2012 Alfresco Software Limited.
* *
* This file is part of Alfresco * This file is part of Alfresco
* *
@@ -48,11 +48,11 @@ import org.alfresco.repo.query.NodeWithTargetsEntity;
import org.alfresco.repo.query.NodeWithTargetsEntity.TargetAndTypeId; import org.alfresco.repo.query.NodeWithTargetsEntity.TargetAndTypeId;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.site.SiteServiceImpl; import org.alfresco.repo.site.SiteServiceImpl;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.discussion.DiscussionService; import org.alfresco.service.cmr.discussion.DiscussionService;
import org.alfresco.service.cmr.discussion.PostInfo; import org.alfresco.service.cmr.discussion.PostInfo;
import org.alfresco.service.cmr.discussion.PostWithReplies; import org.alfresco.service.cmr.discussion.PostWithReplies;
import org.alfresco.service.cmr.discussion.TopicInfo; import org.alfresco.service.cmr.discussion.TopicInfo;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentService;
@@ -100,9 +100,9 @@ public class DiscussionServiceImpl implements DiscussionService
private ContentService contentService; private ContentService contentService;
private TaggingService taggingService; private TaggingService taggingService;
private NamespaceService namespaceService; private NamespaceService namespaceService;
private FileFolderService fileFolderService;
private TransactionService transactionService; private TransactionService transactionService;
private NamedObjectRegistry<CannedQueryFactory<? extends Object>> cannedQueryRegistry; private NamedObjectRegistry<CannedQueryFactory<? extends Object>> cannedQueryRegistry;
private TenantService tenantService;
public void setNodeDAO(NodeDAO nodeDAO) public void setNodeDAO(NodeDAO nodeDAO)
{ {
@@ -139,11 +139,6 @@ public class DiscussionServiceImpl implements DiscussionService
this.namespaceService = namespaceService; this.namespaceService = namespaceService;
} }
public void setFileFolderService(FileFolderService fileFolderService)
{
this.fileFolderService = fileFolderService;
}
public void setTransactionService(TransactionService transactionService) public void setTransactionService(TransactionService transactionService)
{ {
this.transactionService = transactionService; this.transactionService = transactionService;
@@ -157,6 +152,14 @@ public class DiscussionServiceImpl implements DiscussionService
this.cannedQueryRegistry = cannedQueryRegistry; this.cannedQueryRegistry = cannedQueryRegistry;
} }
/**
* Set the {@link TenantService}
*/
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
/** /**
* Fetches the Discussions Container on a site, creating as required if requested. * Fetches the Discussions Container on a site, creating as required if requested.
*/ */
@@ -832,6 +835,7 @@ public class DiscussionServiceImpl implements DiscussionService
// References a node outside of this topic // References a node outside of this topic
continue; continue;
} }
nodeRef = tenantService.getBaseName(nodeRef);
if (id.equals(e.getId())) if (id.equals(e.getId()))
{ {
// Self reference // Self reference

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2011 Alfresco Software Limited. * Copyright (C) 2005-2012 Alfresco Software Limited.
* *
* This file is part of Alfresco * This file is part of Alfresco
* *
@@ -34,7 +34,11 @@ import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults; import org.alfresco.query.PagingResults;
import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.site.SiteModel; import org.alfresco.repo.site.SiteModel;
import org.alfresco.repo.tenant.TenantAdminService;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork;
import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
@@ -53,7 +57,6 @@ import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.service.cmr.site.SiteVisibility; import org.alfresco.service.cmr.site.SiteVisibility;
import org.alfresco.service.cmr.tagging.TaggingService; import org.alfresco.service.cmr.tagging.TaggingService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.Pair; import org.alfresco.util.Pair;
import org.alfresco.util.PropertyMap; import org.alfresco.util.PropertyMap;
@@ -86,16 +89,21 @@ public class DiscussionServiceImplTest
private static NodeService PUBLIC_NODE_SERVICE; private static NodeService PUBLIC_NODE_SERVICE;
private static PersonService PERSON_SERVICE; private static PersonService PERSON_SERVICE;
private static RetryingTransactionHelper TRANSACTION_HELPER; private static RetryingTransactionHelper TRANSACTION_HELPER;
private static TransactionService TRANSACTION_SERVICE;
private static PermissionService PERMISSION_SERVICE; private static PermissionService PERMISSION_SERVICE;
private static SiteService SITE_SERVICE; private static SiteService SITE_SERVICE;
private static TaggingService TAGGING_SERVICE; private static TaggingService TAGGING_SERVICE;
private static TenantAdminService TENANT_ADMIN_SERVICE;
private static final String TEST_USER = DiscussionServiceImplTest.class.getSimpleName() + "_testuser"; private static final String TEST_USER = DiscussionServiceImplTest.class.getSimpleName() + "_testuser";
private static final String ADMIN_USER = AuthenticationUtil.getAdminUserName(); private static final String ADMIN_USER = AuthenticationUtil.getAdminUserName();
private static final String TENANT_DOMAIN = (DiscussionServiceImplTest.class.getSimpleName() + "Tenant").toLowerCase();
private static final String TENANT_ADMIN_USER = ADMIN_USER + "@" + TENANT_DOMAIN;
private static final String TENANT_TEST_USER = TEST_USER + "@" + TENANT_DOMAIN;
private static SiteInfo DISCUSSION_SITE; private static SiteInfo DISCUSSION_SITE;
private static SiteInfo ALTERNATE_DISCUSSION_SITE; private static SiteInfo ALTERNATE_DISCUSSION_SITE;
private static SiteInfo TENANT_DISCUSSION_SITE;
private static NodeRef FORUM_NODE; private static NodeRef FORUM_NODE;
/** /**
@@ -117,10 +125,12 @@ public class DiscussionServiceImplTest
PUBLIC_NODE_SERVICE = (NodeService)testContext.getBean("NodeService"); PUBLIC_NODE_SERVICE = (NodeService)testContext.getBean("NodeService");
PERSON_SERVICE = (PersonService)testContext.getBean("personService"); PERSON_SERVICE = (PersonService)testContext.getBean("personService");
TRANSACTION_HELPER = (RetryingTransactionHelper)testContext.getBean("retryingTransactionHelper"); TRANSACTION_HELPER = (RetryingTransactionHelper)testContext.getBean("retryingTransactionHelper");
TRANSACTION_SERVICE = (TransactionService)testContext.getBean("TransactionService");
PERMISSION_SERVICE = (PermissionService)testContext.getBean("permissionService"); PERMISSION_SERVICE = (PermissionService)testContext.getBean("permissionService");
SITE_SERVICE = (SiteService)testContext.getBean("siteService"); SITE_SERVICE = (SiteService)testContext.getBean("siteService");
TAGGING_SERVICE = (TaggingService)testContext.getBean("TaggingService"); TAGGING_SERVICE = (TaggingService)testContext.getBean("TaggingService");
TENANT_ADMIN_SERVICE = testContext.getBean("tenantAdminService", TenantAdminService.class);
createTenantAndTestSites();
// Do the setup as admin // Do the setup as admin
AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER); AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER);
@@ -381,6 +391,99 @@ public class DiscussionServiceImplTest
} }
} }
@Test
public void tenantCreateNewTopicAndPostAndReply() throws Exception
{
TenantUtil.runAsUserTenant(new TenantRunAsWork<Object>(){
@Override
public Object doWork() throws Exception
{
TopicInfo siteTopic;
PostInfo post;
PostInfo reply1;
// Nothing to start with
PagingResults<TopicInfo> results = DISCUSSION_SERVICE.listTopics(TENANT_DISCUSSION_SITE.getShortName(), true, new PagingRequest(10));
assertEquals(0, results.getPage().size());
// Create two topics, one node and one site based
siteTopic = DISCUSSION_SERVICE.createTopic(TENANT_DISCUSSION_SITE.getShortName(),
"Site Title");
testNodesToTidy.add(siteTopic.getNodeRef());
// There are no posts to start with
PagingResults<PostInfo> posts = DISCUSSION_SERVICE.listPosts(siteTopic, new PagingRequest(10));
assertEquals(0, posts.getPage().size());
// The topic has no primary post
assertEquals(null, DISCUSSION_SERVICE.getPrimaryPost(siteTopic));
// Which means no recent post
assertEquals(null, DISCUSSION_SERVICE.getMostRecentPost(siteTopic));
// Create the first post
String contents = "This Is Some Content";
post = DISCUSSION_SERVICE.createPost(siteTopic, contents);
// Ensure it got a NodeRef, a Name and the Topic
assertNotNull(post.getNodeRef());
assertNotNull(post.getSystemName());
assertEquals(siteTopic, post.getTopic());
// Ensure it shares a name with the topic
assertEquals(siteTopic.getSystemName(), post.getSystemName());
// As this is the primary post, it'll share the topic title
assertEquals(siteTopic.getTitle(), post.getTitle());
// It will have contents and a creator
assertEquals(contents, post.getContents());
// Fetch and check
post = DISCUSSION_SERVICE.getPost(siteTopic, post.getSystemName());
assertNotNull(post.getNodeRef());
assertNotNull(post.getSystemName());
assertEquals(siteTopic, post.getTopic());
assertEquals(siteTopic.getTitle(), post.getTitle());
assertEquals(contents, post.getContents());
// Topic will now have a primary post
assertNotNull(DISCUSSION_SERVICE.getPrimaryPost(siteTopic));
assertEquals(post.getNodeRef(), DISCUSSION_SERVICE.getPrimaryPost(siteTopic).getNodeRef());
// Topic will now have one post listed
posts = DISCUSSION_SERVICE.listPosts(siteTopic, new PagingRequest(10));
assertEquals(1, posts.getPage().size());
// Add a reply
String reply1Contents = "Reply Contents";
reply1 = DISCUSSION_SERVICE.createReply(post, reply1Contents);
assertNotNull(reply1.getNodeRef());
assertNotNull(reply1.getSystemName());
assertEquals(siteTopic, reply1.getTopic());
assertEquals(null, reply1.getTitle()); // No title by default for
// replies
assertEquals(reply1Contents, reply1.getContents());
// Fetch and check
PostWithReplies postWithReplies = DISCUSSION_SERVICE.listPostReplies(siteTopic, 1);
assertNotNull(postWithReplies);
assertEquals(1, postWithReplies.getReplies().size());
PostInfo reply2 = postWithReplies.getReplies().get(0).getPost();
assertNotNull(reply2.getNodeRef());
assertNotNull(reply2.getSystemName());
assertEquals(siteTopic, reply2.getTopic());
assertEquals(null, reply2.getTitle()); // No title by default for
// replies
assertEquals(reply1Contents, reply1.getContents());
return null;
}
}, TENANT_TEST_USER, TENANT_DOMAIN);
}
@Test public void createUpdateDeleteEntries() throws Exception @Test public void createUpdateDeleteEntries() throws Exception
{ {
TopicInfo siteTopic; TopicInfo siteTopic;
@@ -1848,6 +1951,84 @@ public class DiscussionServiceImplTest
AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER); AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER);
} }
private static void createTenantAndTestSites()
{
AuthenticationUtil.runAs(new RunAsWork<Object>(){
@Override
public Object doWork() throws Exception
{
createTenant();
return null;
}
}, ADMIN_USER);
createTenantUser();
TenantUtil.runAsUserTenant(new TenantRunAsWork<Object>() {
@Override
public Object doWork() throws Exception
{
createTenantTestSites();
return null;
}
}, TENANT_TEST_USER, TENANT_DOMAIN);
}
private static void createTenantTestSites() throws Exception
{
final DiscussionServiceImpl privateDiscussionService = (DiscussionServiceImpl)testContext.getBean("discussionService");
TENANT_DISCUSSION_SITE = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<SiteInfo>()
{
@Override
public SiteInfo execute() throws Throwable
{
SiteInfo site = SITE_SERVICE.createSite(
TEST_SITE_PREFIX,
DiscussionServiceImplTest.class.getSimpleName() + "_testSite" + System.currentTimeMillis(),
"test site title", "test site description",
SiteVisibility.PUBLIC);
privateDiscussionService.getSiteDiscussionsContainer(site.getShortName(), true);
CLASS_TEST_NODES_TO_TIDY.add(site.getNodeRef());
return site;
}
});
}
private static void createTenant()
{
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
if (!TENANT_ADMIN_SERVICE.existsTenant(TENANT_DOMAIN))
{
TENANT_ADMIN_SERVICE.createTenant(TENANT_DOMAIN, "password".toCharArray());
}
return null;
}
});
}
private static void createTenantUser()
{
TenantUtil.runAsUserTenant(new TenantRunAsWork<Object>(){
@Override
public Object doWork() throws Exception
{
createUser(TENANT_TEST_USER);
return null;
}
}, TENANT_ADMIN_USER, TENANT_DOMAIN);
}
/** /**
* By default, all tests are run as the admin user. * By default, all tests are run as the admin user.
*/ */
@@ -1865,6 +2046,21 @@ public class DiscussionServiceImplTest
{ {
performDeletionOfNodes(CLASS_TEST_NODES_TO_TIDY); performDeletionOfNodes(CLASS_TEST_NODES_TO_TIDY);
deleteUser(TEST_USER); deleteUser(TEST_USER);
deleteUser(TENANT_TEST_USER);
deleteTenant();
}
private static void deleteTenant()
{
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
TENANT_ADMIN_SERVICE.deleteTenant(TENANT_DOMAIN);
return null;
}
});
} }
/** /**

View File

@@ -72,6 +72,26 @@ public class TenantUtil
} }
} }
/**
* Execute a unit of work in a given tenant context. The thread's tenant context will be returned to its normal state
* after the call.
*
* @param runAsWork the unit of work to do
* @param uid the user ID
* @param tenanDomain the tenant domain
* @return Returns the work's return value
*/
public static <R> R runAsUserTenant(final TenantRunAsWork<R> runAsWork, final String uid, final String tenantDomain)
{
return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<R>()
{
public R doWork()
{
return runAsTenant(runAsWork, tenantDomain);
}
}, uid);
}
/** /**
* Execute a unit of work in a given tenant context. The thread's tenant context will be returned to its normal state * Execute a unit of work in a given tenant context. The thread's tenant context will be returned to its normal state
* after the call. * after the call.