mostr-zulip-bot/zulip_bots/zulip_bots/bots/dropbox_share/dropbox_share.py
LoopThrough-i-j 4c75057de1 dropbox-bot: Update to support dropbox>=11.0.0.
Changes in dropox version >= 11.0 broke the dropbox bot.
The required fixes are mentioned at:
https://github.com/dropbox/dropbox-sdk-python/blob/main/UPGRADING.md#upgrading-from-v10xx-to-v1100
2021-02-23 19:19:16 -08:00

225 lines
7.2 KiB
Python

from dropbox import Dropbox
from typing import Any, Dict, List, Tuple
import re
URL = "[{name}](https://www.dropbox.com/home{path})"
class DropboxHandler:
'''
This bot allows you to easily share, search and upload files
between zulip and your dropbox account.
'''
def initialize(self, bot_handler: Any) -> None:
self.config_info = bot_handler.get_config_info('dropbox_share')
self.ACCESS_TOKEN = self.config_info.get('access_token')
self.client = Dropbox(self.ACCESS_TOKEN)
def usage(self) -> str:
return get_help()
def handle_message(self, message: Dict[str, str], bot_handler: Any) -> None:
command = message['content']
if command == "":
command = "help"
msg = dbx_command(self.client, command)
bot_handler.send_reply(message, msg)
def get_help() -> str:
return '''
Example commands:
```
@mention-bot usage: see usage examples
@mention-bot mkdir: create a folder
@mention-bot ls: list a folder
@mention-bot write: write text
@mention-bot rm: remove a file or folder
@mention-bot read: read a file
@mention-bot search: search a file/folder
@mention-bot share: get a shareable link for the file/folder
```
'''
def get_usage_examples() -> str:
return '''
Usage:
```
@dropbox ls - Shows files/folders in the root folder.
@dropbox mkdir foo - Make folder named foo.
@dropbox ls foo/boo - Shows the files/folders in foo/boo folder.
@dropbox write test hello world - Write "hello world" to the file 'test'.
@dropbox rm test - Remove the file/folder test.
@dropbox read foo - Read the contents of file/folder foo.
@dropbox share foo - Get shareable link for the file/folder foo.
@dropbox search boo - Search for boo in root folder and get at max 20 results.
@dropbox search boo --mr 10 - Search for boo and get at max 10 results.
@dropbox search boo --fd foo - Search for boo in folder foo.
```
'''
REGEXES = dict(
command='(ls|mkdir|read|rm|write|search|usage|help)',
path=r'(\S+)',
optional_path=r'(\S*)',
some_text='(.+?)',
folder=r'?(?:--fd (\S+))?',
max_results=r'?(?:--mr (\d+))?'
)
def get_commands() -> Dict[str, Tuple[Any, List[str]]]:
return {
'help': (dbx_help, ['command']),
'ls': (dbx_ls, ['optional_path']),
'mkdir': (dbx_mkdir, ['path']),
'rm': (dbx_rm, ['path']),
'write': (dbx_write, ['path', 'some_text']),
'read': (dbx_read, ['path']),
'search': (dbx_search, ['some_text', 'folder', 'max_results']),
'share': (dbx_share, ['path']),
'usage': (dbx_usage, []),
}
def dbx_command(client: Any, cmd: str) -> str:
cmd = cmd.strip()
if cmd == 'help':
return get_help()
cmd_name = cmd.split()[0]
cmd_args = cmd[len(cmd_name):].strip()
commands = get_commands()
if cmd_name not in commands:
return 'ERROR: unrecognized command\n' + get_help()
f, arg_names = commands[cmd_name]
partial_regexes = [REGEXES[a] for a in arg_names]
regex = ' '.join(partial_regexes)
regex += '$'
m = re.match(regex, cmd_args)
if m:
return f(client, *m.groups())
else:
return 'ERROR: ' + syntax_help(cmd_name)
def syntax_help(cmd_name: str) -> str:
commands = get_commands()
f, arg_names = commands[cmd_name]
arg_syntax = ' '.join('<' + a + '>' for a in arg_names)
if arg_syntax:
cmd = cmd_name + ' ' + arg_syntax
else:
cmd = cmd_name
return 'syntax: {}'.format(cmd)
def dbx_help(client: Any, cmd_name: str) -> str:
return syntax_help(cmd_name)
def dbx_usage(client: Any) -> str:
return get_usage_examples()
def dbx_mkdir(client: Any, fn: str) -> str:
fn = '/' + fn # foo/boo -> /foo/boo
try:
result = client.files_create_folder(fn)
msg = "CREATED FOLDER: " + URL.format(name=result.name, path=result.path_lower)
except Exception:
msg = "Please provide a correct folder path and name.\n"\
"Usage: `mkdir <foldername>` to create a folder."
return msg
def dbx_ls(client: Any, fn: str) -> str:
if fn != '':
fn = '/' + fn
try:
result = client.files_list_folder(fn)
files_list = [] # type: List[str]
for meta in result.entries:
files_list += [" - " + URL.format(name=meta.name, path=meta.path_lower)]
msg = '\n'.join(files_list)
if msg == '':
msg = '`No files available`'
except Exception:
msg = "Please provide a correct folder path\n"\
"Usage: `ls <foldername>` to list folders in directory\n"\
"or simply `ls` for listing folders in the root directory"
return msg
def dbx_rm(client: Any, fn: str) -> str:
fn = '/' + fn
try:
result = client.files_delete(fn)
msg = "DELETED File/Folder : " + URL.format(name=result.name, path=result.path_lower)
except Exception:
msg = "Please provide a correct folder path and name.\n"\
"Usage: `rm <foldername>` to delete a folder in root directory."
return msg
def dbx_write(client: Any, fn: str, content: str) -> str:
fn = '/' + fn
try:
result = client.files_upload(content.encode(), fn)
msg = "Written to file: " + URL.format(name=result.name, path=result.path_lower)
except Exception:
msg = "Incorrect file path or file already exists.\n"\
"Usage: `write <filename> CONTENT`"
return msg
def dbx_read(client: Any, fn: str) -> str:
fn = '/' + fn
try:
result = client.files_download(fn)
msg = "**{}** :\n{}".format(result[0].name, result[1].text)
except Exception:
msg = "Please provide a correct file path\n"\
"Usage: `read <filename>` to read content of a file"
return msg
def dbx_search(client: Any, query: str, folder: str, max_results: str) -> str:
if folder is None:
folder = ''
else:
folder = '/' + folder
if max_results is None:
max_results = '20'
try:
result = client.files_search(folder, query, max_results=int(max_results))
msg_list = []
count = 0
for entry in result.matches:
file_info = entry.metadata
count += 1
msg_list += [" - " + URL.format(name=file_info.name, path=file_info.path_lower)]
msg = '\n'.join(msg_list)
except Exception:
msg = "Usage: `search <foldername> query --mr 10 --fd <folderName>`\n"\
"Note:`--mr <int>` is optional and is used to specify maximun results.\n"\
" `--fd <folderName>` to search in specific folder."
if msg == '':
msg = "No files/folders found matching your query.\n"\
"For file name searching, the last token is used for prefix matching"\
" (i.e. “bat c” matches “bat cave” but not “batman car”)."
return msg
def dbx_share(client: Any, fn: str):
fn = '/' + fn
try:
result = client.sharing_create_shared_link(fn)
msg = result.url
except Exception:
msg = "Please provide a correct file name.\n"\
"Usage: `share <filename>`"
return msg
handler_class = DropboxHandler