diff --git a/config/alfresco/model-specific-services-context.xml b/config/alfresco/model-specific-services-context.xml index b8f3aa9843..5e158b9972 100644 --- a/config/alfresco/model-specific-services-context.xml +++ b/config/alfresco/model-specific-services-context.xml @@ -12,6 +12,9 @@ + + + @@ -138,6 +141,7 @@ + diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties index cc0652f703..5d14818439 100644 --- a/config/alfresco/repository.properties +++ b/config/alfresco/repository.properties @@ -816,3 +816,4 @@ system.content.caching.maxFileSizeMB=0 mybatis.useLocalCaches=false +fileFolderService.checkHidden.enabled=true \ No newline at end of file diff --git a/source/java/org/alfresco/repo/importer/ImporterComponent.java b/source/java/org/alfresco/repo/importer/ImporterComponent.java index ab05b7215f..cd39800726 100644 --- a/source/java/org/alfresco/repo/importer/ImporterComponent.java +++ b/source/java/org/alfresco/repo/importer/ImporterComponent.java @@ -619,7 +619,7 @@ public class ImporterComponent } // check whether the node should be hidden - hiddenAspect.checkHidden(nodeRef); + hiddenAspect.checkHidden(nodeRef, false); // import content, if applicable for (Map.Entry property : context.getProperties().entrySet()) diff --git a/source/java/org/alfresco/repo/model/filefolder/FilenameFilteringInterceptor.java b/source/java/org/alfresco/repo/model/filefolder/FilenameFilteringInterceptor.java index c18be8db43..983b9ea3dc 100644 --- a/source/java/org/alfresco/repo/model/filefolder/FilenameFilteringInterceptor.java +++ b/source/java/org/alfresco/repo/model/filefolder/FilenameFilteringInterceptor.java @@ -53,6 +53,7 @@ public class FilenameFilteringInterceptor implements MethodInterceptor private PatternFilter temporaryFiles; private PatternFilter systemPaths; private HiddenAspect hiddenAspect; + private boolean enabled = true; public FilenameFilteringInterceptor() { @@ -72,6 +73,11 @@ public class FilenameFilteringInterceptor implements MethodInterceptor this.hiddenAspect = hiddenAspect; } + public void setEnabled(boolean enabled) + { + this.enabled = enabled; + } + /** * A list of regular expressions that represent patterns of system paths. * @@ -192,74 +198,81 @@ public class FilenameFilteringInterceptor implements MethodInterceptor String methodName = invocation.getMethod().getName(); Object ret = null; - // do the invocation - if (methodName.startsWith("create")) + if(enabled) { - NodeRef nodeRef = (NodeRef)invocation.getArguments()[0]; - String filename = (String)invocation.getArguments()[1]; - - if(getMode() == Mode.ENHANCED) - { - if(systemPaths.isFiltered(filename)) - { - // it's a system file/folder, create as system and allow full control to all authorities - ret = runAsSystem(invocation); - FileInfoImpl fileInfo = (FileInfoImpl)ret; - permissionService.setPermission(fileInfo.getNodeRef(), PermissionService.ALL_AUTHORITIES, PermissionService.FULL_CONTROL, true); - - // it's always marked temporary and hidden - checkTemporaryAspect(true, fileInfo); - hiddenAspect.hideNode(fileInfo, getSystemFileVisibilityMask()); - } - else - { - // it's not a temporary file/folder, create as normal - ret = invocation.proceed(); - - FileInfoImpl fileInfo = (FileInfoImpl)ret; - - if(isSystemPath(nodeRef, filename)) - { - // it's on a system path, check whether temporary, hidden and noindex aspects need to be applied - checkTemporaryAspect(true, fileInfo); - hiddenAspect.hideNode(fileInfo, getSystemFileVisibilityMask()); - } - else - { - // check whether it's a temporary or hidden file - checkTemporaryAspect(temporaryFiles.isFiltered(filename), (FileInfo)ret); - hiddenAspect.checkHidden(fileInfo); - } - } + // do the invocation + if (methodName.startsWith("create")) + { + NodeRef nodeRef = (NodeRef)invocation.getArguments()[0]; + String filename = (String)invocation.getArguments()[1]; + + if(getMode() == Mode.ENHANCED) + { + if(systemPaths.isFiltered(filename)) + { + // it's a system file/folder, create as system and allow full control to all authorities + ret = runAsSystem(invocation); + FileInfoImpl fileInfo = (FileInfoImpl)ret; + permissionService.setPermission(fileInfo.getNodeRef(), PermissionService.ALL_AUTHORITIES, PermissionService.FULL_CONTROL, true); + + // it's always marked temporary and hidden + checkTemporaryAspect(true, fileInfo); + hiddenAspect.hideNode(fileInfo, getSystemFileVisibilityMask()); + } + else + { + // it's not a temporary file/folder, create as normal + ret = invocation.proceed(); + + FileInfoImpl fileInfo = (FileInfoImpl)ret; + + if(isSystemPath(nodeRef, filename)) + { + // it's on a system path, check whether temporary, hidden and noindex aspects need to be applied + checkTemporaryAspect(true, fileInfo); + hiddenAspect.hideNode(fileInfo, getSystemFileVisibilityMask()); + } + else + { + // check whether it's a temporary or hidden file + checkTemporaryAspect(temporaryFiles.isFiltered(filename), (FileInfo)ret); + hiddenAspect.checkHidden(fileInfo, false); + } + } + } + else + { + ret = invocation.proceed(); + + FileInfoImpl fileInfo = (FileInfoImpl)ret; + + checkTemporaryAspect(temporaryFiles.isFiltered(filename), fileInfo); + } + } + else if (methodName.startsWith("rename") || + methodName.startsWith("move") || + methodName.startsWith("copy")) + { + ret = invocation.proceed(); + + FileInfoImpl fileInfo = (FileInfoImpl) ret; + String filename = fileInfo.getName(); + + if (logger.isDebugEnabled()) + { + logger.debug("Checking filename returned by " + methodName + ": " + filename); + } + + // check against all the regular expressions + checkTemporaryAspect(temporaryFiles.isFiltered(filename), fileInfo); + if(getMode() == Mode.ENHANCED) + { + hiddenAspect.checkHidden(fileInfo, true); + } } else { ret = invocation.proceed(); - - FileInfoImpl fileInfo = (FileInfoImpl)ret; - - checkTemporaryAspect(temporaryFiles.isFiltered(filename), fileInfo); - } - } - else if (methodName.startsWith("rename") || - methodName.startsWith("move") || - methodName.startsWith("copy")) - { - ret = invocation.proceed(); - - FileInfoImpl fileInfo = (FileInfoImpl) ret; - String filename = fileInfo.getName(); - - if (logger.isDebugEnabled()) - { - logger.debug("Checking filename returned by " + methodName + ": " + filename); - } - - // check against all the regular expressions - checkTemporaryAspect(temporaryFiles.isFiltered(filename), fileInfo); - if(getMode() == Mode.ENHANCED) - { - hiddenAspect.checkHidden(fileInfo); } } else diff --git a/source/java/org/alfresco/repo/model/filefolder/HiddenAspect.java b/source/java/org/alfresco/repo/model/filefolder/HiddenAspect.java index 6f8f4b84be..54a6c88e3c 100644 --- a/source/java/org/alfresco/repo/model/filefolder/HiddenAspect.java +++ b/source/java/org/alfresco/repo/model/filefolder/HiddenAspect.java @@ -6,15 +6,25 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import org.alfresco.model.ContentModel; +import org.alfresco.query.PagingRequest; +import org.alfresco.query.PagingResults; +import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; +import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.Path; import org.alfresco.service.cmr.repository.Path.Element; +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.namespace.QName; import org.alfresco.util.FileFilterMode.Client; import org.apache.commons.logging.Log; @@ -78,19 +88,31 @@ public class HiddenAspect } }; - private List filters = new ArrayList(10); + private List filters = new ArrayList(10); private NodeService nodeService; + private FileFolderService fileFolderService; + private SearchService searchService; public HiddenAspect() { } - + public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; } + public void setFileFolderService(FileFolderService fileFolderService) + { + this.fileFolderService = fileFolderService; + } + + public void setSearchService(SearchService searchService) + { + this.searchService = searchService; + } + public void setPatterns(List filters) { for(HiddenFileFilter filter : filters) @@ -99,11 +121,49 @@ public class HiddenAspect } } + public List getPatterns() + { + return filters; + } + public Client[] getClients() { return Client.values(); } - + + private ResultSet searchForName(StoreRef storeRef, String name) + { + SearchParameters sp = new SearchParameters(); + sp.addStore(storeRef); + sp.setLanguage("lucene"); + sp.setQuery("@" + LuceneQueryParser.escape(ContentModel.PROP_NAME.toString()) + ":\"" + name + "\""); + sp.addLocale(new Locale("en")); + return searchService.query(sp); + } + + /** + * Searches for nodes in the given store that should be hidden (i.e. match the hidden pattern) + * and hides them if they are not already hidden. + * + * @param storeRef + */ + public void checkHidden(StoreRef storeRef) + { + for(HiddenFileInfo filter : filters) + { + String pattern = filter.getFilter(); + + ResultSet rs = searchForName(storeRef, pattern); + for(NodeRef nodeRef : rs.getNodeRefs()) + { + if(!hasHiddenAspect(nodeRef)) + { + hideNode(nodeRef, filter.getVisibilityMask()); + } + } + } + } + private Integer getClientIndex(Client client) { return client.ordinal(); @@ -177,9 +237,9 @@ public class HiddenAspect private HiddenFileInfo isHidden(String path) { // check against all the filters - HiddenFileInfoImpl matched = null; + HiddenFileInfo matched = null; - for(HiddenFileInfoImpl filter : filters) + for(HiddenFileInfo filter : filters) { if(filter.isHidden(path)) { @@ -191,6 +251,11 @@ public class HiddenAspect return matched; } + private boolean hasHiddenAspect(NodeRef nodeRef) + { + return nodeService.hasAspect(nodeRef, ContentModel.ASPECT_HIDDEN); + } + public int getClientVisibilityMask(Client client, Visibility visibility) { return visibility.getMask() << getClientIndex(client)*2; @@ -202,7 +267,7 @@ public class HiddenAspect * @param nodeRef * @return the matching filter, or null if no match */ - public HiddenFileInfo isHidden(NodeRef nodeRef) + public HiddenFileInfo onHiddenPath(NodeRef nodeRef) { HiddenFileInfo ret = null; // TODO would be nice to check each part of the path in turn, bailing out if a match is found @@ -259,10 +324,10 @@ public class HiddenAspect * @param fileInfo * @return */ - public void checkHidden(FileInfoImpl fileInfo) + public void checkHidden(FileInfoImpl fileInfo, boolean cascade) { NodeRef nodeRef = fileInfo.getNodeRef(); - HiddenFileInfo hiddenFileInfo = checkHidden(nodeRef); + HiddenFileInfo hiddenFileInfo = checkHidden(nodeRef, cascade); if(hiddenFileInfo != null) { fileInfo.setHidden(true); @@ -283,20 +348,79 @@ public class HiddenAspect fileInfo.setHidden(true); } + private void applyHidden(NodeRef nodeRef, int visibilityMask) + { + PagingRequest pagingRequest = new PagingRequest(0, Integer.MAX_VALUE, null); + PagingResults results = fileFolderService.list(nodeRef, true, true, null, null, pagingRequest); + List files = results.getPage(); + + // apply the hidden aspect to all folders and folders and then recursively to all sub-folders, unless the sub-folder + // already has the hidden aspect applied (it may have been applied for a different pattern). + for(FileInfo file : files) + { + if(!hasHiddenAspect(file.getNodeRef())) + { + hideNode(file.getNodeRef(), visibilityMask); + } + + if(file.isFolder()) + { + applyHidden(file.getNodeRef(), visibilityMask); + } + } + } + + private void removeHidden(NodeRef nodeRef) + { + PagingRequest pagingRequest = new PagingRequest(0, Integer.MAX_VALUE, null); + PagingResults results = fileFolderService.list(nodeRef, true, true, null, null, pagingRequest); + List files = results.getPage(); + + for(FileInfo file : files) + { + String name = (String)nodeService.getProperty(file.getNodeRef(), ContentModel.PROP_NAME); + // remove hidden aspect only if it doesn't match a hidden pattern + if(isHidden(name) == null) + { + removeHiddenAspect(file.getNodeRef()); + removeIndexControlAspect(file.getNodeRef()); + + if(file.isFolder()) + { + removeHidden(file.getNodeRef()); + } + } + } + } + /** * Checks whether the file should be hidden and applies the hidden and not indexed aspects if so. * * @param fileInfo * @return */ - public HiddenFileInfo checkHidden(NodeRef nodeRef) + public HiddenFileInfo checkHidden(NodeRef nodeRef, boolean cascade) { - HiddenFileInfo filter = isHidden(nodeRef); + HiddenFileInfo filter = onHiddenPath(nodeRef); if(filter != null) { - // the file matches a pattern, apply the hidden and aspect control aspects - addHiddenAspect(nodeRef, filter.getVisibilityMask()); - addIndexControlAspect(nodeRef); + if(!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_HIDDEN)) + { + int visibilityMask = filter.getVisibilityMask(); + + // the file matches a pattern, apply the hidden and aspect control aspects + addHiddenAspect(nodeRef, visibilityMask); + + if(!nodeService.hasAspect(nodeRef, ContentModel.ASPECT_INDEX_CONTROL)) + { + addIndexControlAspect(nodeRef); + } + + if(cascade) + { + applyHidden(nodeRef, visibilityMask); + } + } } else { @@ -310,6 +434,11 @@ public class HiddenAspect { removeIndexControlAspect(nodeRef); } + + if(cascade) + { + removeHidden(nodeRef); + } } return filter; @@ -445,7 +574,7 @@ public class HiddenAspect return visibilityMask; } - boolean isHidden(String path) + public boolean isHidden(String path) { return filter.matcher(path).matches(); } diff --git a/source/java/org/alfresco/repo/model/filefolder/HiddenAspectTest.java b/source/java/org/alfresco/repo/model/filefolder/HiddenAspectTest.java index c3c6f21d5d..7c2b5f0be1 100644 --- a/source/java/org/alfresco/repo/model/filefolder/HiddenAspectTest.java +++ b/source/java/org/alfresco/repo/model/filefolder/HiddenAspectTest.java @@ -5,6 +5,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Locale; @@ -16,6 +18,8 @@ import javax.transaction.UserTransaction; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.repo.dictionary.DictionaryNamespaceComponent; +import org.alfresco.repo.domain.node.NodeDAO; +import org.alfresco.repo.domain.node.NodeDAO.NodeRefQueryCallback; import org.alfresco.repo.imap.AlfrescoImapFolder; import org.alfresco.repo.imap.AlfrescoImapUser; import org.alfresco.repo.imap.ImapService; @@ -35,11 +39,14 @@ import org.alfresco.service.cmr.search.SearchParameters; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.MutableAuthenticationService; import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.FileFilterMode; import org.alfresco.util.FileFilterMode.Client; import org.alfresco.util.GUID; +import org.alfresco.util.Pair; import org.alfresco.util.PropertyMap; import org.junit.After; import org.junit.Before; @@ -56,15 +63,21 @@ public class HiddenAspectTest private HiddenAspect hiddenAspect; private TransactionService transactionService; + private NodeDAO nodeDAO; private NodeService nodeService; private FileFolderService fileFolderService; private MutableAuthenticationService authenticationService; private UserTransaction txn; - private NodeRef rootNodeRef; + private SearchService searchService; private DictionaryNamespaceComponent namespacePrefixResolver; private ImapService imapService; private PersonService personService; + private FilenameFilteringInterceptor interceptor; + + private StoreRef storeRef; + private NodeRef rootNodeRef; + private NodeRef topNodeRef; private final String MAILBOX_NAME_A = "mailbox_a"; private final String MAILBOX_NAME_B = ".mailbox_a"; @@ -80,10 +93,12 @@ public class HiddenAspectTest fileFolderService = serviceRegistry.getFileFolderService(); authenticationService = (MutableAuthenticationService) ctx.getBean("AuthenticationService"); hiddenAspect = (HiddenAspect) ctx.getBean("hiddenAspect"); - searchService = (SearchService) ctx.getBean("searchService"); + interceptor = (FilenameFilteringInterceptor) ctx.getBean("filenameFilteringInterceptor"); namespacePrefixResolver = (DictionaryNamespaceComponent) ctx.getBean("namespaceService"); imapService = serviceRegistry.getImapService(); personService = serviceRegistry.getPersonService(); + searchService = serviceRegistry.getSearchService(); + nodeDAO = (NodeDAO)ctx.getBean("nodeDAO"); // start the transaction txn = transactionService.getUserTransaction(); @@ -93,10 +108,16 @@ public class HiddenAspectTest AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); // create a test store - StoreRef storeRef = nodeService + storeRef = nodeService .createStore(StoreRef.PROTOCOL_WORKSPACE, getName() + System.currentTimeMillis()); rootNodeRef = nodeService.getRootNode(storeRef); + topNodeRef = nodeService.createNode( + rootNodeRef, + ContentModel.ASSOC_CHILDREN, + QName.createQName(NamespaceService.ALFRESCO_URI, "working root"), + ContentModel.TYPE_FOLDER).getChildRef(); + anotherUserName = "user" + System.currentTimeMillis(); PropertyMap testUser = new PropertyMap(); @@ -134,16 +155,16 @@ public class HiddenAspectTest e.printStackTrace(); } } - + @Test public void testHiddenFilesEnhancedClient() { FileFilterMode.setClient(Client.webdav); -long start = System.currentTimeMillis(); + try { // check temporary file - NodeRef parent = fileFolderService.create(rootNodeRef, "New Folder", ContentModel.TYPE_FOLDER).getNodeRef(); + NodeRef parent = fileFolderService.create(topNodeRef, "New Folder", ContentModel.TYPE_FOLDER).getNodeRef(); NodeRef child = fileFolderService.create(parent, "file.tmp", ContentModel.TYPE_CONTENT).getNodeRef(); assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_TEMPORARY)); assertFalse(nodeService.hasAspect(child, ContentModel.ASPECT_HIDDEN)); @@ -151,7 +172,7 @@ long start = System.currentTimeMillis(); assertEquals(1, children.size()); // check hidden files - should be hidden for an enhanced client - parent = fileFolderService.create(rootNodeRef, "abc", ContentModel.TYPE_FOLDER).getNodeRef(); + parent = fileFolderService.create(topNodeRef, "abc", ContentModel.TYPE_FOLDER).getNodeRef(); child = fileFolderService.create(parent, ".TemporaryItems", ContentModel.TYPE_FOLDER).getNodeRef(); NodeRef child1 = fileFolderService.create(child, "inTemporaryItems", ContentModel.TYPE_FOLDER).getNodeRef(); assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_TEMPORARY)); @@ -177,7 +198,7 @@ long start = System.currentTimeMillis(); } assertEquals(0, children.size()); - parent = fileFolderService.create(rootNodeRef, "Folder 2", ContentModel.TYPE_FOLDER).getNodeRef(); + parent = fileFolderService.create(topNodeRef, "Folder 2", ContentModel.TYPE_FOLDER).getNodeRef(); child = fileFolderService.create(parent, "Thumbs.db", ContentModel.TYPE_CONTENT).getNodeRef(); assertFalse(nodeService.hasAspect(child, ContentModel.ASPECT_TEMPORARY)); assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_HIDDEN)); @@ -195,7 +216,7 @@ long start = System.currentTimeMillis(); assertEquals(Visibility.NotVisible, hiddenAspect.getVisibility(Client.webclient, child)); // surf-config should not be visible to any client - NodeRef node = fileFolderService.create(rootNodeRef, "surf-config", ContentModel.TYPE_FOLDER).getNodeRef(); + NodeRef node = fileFolderService.create(topNodeRef, "surf-config", ContentModel.TYPE_FOLDER).getNodeRef(); assertTrue(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN)); assertTrue(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL)); results = searchForName("surf-config"); @@ -206,7 +227,7 @@ long start = System.currentTimeMillis(); } // .DS_Store is a system path and so is visible in nfs and webdav, as a hidden file in cifs and hidden to all other clients - node = fileFolderService.create(rootNodeRef, ".DS_Store", ContentModel.TYPE_CONTENT).getNodeRef(); + node = fileFolderService.create(topNodeRef, ".DS_Store", ContentModel.TYPE_CONTENT).getNodeRef(); assertTrue(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN)); assertTrue(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL)); results = searchForName(".DS_Store"); @@ -228,7 +249,7 @@ long start = System.currentTimeMillis(); } // Resource fork should not be visible to any client - node = fileFolderService.create(rootNodeRef, "._resourceFork", ContentModel.TYPE_FOLDER).getNodeRef(); + node = fileFolderService.create(topNodeRef, "._resourceFork", ContentModel.TYPE_FOLDER).getNodeRef(); assertTrue(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN)); assertTrue(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL)); results = searchForName("._resourceFork"); @@ -237,25 +258,68 @@ long start = System.currentTimeMillis(); { assertEquals(Visibility.NotVisible, hiddenAspect.getVisibility(client, node)); } + } + finally + { + FileFilterMode.clearClient(); + } + } + @Test + public void testImap() + { + FileFilterMode.setClient(Client.webdav); + + try + { + // Test that hidden files don't apply to imap service + imapService.getOrCreateMailbox(user, MAILBOX_NAME_A, false, true); + imapService.renameMailbox(user, MAILBOX_NAME_A, MAILBOX_NAME_B); + assertFalse("Can't rename mailbox", checkMailbox(user, MAILBOX_NAME_A)); + assertTrue("Can't rename mailbox", checkMailbox(user, MAILBOX_NAME_B)); + assertEquals("Can't rename mailbox", 0, numMailboxes(user, MAILBOX_NAME_A)); + assertEquals("Can't rename mailbox", 1, numMailboxes(user, MAILBOX_NAME_B)); + } + finally + { + FileFilterMode.clearClient(); + } + } + + @Test + public void testRename() + { + FileFilterMode.setClient(Client.webdav); + + try + { // Test renaming String nodeName = GUID.generate(); - node = fileFolderService.create(rootNodeRef, nodeName, ContentModel.TYPE_CONTENT).getNodeRef(); - NodeRef node1 = fileFolderService.create(node, nodeName + ".1", ContentModel.TYPE_CONTENT).getNodeRef(); - NodeRef node2 = fileFolderService.create(node1, nodeName + ".2", ContentModel.TYPE_CONTENT).getNodeRef(); - NodeRef node3 = fileFolderService.create(node2, nodeName + ".3", ContentModel.TYPE_CONTENT).getNodeRef(); + NodeRef node = fileFolderService.create(topNodeRef, nodeName, ContentModel.TYPE_FOLDER).getNodeRef(); + NodeRef node11 = fileFolderService.create(node, nodeName + ".11", ContentModel.TYPE_FOLDER).getNodeRef(); + NodeRef node12 = fileFolderService.create(node, nodeName + ".12", ContentModel.TYPE_CONTENT).getNodeRef(); + NodeRef node21 = fileFolderService.create(node11, nodeName + ".21", ContentModel.TYPE_FOLDER).getNodeRef(); + NodeRef node22 = fileFolderService.create(node11, nodeName + ".22", ContentModel.TYPE_CONTENT).getNodeRef(); + NodeRef node31 = fileFolderService.create(node21, ".31", ContentModel.TYPE_FOLDER).getNodeRef(); + NodeRef node41 = fileFolderService.create(node31, nodeName + ".41", ContentModel.TYPE_CONTENT).getNodeRef(); assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN)); assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL)); - assertFalse(nodeService.hasAspect(node1, ContentModel.ASPECT_HIDDEN)); - assertFalse(nodeService.hasAspect(node1, ContentModel.ASPECT_INDEX_CONTROL)); - assertFalse(nodeService.hasAspect(node2, ContentModel.ASPECT_HIDDEN)); - assertFalse(nodeService.hasAspect(node2, ContentModel.ASPECT_INDEX_CONTROL)); - assertFalse(nodeService.hasAspect(node3, ContentModel.ASPECT_HIDDEN)); - assertFalse(nodeService.hasAspect(node3, ContentModel.ASPECT_INDEX_CONTROL)); - - results = searchForName(nodeName); + assertFalse(nodeService.hasAspect(node11, ContentModel.ASPECT_HIDDEN)); + assertFalse(nodeService.hasAspect(node11, ContentModel.ASPECT_INDEX_CONTROL)); + assertFalse(nodeService.hasAspect(node12, ContentModel.ASPECT_INDEX_CONTROL)); + assertFalse(nodeService.hasAspect(node12, ContentModel.ASPECT_INDEX_CONTROL)); + assertFalse(nodeService.hasAspect(node21, ContentModel.ASPECT_HIDDEN)); + assertFalse(nodeService.hasAspect(node21, ContentModel.ASPECT_INDEX_CONTROL)); + assertFalse(nodeService.hasAspect(node22, ContentModel.ASPECT_HIDDEN)); + assertFalse(nodeService.hasAspect(node22, ContentModel.ASPECT_INDEX_CONTROL)); + assertTrue(nodeService.hasAspect(node31, ContentModel.ASPECT_HIDDEN)); + assertTrue(nodeService.hasAspect(node31, ContentModel.ASPECT_INDEX_CONTROL)); + assertTrue(nodeService.hasAspect(node41, ContentModel.ASPECT_HIDDEN)); + assertTrue(nodeService.hasAspect(node41, ContentModel.ASPECT_INDEX_CONTROL)); + + ResultSet results = searchForName(nodeName); assertEquals("", 1, results.length()); - + try { fileFolderService.rename(node, "." + nodeName); @@ -268,15 +332,28 @@ long start = System.currentTimeMillis(); { fail(); } + assertTrue(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN)); assertTrue(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL)); - + assertTrue(nodeService.hasAspect(node11, ContentModel.ASPECT_HIDDEN)); + assertTrue(nodeService.hasAspect(node11, ContentModel.ASPECT_INDEX_CONTROL)); + assertTrue(nodeService.hasAspect(node12, ContentModel.ASPECT_INDEX_CONTROL)); + assertTrue(nodeService.hasAspect(node12, ContentModel.ASPECT_INDEX_CONTROL)); + assertTrue(nodeService.hasAspect(node21, ContentModel.ASPECT_HIDDEN)); + assertTrue(nodeService.hasAspect(node21, ContentModel.ASPECT_INDEX_CONTROL)); + assertTrue(nodeService.hasAspect(node22, ContentModel.ASPECT_HIDDEN)); + assertTrue(nodeService.hasAspect(node22, ContentModel.ASPECT_INDEX_CONTROL)); + assertTrue(nodeService.hasAspect(node31, ContentModel.ASPECT_HIDDEN)); + assertTrue(nodeService.hasAspect(node31, ContentModel.ASPECT_INDEX_CONTROL)); + assertTrue(nodeService.hasAspect(node41, ContentModel.ASPECT_HIDDEN)); + assertTrue(nodeService.hasAspect(node41, ContentModel.ASPECT_INDEX_CONTROL)); + results = searchForName(nodeName); assertEquals("", 0, results.length()); - + results = searchForName("." + nodeName); assertEquals("", 0, results.length()); - + try { fileFolderService.rename(node, nodeName); @@ -289,25 +366,28 @@ long start = System.currentTimeMillis(); { fail(); } + assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN)); assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL)); - + assertFalse(nodeService.hasAspect(node11, ContentModel.ASPECT_HIDDEN)); + assertFalse(nodeService.hasAspect(node11, ContentModel.ASPECT_INDEX_CONTROL)); + assertFalse(nodeService.hasAspect(node12, ContentModel.ASPECT_INDEX_CONTROL)); + assertFalse(nodeService.hasAspect(node12, ContentModel.ASPECT_INDEX_CONTROL)); + assertFalse(nodeService.hasAspect(node21, ContentModel.ASPECT_HIDDEN)); + assertFalse(nodeService.hasAspect(node21, ContentModel.ASPECT_INDEX_CONTROL)); + assertFalse(nodeService.hasAspect(node22, ContentModel.ASPECT_HIDDEN)); + assertFalse(nodeService.hasAspect(node22, ContentModel.ASPECT_INDEX_CONTROL)); + assertTrue(nodeService.hasAspect(node31, ContentModel.ASPECT_HIDDEN)); + assertTrue(nodeService.hasAspect(node31, ContentModel.ASPECT_INDEX_CONTROL)); + assertTrue(nodeService.hasAspect(node41, ContentModel.ASPECT_HIDDEN)); + assertTrue(nodeService.hasAspect(node41, ContentModel.ASPECT_INDEX_CONTROL)); + results = searchForName(nodeName); assertEquals("", 1, results.length()); - - // Test imap service - imapService.getOrCreateMailbox(user, MAILBOX_NAME_A, false, true); - imapService.renameMailbox(user, MAILBOX_NAME_A, MAILBOX_NAME_B); - assertFalse("Can't rename mailbox", checkMailbox(user, MAILBOX_NAME_A)); - assertTrue("Can't rename mailbox", checkMailbox(user, MAILBOX_NAME_B)); - assertEquals("Can't rename mailbox", 0, numMailboxes(user, MAILBOX_NAME_A)); - assertEquals("Can't rename mailbox", 1, numMailboxes(user, MAILBOX_NAME_B)); } finally { FileFilterMode.clearClient(); - long end = System.currentTimeMillis(); - System.out.println((end - start)/1000 + "s"); } } @@ -319,7 +399,7 @@ long start = System.currentTimeMillis(); try { // check temporary file - NodeRef parent = fileFolderService.create(rootNodeRef, "New Folder", ContentModel.TYPE_FOLDER).getNodeRef(); + NodeRef parent = fileFolderService.create(topNodeRef, "New Folder", ContentModel.TYPE_FOLDER).getNodeRef(); NodeRef child = fileFolderService.create(parent, "file.tmp", ContentModel.TYPE_CONTENT).getNodeRef(); assertTrue(nodeService.hasAspect(child, ContentModel.ASPECT_TEMPORARY)); assertFalse(nodeService.hasAspect(child, ContentModel.ASPECT_HIDDEN)); @@ -330,7 +410,7 @@ long start = System.currentTimeMillis(); assertEquals(1, children.size()); // check hidden files - should not be hidden for a basic client - parent = fileFolderService.create(rootNodeRef, ".TemporaryItems", ContentModel.TYPE_FOLDER).getNodeRef(); + parent = fileFolderService.create(topNodeRef, ".TemporaryItems", ContentModel.TYPE_FOLDER).getNodeRef(); child = fileFolderService.create(parent, "inTemporaryItems", ContentModel.TYPE_FOLDER).getNodeRef(); assertFalse(nodeService.hasAspect(parent, ContentModel.ASPECT_TEMPORARY)); assertFalse(nodeService.hasAspect(parent, ContentModel.ASPECT_HIDDEN)); @@ -343,7 +423,7 @@ long start = System.currentTimeMillis(); children = fileFolderService.list(parent); assertEquals(1, children.size()); - parent = fileFolderService.create(rootNodeRef, "Folder 2", ContentModel.TYPE_FOLDER).getNodeRef(); + parent = fileFolderService.create(topNodeRef, "Folder 2", ContentModel.TYPE_FOLDER).getNodeRef(); child = fileFolderService.create(parent, "Thumbs.db", ContentModel.TYPE_CONTENT).getNodeRef(); assertFalse(nodeService.hasAspect(child, ContentModel.ASPECT_TEMPORARY)); assertFalse(nodeService.hasAspect(child, ContentModel.ASPECT_HIDDEN)); @@ -353,13 +433,13 @@ long start = System.currentTimeMillis(); children = fileFolderService.list(parent); assertEquals(1, children.size()); - NodeRef node = fileFolderService.create(rootNodeRef, "surf-config", ContentModel.TYPE_FOLDER).getNodeRef(); + NodeRef node = fileFolderService.create(topNodeRef, "surf-config", ContentModel.TYPE_FOLDER).getNodeRef(); assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN)); assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL)); results = searchForName("surf-config"); assertEquals("", 1, results.length()); - node = fileFolderService.create(rootNodeRef, ".DS_Store", ContentModel.TYPE_CONTENT).getNodeRef(); + node = fileFolderService.create(topNodeRef, ".DS_Store", ContentModel.TYPE_CONTENT).getNodeRef(); assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN)); assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL)); results = searchForName(".DS_Store"); @@ -369,7 +449,7 @@ long start = System.currentTimeMillis(); assertEquals("Should be visible for client " + client, Visibility.Visible, hiddenAspect.getVisibility(client, node)); } - node = fileFolderService.create(rootNodeRef, "._resourceFork", ContentModel.TYPE_FOLDER).getNodeRef(); + node = fileFolderService.create(topNodeRef, "._resourceFork", ContentModel.TYPE_FOLDER).getNodeRef(); assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN)); assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL)); results = searchForName("._resourceFork"); @@ -380,7 +460,7 @@ long start = System.currentTimeMillis(); String nodeName = "Node" + System.currentTimeMillis(); - node = fileFolderService.create(rootNodeRef, nodeName, ContentModel.TYPE_CONTENT).getNodeRef(); + node = fileFolderService.create(topNodeRef, nodeName, ContentModel.TYPE_CONTENT).getNodeRef(); assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_HIDDEN)); assertFalse(nodeService.hasAspect(node, ContentModel.ASPECT_INDEX_CONTROL)); results = searchForName(nodeName); @@ -437,6 +517,59 @@ long start = System.currentTimeMillis(); } } + @Test + public void testCheckHidden() throws Exception + { + String nodeName = GUID.generate(); + + interceptor.setEnabled(false); + + try + { + // Create some nodes that should be hidden but aren't + NodeRef node = fileFolderService.create(topNodeRef, nodeName, ContentModel.TYPE_FOLDER).getNodeRef(); + NodeRef node11 = fileFolderService.create(node, nodeName + ".11", ContentModel.TYPE_FOLDER).getNodeRef(); + NodeRef node12 = fileFolderService.create(node, ".12", ContentModel.TYPE_CONTENT).getNodeRef(); + NodeRef node21 = fileFolderService.create(node11, nodeName + ".21", ContentModel.TYPE_FOLDER).getNodeRef(); + NodeRef node22 = fileFolderService.create(node11, nodeName + ".22", ContentModel.TYPE_CONTENT).getNodeRef(); + NodeRef node31 = fileFolderService.create(node21, ".31", ContentModel.TYPE_FOLDER).getNodeRef(); + NodeRef node41 = fileFolderService.create(node31, nodeName + ".41", ContentModel.TYPE_CONTENT).getNodeRef(); + + assertEquals(1, searchForName(".12").length()); + assertEquals(1, searchForName(".31").length()); + assertEquals(1, searchForName(nodeName + ".41").length()); + + txn.commit(); + } + finally + { + interceptor.setEnabled(true); + } + } + + private List getHiddenNodes(final StoreRef storeRef) + { + final List nodes = new ArrayList(20); + + NodeRefQueryCallback resultsCallback = new NodeRefQueryCallback() + { + @Override + public boolean handle(Pair nodePair) + { + if(storeRef == null || nodePair.getSecond().getStoreRef().equals(storeRef)) + { + nodes.add(nodePair.getSecond()); + } + + return true; + } + + }; + nodeDAO.getNodesWithAspects(Collections.singleton(ContentModel.ASPECT_HIDDEN), 0l, Long.MAX_VALUE, resultsCallback); + + return nodes; + } + private int numMailboxes(AlfrescoImapUser user, String mailboxName) { int numMailboxes = 0; diff --git a/source/java/org/alfresco/repo/model/filefolder/HiddenFileInfo.java b/source/java/org/alfresco/repo/model/filefolder/HiddenFileInfo.java index 5d6ec3de13..7aff1c02f3 100644 --- a/source/java/org/alfresco/repo/model/filefolder/HiddenFileInfo.java +++ b/source/java/org/alfresco/repo/model/filefolder/HiddenFileInfo.java @@ -10,4 +10,5 @@ public interface HiddenFileInfo { public int getVisibilityMask(); public String getFilter(); + public boolean isHidden(String path); }