from office365.runtime.http.http_method import HttpMethod
from office365.runtime.queries.service_operation_query import ServiceOperationQuery


class DownloadFileQuery(ServiceOperationQuery):

    def __init__(self, web, file_url, file_object):
        """
        A download file content query

        :type file_url: str
        :type web: office365.sharepoint.webs.web.Web
        :type file_object: typing.IO
        """

        def _construct_download_query(request):
            request.method = HttpMethod.Get
            self.context.after_execute(_process_response)

        def _process_response(response):
            """
            :type response: RequestOptions
            """
            file_object.write(response.content)

        super(DownloadFileQuery, self).__init__(web, r"getFileByServerRelativeUrl('{0}')/\$value".format(file_url))
        self.context.before_execute(_construct_download_query)

from office365.runtime.http.http_method import HttpMethod
from office365.runtime.odata.odata_path_parser import ODataPathParser
from office365.runtime.queries.service_operation_query import ServiceOperationQuery


class DownloadFileQuery(ServiceOperationQuery):

    def __init__(self, web, file_url, file_object):
        """
        A download file content query

        :type file_url: str
        :type web: office365.sharepoint.webs.web.Web
        :type file_object: typing.IO
        """

        def _construct_download_query(request):
            request.method = HttpMethod.Get
            self.context.after_execute(_process_response)

        def _process_response(response):
            """
            :type response: RequestOptions
            """
            file_object.write(response.content)

        # Sharepoint Endpoint bug: https://github.com/SharePoint/sp-dev-docs/issues/2630
        file_url = ODataPathParser.encode_method_value(file_url)
                
        super(DownloadFileQuery, self).__init__(web, r"getFileByServerRelativePath(decodedurl={0})/$value".format(file_url))
    
        self.context.before_execute(_construct_download_query)

Support correctly weird characters in filenames when downloading
Support correctly weird characters in filenames when downloading

This commit add support for the following:
- Correctly encoded oData parameter sent to the endpoint.
- Support for # and % in filenames by using a newer 365 endpoint.

Summary:

Current implementation was injecting an URL directly quoted to
the endpoint, instead of encoding as an oData value. This was
solved by using the encode_method_value method. This fixes
issues when the file contains weird characters, like slashes
and single quotes.

The getFileServerByUrl endpoint does not support some characters
in filenames, like # and %. A newer endpoint
(getFileByServerRelativePath) is used instead, which allows to
download files with those characters.
