mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	api: Support file uploads to the API.
Now, the `Client.do_api_query()` method supports sending files to the API. This has allowed the implementation of a new method, `Client.upload_file(file)`. It simply uploads the file set in the parameter, and returns the API's response (that includes the URI). Despite the fact that `do_api_query()` supports multiple files as parameters, `upload_file()` doesn't, because right now the API isn't capable of managing more than a file in the same request.
This commit is contained in:
		
				
					committed by
					
						
						Tim Abbott
					
				
			
			
				
	
			
			
			
						parent
						
							089c0a861d
						
					
				
				
					commit
					25dbe35747
				
			
							
								
								
									
										66
									
								
								api/examples/upload-file
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										66
									
								
								api/examples/upload-file
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
# Copyright © 2012-2017 Zulip, Inc.
 | 
			
		||||
#
 | 
			
		||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
# of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
# in the Software without restriction, including without limitation the rights
 | 
			
		||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
# copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
# furnished to do so, subject to the following conditions:
 | 
			
		||||
#
 | 
			
		||||
# The above copyright notice and this permission notice shall be included in
 | 
			
		||||
# all copies or substantial portions of the Software.
 | 
			
		||||
#
 | 
			
		||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
# THE SOFTWARE.
 | 
			
		||||
 | 
			
		||||
from __future__ import print_function
 | 
			
		||||
import importlib
 | 
			
		||||
import optparse
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
from six.moves import StringIO as _StringIO
 | 
			
		||||
sys.path.insert(0, './api')
 | 
			
		||||
from typing import IO
 | 
			
		||||
import zulip
 | 
			
		||||
 | 
			
		||||
class StringIO(_StringIO):
 | 
			
		||||
    name = '' # https://github.com/python/typeshed/issues/598
 | 
			
		||||
 | 
			
		||||
usage = """upload-file --user=<user's email address> --api-key=<user's api key> [options]
 | 
			
		||||
 | 
			
		||||
Upload a file, and print the corresponding URI.
 | 
			
		||||
 | 
			
		||||
Example: upload-file --user=cordelia@zulip.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --file-path=cat.png
 | 
			
		||||
 | 
			
		||||
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
 | 
			
		||||
If no --file-path is specified, a placeholder text file will be used instead.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
parser = optparse.OptionParser(usage=usage)
 | 
			
		||||
parser.add_option('--file-path')
 | 
			
		||||
parser.add_option_group(zulip.generate_option_group(parser))
 | 
			
		||||
(options, args) = parser.parse_args()
 | 
			
		||||
 | 
			
		||||
client = zulip.init_from_options(options)
 | 
			
		||||
 | 
			
		||||
file = None # type: IO
 | 
			
		||||
if options.file_path:
 | 
			
		||||
    file = open(options.file_path, 'rb')
 | 
			
		||||
else:
 | 
			
		||||
    file = StringIO('This is a test file.')
 | 
			
		||||
    file.name = 'test.txt'
 | 
			
		||||
 | 
			
		||||
response = client.upload_file(file)
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    print('File URI: {}'.format(response['uri']))
 | 
			
		||||
except KeyError:
 | 
			
		||||
    print('Error! API response was: {}'.format(response))
 | 
			
		||||
@@ -38,7 +38,7 @@ from six.moves.configparser import SafeConfigParser
 | 
			
		||||
from six.moves import urllib
 | 
			
		||||
import logging
 | 
			
		||||
import six
 | 
			
		||||
from typing import Any, Callable, Dict, Mapping, Optional, Tuple, Union, Iterable, Text
 | 
			
		||||
from typing import Any, Callable, Dict, Iterable, IO, Mapping, Optional, Text, Tuple, Union
 | 
			
		||||
 | 
			
		||||
__version__ = "0.2.5"
 | 
			
		||||
 | 
			
		||||
@@ -290,9 +290,13 @@ class Client(object):
 | 
			
		||||
                vendor_version=vendor_version,
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
    def do_api_query(self, orig_request, url, method="POST", longpolling=False):
 | 
			
		||||
        # type: (Mapping[str, Any], str, str, bool) -> Dict[str, Any]
 | 
			
		||||
    def do_api_query(self, orig_request, url, method="POST", longpolling=False, files=None):
 | 
			
		||||
        # type: (Mapping[str, Any], str, str, bool, List[IO]) -> Dict[str, Any]
 | 
			
		||||
        if files is None:
 | 
			
		||||
            files = []
 | 
			
		||||
 | 
			
		||||
        request = {}
 | 
			
		||||
        req_files = []
 | 
			
		||||
 | 
			
		||||
        for (key, val) in six.iteritems(orig_request):
 | 
			
		||||
            if isinstance(val, str) or isinstance(val, Text):
 | 
			
		||||
@@ -300,6 +304,9 @@ class Client(object):
 | 
			
		||||
            else:
 | 
			
		||||
                request[key] = simplejson.dumps(val)
 | 
			
		||||
 | 
			
		||||
        for f in files:
 | 
			
		||||
            req_files.append((f.name, f))
 | 
			
		||||
 | 
			
		||||
        query_state = {
 | 
			
		||||
            'had_error_retry': False,
 | 
			
		||||
            'request': request,
 | 
			
		||||
@@ -337,8 +344,12 @@ class Client(object):
 | 
			
		||||
                    kwarg = "params"
 | 
			
		||||
                else:
 | 
			
		||||
                    kwarg = "data"
 | 
			
		||||
 | 
			
		||||
                kwargs = {kwarg: query_state["request"]}
 | 
			
		||||
 | 
			
		||||
                if files:
 | 
			
		||||
                    kwargs['files'] = req_files
 | 
			
		||||
 | 
			
		||||
                # Build a client cert object for requests
 | 
			
		||||
                if self.client_cert_key is not None:
 | 
			
		||||
                    client_cert = (self.client_cert, self.client_cert_key) # type: Union[str, Tuple[str, str]]
 | 
			
		||||
@@ -402,11 +413,11 @@ class Client(object):
 | 
			
		||||
            return {'msg': "Unexpected error from the server", "result": "http-error",
 | 
			
		||||
                    "status_code": res.status_code}
 | 
			
		||||
 | 
			
		||||
    def call_endpoint(self, url=None, method="POST", request=None, longpolling=False):
 | 
			
		||||
        # type: (str, str, Dict[str, Any], bool) -> Dict[str, Any]
 | 
			
		||||
    def call_endpoint(self, url=None, method="POST", request=None, longpolling=False, files=None):
 | 
			
		||||
        # type: (str, str, Dict[str, Any], bool, List[IO]) -> Dict[str, Any]
 | 
			
		||||
        if request is None:
 | 
			
		||||
            request = dict()
 | 
			
		||||
        return self.do_api_query(request, API_VERSTRING + url, method=method)
 | 
			
		||||
        return self.do_api_query(request, API_VERSTRING + url, method=method, files=files)
 | 
			
		||||
 | 
			
		||||
    def call_on_each_event(self, callback, event_types=None, narrow=None):
 | 
			
		||||
        # type: (Callable, Optional[List[str]], Any) -> None
 | 
			
		||||
@@ -480,6 +491,16 @@ class Client(object):
 | 
			
		||||
            request=message_data,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def upload_file(self, file):
 | 
			
		||||
        # type: (IO) -> Dict[str, Any]
 | 
			
		||||
        '''
 | 
			
		||||
            See api/examples/upload-file for example usage.
 | 
			
		||||
        '''
 | 
			
		||||
        return self.call_endpoint(
 | 
			
		||||
            url='user_uploads',
 | 
			
		||||
            files=[file]
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def update_message(self, message_data):
 | 
			
		||||
        # type: (Dict[str, Any]) -> Dict[str, Any]
 | 
			
		||||
        '''
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user