Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 1782eb84 authored by Mario Danic's avatar Mario Danic Committed by AndyScherzinger
Browse files

Better search

parent efd9cc75
Loading
Loading
Loading
Loading
+103 −0
Original line number Diff line number Diff line
/**
 * Nextcloud Android client application
 *
 * @author Mario Danic
 * Copyright (C) 2017 Mario Danic
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.owncloud.android.lib.common.utils;

import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.WebdavEntry;
import com.owncloud.android.lib.resources.files.RemoteFile;

import org.apache.jackrabbit.webdav.MultiStatus;

import java.util.ArrayList;

/**
 * WebDav helper.
 */

public class WebDavFileUtils {


    /**
     *  Read the data retrieved from the server about the contents of the target folder
     *
     *
     *  @param remoteData     	Full response got from the server with the data of the target
     *                          folder and its direct children.
     *  @param client           Client instance to the remote server where the data were
     *                          retrieved.
     *  @return
     */
    public ArrayList<Object> readData(MultiStatus remoteData, OwnCloudClient client, boolean isReadFolderOperation,
                                      boolean isSearchOperation, String username) {
        ArrayList<Object> mFolderAndFiles = new ArrayList<Object>();

        WebdavEntry we;
        int start = 1;

        if (isReadFolderOperation) {
             we = new WebdavEntry(remoteData.getResponses()[0],
                    client.getWebdavUri().getPath());
            mFolderAndFiles.add(fillOCFile(we));
        } else {
            start = 0;
        }

        String stripString = client.getWebdavUri().getPath();
        if (isSearchOperation && username != null) {
            stripString = stripString + "/files/" + username;
        }

        // loop to update every child
        RemoteFile remoteFile = null;
        for (int i = start; i < remoteData.getResponses().length; i++) {
            /// new OCFile instance with the data from the server
            we = new WebdavEntry(remoteData.getResponses()[i], stripString);
            remoteFile = fillOCFile(we);
            mFolderAndFiles.add(remoteFile);
        }

        return mFolderAndFiles;

    }

    /**
     * Creates and populates a new {@link RemoteFile} object with the data read from the server.
     *
     * @param we        WebDAV entry read from the server for a WebDAV resource (remote file or folder).
     * @return          New OCFile instance representing the remote resource described by we.
     */
    private RemoteFile fillOCFile(WebdavEntry we) {
        RemoteFile file = new RemoteFile(we.decodedPath());
        file.setCreationTimestamp(we.createTimestamp());
        file.setLength(we.contentLength());
        file.setMimeType(we.contentType());
        file.setModifiedTimestamp(we.modifiedTimestamp());
        file.setEtag(we.etag());
        file.setPermissions(we.permissions());
        file.setRemoteId(we.remoteId());
        file.setSize(we.size());
        file.setQuotaUsedBytes(we.quotaUsedBytes());
        file.setQuotaAvailableBytes(we.quotaAvailableBytes());
        file.setFavorite(we.isFavorite());
        return file;
    }


}
+16 −14
Original line number Diff line number Diff line
@@ -24,6 +24,19 @@

package com.owncloud.android.lib.resources.files;

import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.OperationCancelledException;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
@@ -34,19 +47,6 @@ import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;

import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.OperationCancelledException;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;

/**
 * Remote operation performing the download of a remote file in the ownCloud server.
 * 
@@ -64,6 +64,8 @@ public class DownloadRemoteFileOperation extends RemoteOperation {
    private String mEtag = "";
    private GetMethod mGet;


    
    private String mRemotePath;
    private String mLocalFolderPath;
	
+9 −37
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import com.owncloud.android.lib.common.network.WebdavUtils;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.common.utils.WebDavFileUtils;

import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.DavConstants;
@@ -50,7 +51,6 @@ public class ReadRemoteFolderOperation extends RemoteOperation {
	private static final String TAG = ReadRemoteFolderOperation.class.getSimpleName();

	private String mRemotePath;
	private ArrayList<Object> mFolderAndFiles;

    /**
     * Constructor
@@ -86,7 +86,8 @@ public class ReadRemoteFolderOperation extends RemoteOperation {
            if (isSuccess) {
            	// get data from remote folder 
                MultiStatus dataInServer = query.getResponseBodyAsMultiStatus();
            	readData(dataInServer, client);
                WebDavFileUtils webDavFileUtils = new WebDavFileUtils();
                ArrayList<Object> mFolderAndFiles = webDavFileUtils.readData(dataInServer, client, true, false, "");
            	
            	// Result of the operation
            	result = new RemoteOperationResult(true, status, query.getResponseHeaders());
@@ -103,7 +104,6 @@ public class ReadRemoteFolderOperation extends RemoteOperation {
        } catch (Exception e) {
            result = new RemoteOperationResult(e);


        } finally {
            if (query != null)
                query.releaseConnection();  // let the connection available for other methods
@@ -126,34 +126,6 @@ public class ReadRemoteFolderOperation extends RemoteOperation {
        return (status == HttpStatus.SC_MULTI_STATUS); 
    }

    /**
     *  Read the data retrieved from the server about the contents of the target folder 
     *  
     * 
     *  @param remoteData     	Full response got from the server with the data of the target 
     *                          folder and its direct children.
     *  @param client           Client instance to the remote server where the data were 
     *                          retrieved.  
     *  @return                
     */
    private void readData(MultiStatus remoteData, OwnCloudClient client) {   	
        mFolderAndFiles = new ArrayList<Object>();
        
        // parse data from remote folder 
        WebdavEntry we = new WebdavEntry(remoteData.getResponses()[0],
                client.getWebdavUri().getPath());
        mFolderAndFiles.add(fillOCFile(we));
        
        // loop to update every child
        RemoteFile remoteFile = null;
        for (int i = 1; i < remoteData.getResponses().length; ++i) {
            /// new OCFile instance with the data from the server
            we = new WebdavEntry(remoteData.getResponses()[i], client.getWebdavUri().getPath());                        
            remoteFile = fillOCFile(we);
            mFolderAndFiles.add(remoteFile);
        }
        
    }

    /**
     * Creates and populates a new {@link RemoteFile} object with the data read from the server.
+248 −0
Original line number Diff line number Diff line
/**
 * Nextcloud Android client application
 *
 * @author Mario Danic
 * Copyright (C) 2017 Mario Danic
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.owncloud.android.lib.resources.files;

import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.WebdavEntry;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.WebDavFileUtils;

import org.apache.commons.httpclient.HttpStatus;
import org.apache.jackrabbit.webdav.MultiStatus;
import org.apache.jackrabbit.webdav.client.methods.OptionsMethod;
import org.apache.jackrabbit.webdav.search.SearchInfo;
import org.apache.jackrabbit.webdav.xml.Namespace;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

import java.io.IOException;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

/**
 * Remote operation performing the search in the Nextcloud server.
 */

public class SearchOperation extends RemoteOperation {

    private static final String HEADER_CONTENT_TYPE_VALUE = "text/xml";

    private static final String DAV_NAMESPACE = "DAV:";

    public enum SearchType {
        FILE_SEARCH,
        FAVORITE_SEARCH,
        CONTENT_TYPE_SEARCH
    }

    private String searchQuery;
    private String username;
    private SearchType searchType;

    public SearchOperation(String query, SearchType searchType, String username) {
        this.searchQuery = query;
        this.searchType = searchType;
        this.username = username;
    }

    @Override
    protected RemoteOperationResult run(OwnCloudClient client) {
        RemoteOperationResult result = null;
        SearchMethod searchMethod = null;
        OptionsMethod optionsMethod = null;

        String webDavUrl = client.getWebdavUri().toString();
        optionsMethod = new OptionsMethod(webDavUrl);

        try {
            int optionsStatus = client.executeMethod(optionsMethod);
            boolean isSearchSupported = optionsMethod.isAllowed("SEARCH");
            if (isSearchSupported) {

                searchMethod = new SearchMethod(webDavUrl, new SearchInfo("NC",
                        Namespace.XMLNS_NAMESPACE, "NC"));

                int status = client.executeMethod(searchMethod);

                // check and process response
                boolean isSuccess = (
                        status == HttpStatus.SC_MULTI_STATUS ||
                                status == HttpStatus.SC_OK
                );
                if (isSuccess) {
                    // get data from remote folder
                    MultiStatus dataInServer = searchMethod.getResponseBodyAsMultiStatus();
                    WebDavFileUtils webDavFileUtils = new WebDavFileUtils();
                    ArrayList<Object> mFolderAndFiles = webDavFileUtils.readData(dataInServer, client, false, true,
                            username);

                    // Result of the operation
                    result = new RemoteOperationResult(true, status, searchMethod.getResponseHeaders());
                    // Add data to the result
                    if (result.isSuccess()) {
                        result.setData(mFolderAndFiles);
                    }
                } else {
                    // synchronization failed
                    client.exhaustResponse(searchMethod.getResponseBodyAsStream());
                    result = new RemoteOperationResult(false, status, searchMethod.getResponseHeaders());
                }
            } else {
                client.exhaustResponse(optionsMethod.getResponseBodyAsStream());
                result = new RemoteOperationResult(false, optionsStatus, optionsMethod.getResponseHeaders());
            }

        } catch (Exception e) {
            result = new RemoteOperationResult(e);
        } finally {
            if (searchMethod != null) {
                searchMethod.releaseConnection();  // let the connection available for other methods
            }

            if (optionsMethod != null) {
                optionsMethod.releaseConnection();
            }
        }
        return result;
    }


    private class SearchMethod extends org.apache.jackrabbit.webdav.client.methods.SearchMethod {

        public SearchMethod(String uri, String statement, String language) throws IOException {
            super(uri, statement, language);
        }

        public SearchMethod(String uri, String statement, String language, Namespace languageNamespace) throws IOException {
            super(uri, statement, language, languageNamespace);
        }

        public SearchMethod(String uri, SearchInfo searchInfo) throws IOException {
            super(uri, searchInfo);
            setRequestHeader(HEADER_CONTENT_TYPE, HEADER_CONTENT_TYPE_VALUE);
            setRequestBody(createQuery(searchQuery, searchType));
        }

    }


    private Document createQuery(String searchString, SearchType searchType) {

        if (searchType == SearchType.FAVORITE_SEARCH) {
            searchString = "yes";
        }
        
        Document query;
        try {
            query = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
        } catch (ParserConfigurationException parserError) {
            System.err.println("ParserConfigurationException: " + parserError.getLocalizedMessage());
            return null;
        }

        // Create Nodes & Elements
        Element searchRequestElement = query.createElementNS(DAV_NAMESPACE, "d:searchrequest");
        Element basicSearchElement = query.createElementNS(DAV_NAMESPACE, "d:basicsearch");
        Element selectElement = query.createElementNS(DAV_NAMESPACE, "d:select");
        Element selectPropsElement = query.createElementNS(DAV_NAMESPACE, "d:prop");
        // get all
        Element displayNameElement = query.createElementNS(DAV_NAMESPACE, "d:displayname");
        Element contentTypeElement = query.createElementNS(DAV_NAMESPACE, "d:getcontenttype");
        Element resourceTypeElement = query.createElementNS(DAV_NAMESPACE, "d:resourcetype");
        Element contentLengthElement = query.createElementNS(DAV_NAMESPACE, "d:getcontentlength");
        Element lastModifiedElement = query.createElementNS(DAV_NAMESPACE, "d:getlastmodified");
        Element creationDate = query.createElementNS(DAV_NAMESPACE, "d:creationdate");
        Element etagElement = query.createElementNS(DAV_NAMESPACE, "d:getetag");
        Element quotaUsedElement = query.createElementNS(DAV_NAMESPACE, "d:quota-used-bytes");
        Element quotaAvailableElement = query.createElementNS(DAV_NAMESPACE, "d:quota-available-bytes");
        Element permissionsElement = query.createElementNS(WebdavEntry.NAMESPACE_OC, "oc:permissions");
        Element remoteIdElement = query.createElementNS(WebdavEntry.NAMESPACE_OC, "oc:id");
        Element sizeElement = query.createElementNS(WebdavEntry.NAMESPACE_OC, "oc:size");
        Element favoriteElement = query.createElementNS(WebdavEntry.NAMESPACE_OC, "oc:favorite");

        selectPropsElement.appendChild(displayNameElement);
        selectPropsElement.appendChild(contentTypeElement);
        selectPropsElement.appendChild(resourceTypeElement);
        selectPropsElement.appendChild(contentLengthElement);
        selectPropsElement.appendChild(lastModifiedElement);
        selectPropsElement.appendChild(creationDate);
        selectPropsElement.appendChild(etagElement);
        selectPropsElement.appendChild(quotaUsedElement);
        selectPropsElement.appendChild(quotaAvailableElement);
        selectPropsElement.appendChild(permissionsElement);
        selectPropsElement.appendChild(remoteIdElement);
        selectPropsElement.appendChild(sizeElement);
        selectPropsElement.appendChild(favoriteElement);

        Element fromElement = query.createElementNS(DAV_NAMESPACE, "d:from");
        Element scopeElement = query.createElementNS(DAV_NAMESPACE, "d:scope");
        Element hrefElement = query.createElementNS(DAV_NAMESPACE, "d:href");
        Element depthElement = query.createElementNS(DAV_NAMESPACE, "d:depth");
        Text hrefTextElement = query.createTextNode("/files/" + username);
        Text depthTextElement = query.createTextNode("infinity");
        Element whereElement = query.createElementNS(DAV_NAMESPACE, "d:where");
        Element equalsElement;
        if (searchType != SearchType.FAVORITE_SEARCH) {
            equalsElement = query.createElementNS(DAV_NAMESPACE, "d:like");
        } else {
            equalsElement = query.createElementNS(DAV_NAMESPACE, "d:eq");
        }
        Element propElement = query.createElementNS(DAV_NAMESPACE, "d:prop");
        Element queryElement = null;
        if (searchType == SearchType.CONTENT_TYPE_SEARCH) {
            queryElement = query.createElementNS(DAV_NAMESPACE, "d:getcontenttype");
        } else if (searchType == SearchType.FILE_SEARCH){
            queryElement = query.createElementNS(DAV_NAMESPACE, "d:displayname");
        } else {
            queryElement = query.createElementNS(WebdavEntry.NAMESPACE_OC, "oc:favorite");
        }
        Element literalElement = query.createElementNS(DAV_NAMESPACE, "d:literal");
        Text literalTextElement = query.createTextNode(searchString);
        Element orderByElement = query.createElementNS(DAV_NAMESPACE, "d:orderby");

        // Build XML tree
        searchRequestElement.setAttribute("xmlns:oc", "http://nextcloud.com/ns");
        query.appendChild(searchRequestElement);
        searchRequestElement.appendChild(basicSearchElement);
        basicSearchElement.appendChild(selectElement);
        basicSearchElement.appendChild(fromElement);
        basicSearchElement.appendChild(whereElement);
        selectElement.appendChild(selectPropsElement);
        fromElement.appendChild(scopeElement);
        scopeElement.appendChild(hrefElement);
        scopeElement.appendChild(depthElement);
        hrefElement.appendChild(hrefTextElement);
        depthElement.appendChild(depthTextElement);
        whereElement.appendChild(equalsElement);
        equalsElement.appendChild(propElement);
        equalsElement.appendChild(literalElement);
        propElement.appendChild(queryElement);
        literalElement.appendChild(literalTextElement);
        basicSearchElement.appendChild(orderByElement);

        return query;
    }


}