Exemple #1
0
    def get_program(self):
        """Retrieve a program file from the Mpala Tower Dropbox listings."""
        # Must use Dropbox to get program files.
        from dropbox import Dropbox
        from posixpath import join
        import os

        # Set up the Dropbox connection. Not sure how access_tokens will work
        access_token = os.environ.get('access_token')
        dropbox_dir = os.environ.get('dropbox_dir')
        client = Dropbox(access_token)

        # If this is our first time with this file, set the program name and
        # location.
        self.program_location = join(
            dropbox_dir,
            program_location,
            self.program_name
        )
        # Retrieve the REST object from Dropbox
        prog_link = client.files_get_temporary_link(self.program_location)
        response = requests.get(prog_link.link)
        # Put the program file contents into an array for parsing
        program_content = response.text
        # Send that stuff back.
        return program_content
Exemple #2
0
def display():
    if 'access_token' not in session:
        abort(400)

    access_token = session['access_token']
    if 'job' in session:
        job = get_job_from_key(session['job'], conn)
        # Only rely on a previous result if the same user is logged in (same access_token)
        if job is not None and access_token == job.meta.get('access_token', None):
            return render_template('display.html', username=session['username'], quota=session['quota'], used=session['used'])

    try:
        client = Dropbox(access_token)
    except Exception:
        abort(401)

    account = client.users_get_current_account()
    session['username'] = account.name.display_name

    space_usage = client.users_get_space_usage()
    allocated, used = get_space_usage_info(space_usage)
    total_bytes = used
    session['used'] = human_readable(used)
    session['quota'] = human_readable(allocated)

    job = q.enqueue(walk_entire_dropbox, access_token, total_bytes)
    job.meta['access_token'] = access_token
    job.save()
    update_progress(job, 0, "/")
    session['job'] = job.key

    return render_template('display.html', username=session['username'], quota=session['quota'], used=session['used'])
def revision():
	dbx = Dropbox(session['access_token'])

	f = dbx.files_download(request.args['path'], request.args['rev'])
	resp = make_response(f[1].content)
	resp.headers["Content-Disposition"] = "attachment; filename=" + f[0].name

	return resp
Exemple #4
0
def i_am_dropbox(token):
    from dropbox import Dropbox
    my_client = Dropbox(token)
    file_list = my_client.files_list_folder('')
    #WE DID NOT CHECK HASMORE!
    folder_list = [x.name for x in file_list.entries if 'size' not in dir(x)]
   #print folder_list
    return folder_list
Exemple #5
0
 def dropBox (self, FILE, token, account_id):
     try:
         dbx = Dropbox(token)
         head, tails = os.path.split(FILE)
         with open(FILE, 'r') as f_in:
             mode = WriteMode('overwrite', None) #ADD SOME EXCEPTIONS HERE TO CATCH IF IT DOESNT UPLAD
             dbx.files_upload(f_in, '/'+tails, mode=mode)
     except Exception as e:
         return str(e)
Exemple #6
0
 def debug():
     """Debug todo synchronization code"""
     dropbox = db.session.query(models.Dropbox).first()  # type: models.Dropbox
     try:
         dbx = Dropbox(dropbox.access_token)
         md, res = dbx.files_download(path=dropbox.file_location)
     except ApiError as err:
         if err.error.is_path() and err.error.get_path().is_not_found():
             return 'File not found: ' + dropbox.file_location
         return 'Other error occurred'
     update_todos(content=res.content)
     return redirect(url_for('show_todos'))
Exemple #7
0
	def __init__(self, accessToken):
		super().__init__()
		self.dropbox = Dropbox(accessToken)
		_meta = self._meta = {
			"case_insensitive": False, # I think?
			"invalid_path_chars": ":", # not sure what else
			"max_path_length": None, # don't know what the limit is
			"max_sys_path_length": None, # there's no syspath
			"network": True,
			"read_only": False,
			"supports_rename": False # since we don't have a syspath...
		}
Exemple #8
0
class CloudDropbox(Wrapper):
    """ Wraps a Dropbox connection client.
    """
    wrapper_type = 'Dropbox connection'
    required_secret_attr = 'secret'
    required_secret_label = 'an OAuth 2 access token'

    def __init__(self, *args, **kwargs):
        super(CloudDropbox, self).__init__(*args, **kwargs)
        self._impl = None  # type: DropboxClient

# ################################################################################################################################

    def _init_impl(self):

        with self.update_lock:

            # Create a pool of at most that many connections
            session = create_session(50)

            scope = as_list(self.config.default_scope, ',')

            config = {
                'session': session,
                'user_agent': self.config.user_agent,
                'oauth2_access_token': self.server.decrypt(self.config.secret),
                'oauth2_access_token_expiration': int(self.config.oauth2_access_token_expiration or 0),
                'scope': scope,
                'max_retries_on_error': int(self.config.max_retries_on_error or 0),
                'max_retries_on_rate_limit': int(self.config.max_retries_on_rate_limit or 0),
                'timeout': int(self.config.timeout),
                'headers': parse_extra_into_dict(self.config.http_headers),
            }

            # Create the actual connection object
            self._impl = DropboxClient(**config)

            # Confirm the connection was established
            self.ping()

            # We can assume we are connected now
            self.is_connected = True

# ################################################################################################################################

    def _delete(self):
        if self._impl:
            self._impl.close()

# ################################################################################################################################

    def _ping(self):
        self._impl.check_user()
Exemple #9
0
    def __init__(self,
                 oauth2_access_token=oauth2_access_token,
                 root_path=location,
                 timeout=timeout,
                 write_mode=write_mode):
        if oauth2_access_token is None:
            raise ImproperlyConfigured("You must configure an auth token at"
                                       "'settings.DROPBOX_OAUTH2_TOKEN'.")

        self.root_path = root_path
        self.write_mode = write_mode
        self.client = Dropbox(oauth2_access_token, timeout=timeout)
class DropboxWriter(FilebaseBaseWriter):
    """
    Writes items to dropbox folder.
    options available

        - access_token (str)
            Oauth access token for Dropbox api.

        - filebase (str)
            Base path to store the items in the share.

    """
    supported_options = {
        'access_token': {'type': six.string_types, 'env_fallback': 'EXPORTERS_DROPBOXWRITER_TOKEN'},
    }

    def __init__(self, *args, **kw):
        from dropbox import Dropbox
        super(DropboxWriter, self).__init__(*args, **kw)
        access_token = self.read_option('access_token')
        self.set_metadata('files_counter', Counter())
        self.client = Dropbox(access_token)

    def write(self, dump_path, group_key=None, file_name=False):
        if group_key is None:
            group_key = []
        self._write_file(dump_path, group_key, file_name)

    @retry_long
    def _upload_file(self, input_file, filepath):
        from dropbox import files
        session_id = self.client.files_upload_session_start('')
        current_offset = 0
        while True:
            data = input_file.read(2**20)
            if not data:
                break
            self.client.files_upload_session_append(data, session_id.session_id, current_offset)
            current_offset += len(data)
        cursor = files.UploadSessionCursor(session_id.session_id, current_offset)
        self.client.files_upload_session_finish(
            '', cursor, files.CommitInfo(path='{}'.format(filepath)))

    def _write_file(self, dump_path, group_key, file_name=None):
        filebase_path, file_name = self.create_filebase_name(group_key, file_name=file_name)
        with open(dump_path, 'r') as f:
            self._upload_file(f, '{}/{}'.format(filebase_path, file_name))
        self.get_metadata('files_counter')[filebase_path] += 1

    def get_file_suffix(self, path, prefix):
        number_of_keys = self.get_metadata('files_counter').get(path, 0)
        suffix = '{}'.format(str(number_of_keys))
        return suffix
Exemple #11
0
def upload(dropbox_helper_id, access_token, size, max_retries):
    from .models import DropboxUploadHelper
    helper = DropboxUploadHelper.objects.get(id=dropbox_helper_id)

    def progress_callback(bytes_uploaded, helper=helper, size=size):
        helper.progress = float(bytes_uploaded) / size
        helper.save()

    try:
        dropbox_path = '/{}'.format(os.path.basename(helper.src))
        path_display = upload_to_dropbox(access_token, dropbox_path, helper.src, progress_callback)
    except Exception as e:
        helper.failure_reason = str(e)
        helper.save()

    couch_user = CouchUser.get_by_username(helper.user.username)
    if helper.failure_reason is None:
        dbx = Dropbox(access_token)
        path_link_metadata = dbx.sharing_create_shared_link_with_settings(
            path_display,
            SharedLinkSettings(
                requested_visibility=RequestedVisibility.team_only,
            ),
        )
        context = {
            'share_url': path_link_metadata.url,
            'path': os.path.join(
                'Apps',
                settings.DROPBOX_APP_NAME,
                path_link_metadata.name,
            )
        }
        with localize(couch_user.get_language_code()):
            subject = _('{} has been uploaded to dropbox!'.format(helper.dest))
            html_content = render_to_string('dropbox/emails/upload_success.html', context)
            text_content = render_to_string('dropbox/emails/upload_success.txt', context)
    else:
        context = {
            'reason': helper.failure_reason,
            'path': helper.dest
        }
        with localize(couch_user.get_language_code()):
            subject = _('{} has failed to upload to dropbox'.format(helper.dest))
            html_content = render_to_string('dropbox/emails/upload_error.html', context)
            text_content = render_to_string('dropbox/emails/upload_error.txt', context)

    send_HTML_email(
        subject,
        helper.user.email,
        html_content,
        text_content=text_content,
    )
Exemple #12
0
def authorize_folder(emailAddress=None,
                     folderId=None,
                     folderName=None,
                     *args,
                     **kwargs):
    dbx = Dropbox(os.getenv('DROPBOX_TOKEN', None))
    if not folderId:
        folderId = get_shared_folder_by_name(folderName).shared_folder_id
    members = [
        dropbox.sharing.AddMember(
            dropbox.sharing.MemberSelector.email(emailAddress))
    ]
    return dbx.sharing_add_folder_member(folderId, members)
def files():
    if access_token:
        dbx = Dropbox(access_token)
    else:
        return redirect(url_for("oauth2_start", _external=True, _scheme="https"))
    if request.args.get("days"):
        days = int(request.args.get("days"))
    else:
        days = 100
    time_delta = datetime.now() - timedelta(days=days)
    file_objs = dbx.files_list_folder("", recursive=True).entries
    files_json = process_files(file_objs, time_delta)
    return render_template("files.html", selected_files=files_json[:50])
Exemple #14
0
class DropboxHelper(object):
    def __init__(self, access_token):
        self.dropbox = Dropbox(oauth2_access_token=access_token)

    def upload(self, filename, file_path):
        with open(file_path, 'rb') as f:
            try:
                self.dropbox.files_upload(f.read(), '/' + filename)
            except Exception:
                os.remove(file_path)
                raise CommandError(
                    'Unable to upload file to Dropbox. Maybe access token is invalid.'
                )

    def delete_all_files(self):
        for i in self.dropbox.files_list_folder('').entries:
            self.dropbox.files_delete(i.path_lower)

    def download_last_backup(self, dir_path):
        entries = self.dropbox.files_list_folder('').entries

        if len(entries) == 0:
            raise CommandError('We could not find any backup.')

        entry = entries[-1]
        full_path = dir_path + entry.path_lower

        self.dropbox.files_download_to_file(full_path, entry.path_lower)
        return full_path, entry.content_hash
Exemple #15
0
class DropboxHelper(object):

    def __init__(self, access_token):
        self.dropbox = Dropbox(oauth2_access_token=access_token)

    def upload(self, filename, file_path):
        with open(file_path, 'rb') as f:
            try:
                self.dropbox.files_upload(f.read(), '/' + filename)
            except Exception:
                os.remove(file_path)
                raise CommandError('Unable to upload file to Dropbox. Maybe access token is invalid.')

    def delete_all_files(self):
        for i in self.dropbox.files_list_folder('').entries:
            self.dropbox.files_delete(i.path_lower)

    def download_last_backup(self, dir_path):
        entries = self.dropbox.files_list_folder('').entries

        if len(entries) == 0:
            raise CommandError('We could not find any backup.')

        entry = entries[-1]
        full_path = dir_path + entry.path_lower

        self.dropbox.files_download_to_file(full_path, entry.path_lower)
        return full_path, entry.content_hash
def store_document(export_format: str, tracker: Tracker, dbx: dropbox.Dropbox,
                   document_id: str):
    """ Download a document to the local file system. 
    
    :param export_format: The format to store the document in. Possible values are "html", "markdown" 
        or "all". For "html" also referenced images are downloaded.
    :param tracker: Instance of the tracker to create new files with.
    :param dbx: Dropbox instance with logged in account with sufficient permissions to download documents.
    :param document_id: The document id if the paper document to download.    
    """

    try:
        folders = [
            folder.name.replace('/', '+') for folder in
            dbx.paper_docs_get_folder_info(document_id).folders or []
        ]
    except dropbox.exceptions.ApiError:
        folders = []

    try:

        if export_format == 'html' or export_format == 'all':
            document_meta, document_body = dbx.paper_docs_download(
                document_id, dropbox.paper.ExportFormat('html'))
            document_reference = "%s-%s" % (document_id,
                                            document_meta.revision)
            content = replace_images(tracker, folders, document_reference,
                                     document_body.content)
            file_name = "%s [%s].html" % (document_meta.title.replace(
                '/', '+'), document_reference)
            with tracker.file_handler(folders, file_name) as fd:
                if fd:
                    fd.write(content)

        if export_format == 'markdown' or export_format == 'all':
            document_meta, document_body = dbx.paper_docs_download(
                document_id, dropbox.paper.ExportFormat('markdown'))
            document_reference = "%s-%s" % (document_id,
                                            document_meta.revision)
            content = document_body.content
            file_name = "%s [%s].md" % (document_meta.title.replace(
                '/', '+'), document_reference)
            with tracker.file_handler(folders, file_name) as fd:
                if fd:
                    fd.write(content)

    except dropbox.exceptions.ApiError as e:
        logging.exception('dropbox api error for document %s: %s', document_id,
                          e)
Exemple #17
0
    def post(self, whose):
        token = request.get_json()['access_token']
        db = Dropbox(token)

        if whose == 'mine':
            start = time.clock()
            budgets = db.get_own_budgets()
            end = time.clock()
            flask_app.logger.debug("Get own budgets time elapsed: {time}s".format(time=(end - start)))
        elif whose == 'theirs':
            start = time.clock()
            budgets = db.get_their_budgets()
            end = time.clock()
            flask_app.logger.debug("Get their budgets time elapsed: {time}s".format(time=(end - start)))
        return budgets
Exemple #18
0
 def __init__(self,
              oauth2_access_token=oauth2_access_token,
              root_path=location,
              timeout=timeout,
              write_mode=write_mode):
     if oauth2_access_token is None:
         raise ImproperlyConfigured("You must configure an auth token at"
                                    "'settings.DROPBOX_OAUTH2_TOKEN'.")
     if write_mode not in ["add", "overwrite", "update"]:
         raise ImproperlyConfigured(
             "DROPBOX_WRITE_MODE must be set to either: 'add', 'overwrite' or 'update'"
         )
     self.root_path = root_path
     self.write_mode = write_mode
     self.client = Dropbox(oauth2_access_token, timeout=timeout)
Exemple #19
0
def upload_to_dropbox(video_file_path):
    """
    Dropbox is an unoffical feature - This code worked at one point,
    but official support was removed for several reasons.
    """
    try:
        file_size = os.path.getsize(video_file_path)
        if file_size <= FILE_CHUNK_SIZE:
            dbx = Dropbox(DROPBOX_API_KEY)
            f = open(video_file_path, 'rb')
            dbx.files_upload(f, video_file_path)
        else:
            upload_dropbox_file_chucks(video_file_path, file_size)
    except Exception as e:
        print('Unhandled exception while uploading files - {}'.format(e))
Exemple #20
0
    def __init__(self, oauth2_access_token: str = None, root_path: str = None):
        """
        The access token and root path may be provided here as well,
        if they are not provided here, program will check settings for environment variables

        :param oauth2_access_token: The OAUTH2 access token for the DropBox api
        :param root_path: The root path for storing the files in the DropBox storage, defaults '/'
        """
        oauth2_access_token = oauth2_access_token or settings.DROPBOX_OAUTH2_TOKEN
        self.root_path = root_path or settings.DROPBOX_ROOT_PATH or '/'
        if oauth2_access_token is None:
            raise ImproperlyConfigured(
                "You must configure an OATH2 access token ENV named "
                "'DROPBOX_OAUTH2_TOKEN'.")
        self.client = Dropbox(oauth2_access_token)
def paper_documents(dbx: dropbox.Dropbox, page_size=1000):
    """ Get all dropbox paper document ids in this account.
    
    :param dbx: Dropbox instance with logged in account with sufficient permissions to list documents.
    :param page_size: Number of document ids to to get with one request.
    :return: Dropbox Paper ids.  
    """
    listing = dbx.paper_docs_list(limit=page_size)
    while True:
        for document_id in listing.doc_ids:
            yield document_id
        if listing.has_more:
            listing = dbx.paper_docs_list_continue(listing.cursor.value)
        else:
            break
Exemple #22
0
 def authenticate(self):
     auth_code = self.widgetLogin.lineEdit.text()
     try:
         access_token, user_id = self.widgetLogin.auth_flow.finish(
             auth_code)
         self.dbx = Dropbox(access_token)
         user_info = self.dbx.users_get_current_account()
         self.widgetOptions.labelName.setText(user_info.name.display_name)
         self.widgetLogin.hide()
         self.widgetOptions.show()
         self.widgetOptions.dbx = self.dbx
         self.widgetOptions.thread.start()
         self.save_token(access_token)
     except:
         self.widgetLogin.labelError.setText('Invalid code, try again.')
Exemple #23
0
def revisions():
    # Shared Link from Dropbox Chooser
    link = request.args["link"]

    # Calling Dropbox API v1
    metadata = requests.post(
        "https://api.dropbox.com/1/metadata/link",
        params={"link": link},
        headers={"Authorization": "Bearer " + str(session["access_token"])},
    ).json()

    # Calling Dropbox API v2
    dbx = Dropbox(session["access_token"])
    entries = dbx.files_list_revisions(metadata["path"]).entries

    return render_template("revisions.html", path=metadata["path"], revisions=entries)
def refresh_dbx_from_env():
    refresh_token = _value_from_env_or_die("DROPBOX_REFRESH_TOKEN")
    app_key = _value_from_env_or_die("DROPBOX_APP_KEY")
    app_secret = _value_from_env_or_die("DROPBOX_APP_SECRET")
    return Dropbox(oauth2_refresh_token=refresh_token,
                   app_key=app_key,
                   app_secret=app_secret)
Exemple #25
0
    def _init_impl(self):

        with self.update_lock:

            # Create a pool of at most that many connections
            session = create_session(50)

            scope = as_list(self.config.default_scope, ',')

            config = {
                'session': session,
                'user_agent': self.config.user_agent,
                'oauth2_access_token': self.server.decrypt(self.config.secret),
                'oauth2_access_token_expiration': int(self.config.oauth2_access_token_expiration or 0),
                'scope': scope,
                'max_retries_on_error': int(self.config.max_retries_on_error or 0),
                'max_retries_on_rate_limit': int(self.config.max_retries_on_rate_limit or 0),
                'timeout': int(self.config.timeout),
                'headers': parse_extra_into_dict(self.config.http_headers),
            }

            # Create the actual connection object
            self._impl = DropboxClient(**config)

            # Confirm the connection was established
            self.ping()

            # We can assume we are connected now
            self.is_connected = True
Exemple #26
0
 def __init__(self, oauth2_access_token=None, root_path=None):
     oauth2_access_token = oauth2_access_token or setting('DROPBOX_OAUTH2_TOKEN')
     self.root_path = root_path or setting('DROPBOX_ROOT_PATH', '/')
     if oauth2_access_token is None:
         raise ImproperlyConfigured("You must configure a token auth at"
                                    "'settings.DROPBOX_OAUTH2_TOKEN'.")
     self.client = Dropbox(oauth2_access_token)
Exemple #27
0
class Cliente:

    def __init__(self):

        self.auth_flow = DropboxOAuth2FlowNoRedirect(APP_KEY, APP_SECRET)
        self.authorize_url = self.auth_flow.start()

        self.dbx = None
        self.tree = Tree()

        self.path_actual = '' # Si el string es vacío estamos en el root


    def get_auth(self, auth_code):
        try:
            access_token, user_id = self.auth_flow.finish(auth_code)
        except Exception as e:
            print('Error: %s' % (e,))
            return False
        else:
            self.dbx = Dropbox(access_token)
            self.setup_tree(self.tree.root, '')
            return True

    def setup_tree(self, nodo_actual, path):

        print(threading.current_thread().name)
        lista = self.dbx.files_list_folder(path, recursive=False).entries
        for entry in lista:
            nodo = Nodo(entry.name, entry)
            self.tree.agregar_nodo(nodo_padre=nodo_actual, nodo_hijo=nodo)
            if isinstance(entry, files.FolderMetadata):
                t = threading.Thread(name=entry.name ,target=self.setup_tree, args=(nodo, entry.path_lower))
                t.setDaemon(True)
                t.start()
 def wrapped(self, *args, **kwargs):
     refresh_token = _token_from_env_or_die("DROPBOX_REFRESH_TOKEN")
     app_key = _token_from_env_or_die("DROPBOX_APP_KEY")
     app_secret = _token_from_env_or_die("DROPBOX_APP_SECRET")
     args += (Dropbox(oauth2_refresh_token=refresh_token,
                      app_key=app_key, app_secret=app_secret),)
     return f(self, *args, **kwargs)
def get_dropbox_client(access_token=""):
    """
    Given an access_token, return a Dropbox client.  If the access_token is an
    empty string, prompt user to authenticate the app to Dropbox and create a
    client using the returned access_token.
    
    :param access_token: string
    :return: Dropbox
    """

    if access_token == "":
        # connect to dropbox and start the session authorization process
        flow = DropboxOAuth2FlowNoRedirect(conf["dropbox_key"], conf["dropbox_secret"])
        print("[INFO] Authorize this application: {}".format(flow.start()))
        authCode = input("Enter auth code here: ").strip()

        # finish the authorization and grab the Dropbox client
        access_token = flow.finish(authCode).access_token

        # Display the access token so it can be stored for later use.
        # @todo: have the program write this out somewhere so it doesn't have to be done manually.
        logging.info("################")
        logging.info("Your access token is {}. set this value in conf.json so you don't have to reauthenticate \
    			each time the program is run".format(access_token))
        logging.info("################")

    client = Dropbox(access_token)
    logging.info("Dropbox client connected.")
    return client
class TestDropbox(unittest.TestCase):

    def setUp(self):
        self.dbx = Dropbox(oauth2_token)

    def test_bad_auth(self):
        # Test malformed token
        malformed_token_dbx = Dropbox(MALFORMED_TOKEN)
        with self.assertRaises(BadInputError) as cm:
            malformed_token_dbx.files_list_folder('')
        self.assertIn('token is malformed', cm.exception.message)

        # Test reasonable-looking invalid token
        invalid_token_dbx = Dropbox(INVALID_TOKEN)
        with self.assertRaises(AuthError) as cm:
            invalid_token_dbx.files_list_folder('')
        self.assertEqual(cm.exception.error['error']['.tag'],
                         'invalid_access_token')

    def test_rpc(self):
        self.dbx.files_list_folder('')

        # Test API error
        random_folder_path = '/' + \
                             ''.join(random.sample(string.ascii_letters, 15))
        with self.assertRaises(ApiError) as cm:
            self.dbx.files_list_folder(random_folder_path)
        self.assertIsInstance(cm.exception.error, ListFolderError)

    def test_upload_download(self):
        # Upload file
        timestamp = str(datetime.datetime.utcnow())
        random_filename = ''.join(random.sample(string.ascii_letters, 15))
        random_path = '/Test/%s/%s' % (timestamp, random_filename)
        test_contents = string.ascii_letters
        self.dbx.files_upload(test_contents, random_path)

        # Download file
        metadata, resp = self.dbx.files_download(random_path)
        self.assertEqual(string.ascii_letters, resp.text)

        # Cleanup folder
        self.dbx.files_delete('/Test/%s' % timestamp)

    @require_team_token
    def test_team(self, token):
        dbxt = DropboxTeam(token)
        dbxt.team_groups_list()
        r = dbxt.team_members_list()
        if r.members:
            # Only test assuming a member if there is a member
            dbxt.as_user(r.members[0].profile.team_member_id).files_list_folder('')
Exemple #31
0
def revisions():
	# Shared Link from Dropbox Chooser
	link = request.args['link']

	# Calling Dropbox API v1
	metadata = requests.post('https://api.dropbox.com/1/metadata/link', params={'link': link},
		headers={'Authorization': 'Bearer ' + str(session['access_token'])}).json()

	# Calling Dropbox API v2
	if not metadata.get('path'):
		return redirect(url_for('index'))
	else:
		dbx = Dropbox(session['access_token'])
		entries = sorted(dbx.files_list_revisions(metadata['path']).entries, key=lambda entry: entry.client_modified)
		entries.reverse()
		return render_template('revisions.html', path=metadata['path'], filename=os.path.split(metadata['path'])[1],
			revisions=entries)
Exemple #32
0
    def _update_secrets(self):
        """update secrets will look for a dropbox token in the environment at
           SREGISTRY_DROPBOX_TOKEN and if found, create a client. If not,
           an error message is returned and the client exits.
        """

        # Retrieve the user token. Exit if not found
        token = self._required_get_and_update("SREGISTRY_DROPBOX_TOKEN")

        # Create the dropbox client
        self.dbx = Dropbox(token)

        # Verify that the account is valid
        try:
            self.account = self.dbx.users_get_current_account()
        except:
            bot.exit("Account invalid. Exiting.")
    def __init__(self, rootdir, oauth2_access_token,
                 connection_kwargs=None, files_upload_kwargs=None,
                 files_list_folder_kwargs=None, rev=None):

        if connection_kwargs is None:
            connection_kwargs = {}
        if files_upload_kwargs is None:
            files_upload_kwargs = {'mode': WriteMode.overwrite}
        if files_list_folder_kwargs is None:
            files_list_folder_kwargs = {'recursive': True, 'include_non_downloadable_files': False}

        self._prefix = rootdir
        self._con = Dropbox(oauth2_access_token, **connection_kwargs)
        self._connection_kwargs = connection_kwargs
        self._files_upload_kwargs = files_upload_kwargs
        self._files_list_folder_kwargs = files_list_folder_kwargs
        self._rev = rev
Exemple #34
0
 def checkFolder(self, accessToken, folder):
     try:
         client = Dropbox(accessToken, session=create_session(proxies=self.__proxies))
         self.__createFolder(client, folder + "/entries/deleted")
         self.__createFolder(client, folder + "/photos/deleted")
     except ApiError:
         return False
     return True
Exemple #35
0
 def test_Dropbox_with_expired_offline_token(self, session_instance):
     # Test Offline Case w/ invalid access
     Dropbox(oauth2_access_token=ACCESS_TOKEN,
             oauth2_refresh_token=REFRESH_TOKEN,
             oauth2_access_token_expiration=EXPIRATION - timedelta(weeks=1),
             app_key=APP_KEY,
             app_secret=APP_SECRET,
             session=session_instance)
    def chunk(self, path, filename, size, offset=0):
        """
        return one chunk of file

        :param str path: path on server
        :param str filename: name of file
        :param int size: chunk-size
        :param int offset: bits from the beginning
        :return: tuple(File obj, content)
        """
        p_session = session()
        dbx_p = Dropbox(oauth2_access_token=self._access_token, headers={
            "Range": "bytes=" + str(offset) + "-" + str(offset + size - 1)}, session=p_session)  # fetch chunks from dropbox
        meta, response = dbx_p.files_download(path+"/"+filename)
        f = File(meta.name, meta.path_lower, meta.client_modified, meta.client_modified)
        p_session.close()
        return f, response.content
Exemple #37
0
    def sync():
        challenge = request.args.get('challenge')
        if challenge is not None:
            return challenge

        """Synchronize database with todo.txt"""
        dropbox = db.session.query(models.Dropbox).first()  # type: models.Dropbox

        # Make sure this is a valid request from Dropbox
        signature = request.headers.get('X-Dropbox-Signature')
        if not hmac.compare_digest(signature, hmac.new(dropbox.secret.encode(), request.data, sha256).hexdigest()):
            app.logger.warn('Invalid sync request attempted')
            abort(403)

        dbx = Dropbox(dropbox.access_token)
        if dropbox.cursor is None:
            result = dbx.files_list_folder(path=os.path.dirname(dropbox.file_location))
        else:
            result = dbx.files_list_folder_continue(cursor=dropbox.cursor)

        # Check if todo.txt was changed
        found = False
        for metadata in result.entries:  # type: Metadata
            if metadata.path_lower == dropbox.file_location.lower():
                found = True
                break
        if not found:
            dropbox.cursor = result.cursor
            db.session.merge(dropbox)
            db.session.commit()
            return ''

        app.logger.info('Sync request made')

        try:
            md, res = dbx.files_download(path=dropbox.file_location)
        except ApiError as err:
            if err.error.is_path() and err.error.get_path().is_not_found():
                return 'File not found: ' + dropbox.file_location
            return 'Other error occurred'
        update_todos(content=res.content)

        dropbox.cursor = result.cursor
        db.session.merge(dropbox)
        db.session.commit()
        return ''
Exemple #38
0
    def post(self):
        method_start = time.clock()
        flask_app.logger.info("Comparing budgets")

        json = request.get_json()
        token = json['access_token']
        this_budget_path = json['this_budget_path']
        other_budget_path = json['other_budget_path']

        db = Dropbox(token)

        start = time.clock()
        this_json = db.get_budget_file(this_budget_path)
        end = time.clock()
        elapsed = end - start
        flask_app.logger.debug("Get this budget time elapsed: {time}s".format(time=elapsed))

        start = time.clock()
        other_json = db.get_budget_file(other_budget_path)
        end = time.clock()
        elapsed = end - start
        flask_app.logger.debug("Get other budget time elapsed: {time}s".format(time=elapsed))

        this_target_category = json['this_target_category']
        other_target_category = json['other_target_category']

        start_date = json['comparison_start_date']

        comparer = YnabBudgetComparer(this_json, this_target_category, other_json, other_target_category)
        comparer.set_start_date(start_date)

        start = time.clock()
        missing_txns = comparer.get_missing_transactions()
        end = time.clock()
        flask_app.logger.debug("Find missing transactions time elapsed: {time}s".format(time=(end - start)))

        method_finish = time.clock()
        method_elapsed = method_finish - method_start
        flask_app.logger.info("Finished comparing budgets. Time elapsed: {time}s".format(time=method_elapsed))

        this_payees = comparer.get_this_payees()
        other_payees = comparer.get_other_payees()

        return {"this_missing": missing_txns[0], "other_missing": missing_txns[1],
                "this_payees": this_payees, "other_payees": other_payees}
Exemple #39
0
def process_user(uid):
    '''Call /delta for the given user ID and process any changes.'''

    # OAuth token for the user
    token = redis_client.hget('tokens', uid)

    # /delta cursor for the user (None the first time)
    cursor = redis_client.hget('cursors', uid)

    dbx = Dropbox(token)
    has_more = True
    trello_client = trello.TrelloClient(TRELLO_API_KEY, token=TRELLO_API_TOKEN)

    while has_more:
        if cursor is None:
            result = dbx.files_list_folder(path='/remote_workspace')
        else:
            result = dbx.files_list_folder_continue(cursor)

        for entry in result.entries:
            # Ignore deleted files, folders, and non-markdown files
            if (isinstance(entry, DeletedMetadata) or isinstance(entry, FolderMetadata)):
                continue

            card = get_card_by_name(trello_client, entry.name.encode('utf-8'))
            
            if(card == False):
                trello_post(trello_client, entry.name.encode('utf-8'))
                continue

            card.set_pos("top")
            card.comment("update! revision: %s" % entry.rev)

            revs = dbx.files_list_revisions(entry.path_lower)
            if(card.list_id == "577db30f129e87073996cc1a" and len(revs.entries) >= 2):
                card.change_list("577db3127b9a95030e956ab8")



        # Update cursor
        cursor = result.cursor
        redis_client.hset('cursors', uid, cursor)

        # Repeat only if there's more to do
        has_more = result.has_more
Exemple #40
0
 def client(self, request):
     redirect_uri = reverse('dropbox_integration:oauth2_callback')
     oauth = DropboxOAuth2Flow(
         consumer_key=settings.DROPBOX_APP_KEY,
         consumer_secret=settings.DROPBOX_APP_SECRET,
         redirect_uri=request.build_absolute_uri(redirect_uri),
         session=request.session['dropbox'],
         csrf_token_session_key='state')
     return Dropbox(oauth.access_token)
Exemple #41
0
def download_file(dbx: dropbox.Dropbox, local_report_file_path: Path,
                  remote_report_file_path: str):
    try:
        metadata, response = dbx.files_download(remote_report_file_path)
        with local_report_file_path.open(mode='wb') as report_file:
            report_file.write(response.content)

    except ApiError as e:
        sys.exit(f"Error: {e}")
def delete():
    if access_token:
        dbx = Dropbox(access_token)
        path_lower = request.json["path_lower"]
        loop = 0
        result = False
        while not result and loop <= 9:
            try:
                metadata = dbx.files_delete(path_lower)
                result = True
            except ApiError:
                pass
            loop += 1
        if not result:
            return redirect(url_for("files", _external=True, _scheme="https"))
        return json.dumps({"success": True}), 200, {"ContentType": "application/json"}
    else:
        return redirect(url_for("oauth2_start", _external=True, _scheme="https"))
Exemple #43
0
def get_list_of_files():
    get_or_create_folder()

    dbx = Dropbox(get_token())
    response = dbx.files_list_folder(path='/Mainstay')

    files = []

    for file in response.entries:
        files.append({
            'name': file.name,
            'extension': file.name.split('.')[-1],
            'size': round(int(file.size) / (1024 * 1024), 2),
            'date_modified': file.server_modified,
            'checksum': file.content_hash
        })

    return files
    def get_handler(api_key: str) -> Dropbox:
        """
        Returns a Cloudstore handler.

        :param api_key:
        :return:
        """

        dbx = Dropbox(api_key)
        return dbx
    def test_bad_auth(self):
        # Test malformed token
        malformed_token_dbx = Dropbox(MALFORMED_TOKEN)
        with self.assertRaises(BadInputError) as cm:
            malformed_token_dbx.files_list_folder('')
        self.assertIn('token is malformed', cm.exception.message)

        # Test reasonable-looking invalid token
        invalid_token_dbx = Dropbox(INVALID_TOKEN)
        with self.assertRaises(AuthError) as cm:
            invalid_token_dbx.files_list_folder('')
        self.assertTrue(cm.exception.error.is_invalid_access_token())
Exemple #46
0
def download_dropboxfiles(payload):
    # Get the Project
    project = Project.objects.get(pk=payload['project_id'])
    project.set_status('downloading')

    # Check to see what files to download from Dropbox
    client = Dropbox(project.user.dropboxinfo.access_token)
    num_files = 0
    for x in client.files_list_folder(project.path).entries:
        if x.path_lower.endswith('.jpg') and x.size > 0:
            # Download the file from Dropbox to local disk
            local_filename = os.path.split(x.path_lower)[-1]
            local_filepath = os.path.join(project.originals_path, local_filename)
            num_files += 1
            if os.path.exists(local_filepath): # and not payload.get('redownload') == True
                continue
            client.files_download_to_file(local_filepath, x.path_lower)

    
    # Get the metadata as a separate task
    new_task(project.user, {
        'action': 'extract_metadata',
        'project_id': project.pk
    })

    # schedule a thumbnail task
    new_task(project.user, {
        'action': 'makethumbnails',
        'project_id': project.pk
    })


    # Downloading files can take a long time
    # In the meantime this Project could have been changed by other tasks
    # Reload it before setting the status
    project = Project.objects.get(pk=payload['project_id'])
    project.num_files_on_dropbox = num_files
    project.status = 'layout'
    project.save()
    return {'downloaded_files_count':num_files}
Exemple #47
0
class DropboxConnector:
    def __init__(self, account):
        self.client = Dropbox(account["access_token"])

    # Dropbox does not like the "/" path for some stupid reason...
    # "" refers to the root directory
    @staticmethod
    def convert_to_dropbox_path(path):
        if path == "/":
            return ""
        else:
            return path

    def make_directory(self, path):
        self.client.files_create_folder(path)

    def change_mode(self, path, mode):
        pass

    def change_owner(self, path, user_id, group_id):
        pass

    def getattr(self, path, file_handle=None):
        dropbox_path = DropboxConnector.convert_to_dropbox_path(path)
        metadata = self.client.files_get_metadata(dropbox_path)
        file_status = FileStatus()

        # I'm going to change this hard coded stuff later
        file_status.group_id = 20
        file_status.user_id = 501

    @property
    def total_storage(self):
        space_usage = self.client.users_get_space_usage()
        return space_usage.allocation.get_individual().allocated

    @property
    def free_storage(self):
        space_usage = self.client.users_get_space_usage()
        return space_usage.used
Exemple #48
0
    def find_files(year=None, doy=None):
        """Find netcdf files correponding to year and doy on Dropbox."""
        from dropbox import Dropbox
        from posixpath import join
        import os

        access_token = os.environ.get('access_token')
        dropbox_dir = os.environ.get('dropbox_dir')

        client = Dropbox(access_token)

        files = []  # Initialize an empty array
        f = 'raw_MpalaTower_{year}_{doy:03d}.nc'.format(
            year=year, doy=doy)
        program_list = DATA_FILES
        program_list.remove('unknown')
        for this_file in program_list:
            file_location = join(dropbox_dir, netcdf_location, this_file)
            matches = []
            # listdict has a good metadata in it if we ever decide to use it
            results = client.files_search(file_location, f, max_results=1)
            matches = results.matches
            if matches:
                match = matches[0]
                temp_location = write_temp(
                    client,
                    match.metadata.path_display,
                    this_file,
                    f
                )
                this_file = File(
                    filename=f,
                    datafile=this_file,
                    file_location=temp_location,
                )
                files.append(this_file)
            else:
                continue
        return files
Exemple #49
0
    def authenticate(self, **credentials):
        #TODO user_id comes in here?
        account_id, access_token = credentials.get('account_id'), credentials.get('access_token')
        client = Dropbox(access_token)
        info = client.users_get_current_account()
        # Django User object has a max length of 30, so we can't store the account_id which is longer
        # So let's just save it as a hash
        account_id_hash = str(binascii.crc32(account_id))
        try:
            user = User.objects.get(username=account_id_hash)
        except User.DoesNotExist:
            user = User.objects.create(username=account_id_hash, 
                                       password='******',
                                       last_name=info.name.display_name,
                                       email=info.email,
                                       is_active=False)
            DropBoxInfo.objects.create(user=user, access_token=access_token)
            send_mail('A new Metabotnik user has registered', 
                      'And the user %s is https://metabotnik.com/admin/auth/user/%s/' % (user.last_name, user.pk), 
                          '*****@*****.**', ['*****@*****.**'], fail_silently=True)

        return user
Exemple #50
0
def upload_to_dropbox(access_token, dropbox_path, file_path, progress_callback=None):
    dbx = Dropbox(access_token)
    with open(file_path, 'rb') as file:
        chunk = file.read(CHUNK_SIZE)
        offset = len(chunk)

        upload_session = dbx.files_upload_session_start(chunk)
        progress_callback and progress_callback(offset)

        while True:
            chunk = file.read(CHUNK_SIZE)
            if not chunk:
                break
            dbx.files_upload_session_append_v2(
                chunk,
                UploadSessionCursor(
                    upload_session.session_id,
                    offset,
                ),
            )
            offset += len(chunk)
            progress_callback and progress_callback(offset)

        file_metadata = dbx.files_upload_session_finish(
            b'',
            UploadSessionCursor(
                upload_session.session_id,
                offset=offset,
            ),
            CommitInfo(
                dropbox_path,
                # When writing the file it won't overwrite an existing file, just add
                # another file like "filename (2).txt"
                WriteMode('add'),
            ),
        )
        progress_callback and progress_callback(offset)
        return file_metadata.path_display
Exemple #51
0
def i_am_thumb(token):
    import dropbox
    from dropbox import Dropbox
    import base64
    
    my_client = Dropbox(token)
    folderfile_list = my_client.files_list_folder('',True,True)
    
    file_list  =  [x for x in folderfile_list.entries if 'media_info' in dir(x)]
    image_list =  [x for x in file_list if not x.media_info == None]
    
    print "IMAGES ", image_list
    
    img_data = []
    for image in image_list:
        m,f = my_client.files_get_thumbnail(image.path_lower,\
                                        dropbox.files.ThumbnailFormat('png', value=None),\
                                        dropbox.files.ThumbnailSize('w128h128', None))
                                        
        encoded = base64.b64encode(f.content) 
        img_data.append (encoded)
        
    return img_data
    def test_bad_auth(self):
        # Test malformed token
        malformed_token_dbx = Dropbox(MALFORMED_TOKEN)
        with self.assertRaises(BadInputError) as cm:
            malformed_token_dbx.files_list_folder('')
        self.assertIn('token is malformed', cm.exception.message)

        # Test reasonable-looking invalid token
        invalid_token_dbx = Dropbox(INVALID_TOKEN)
        with self.assertRaises(AuthError) as cm:
            invalid_token_dbx.files_list_folder('')
        self.assertTrue(cm.exception.error.is_invalid_access_token())
Exemple #53
0
    def __init__(self, access_token, collection_name=''):
        
        '''
            a method to initialize the dropboxClient class
            
        :param access_token: string with oauth2 access token for users account
        '''    

        title = '%s.__init__' % self.__class__.__name__
    
    # construct input validation model
        self.fields = jsonModel(self._class_fields)
        
    # validate inputs
        input_fields = {
            'access_token': access_token,
            'collection_name': collection_name
        }
        for key, value in input_fields.items():
            object_title = '%s(%s=%s)' % (title, key, str(value))
            self.fields.validate(value, '.%s' % key, object_title)
    
    # workaround for module namespace conflict
        from sys import path as sys_path
        sys_path.append(sys_path.pop(0))
        from dropbox import Dropbox
        from dropbox.files import FileMetadata, WriteMode, DeleteArg
        from dropbox.exceptions import ApiError
        sys_path.insert(0, sys_path.pop())
    
    # construct dropbox client
        from labpack.compilers.objects import _method_constructor
        self.dropbox = Dropbox(oauth2_access_token=access_token)
    
    # construct dropbox objects
        self.objects = _method_constructor({
            'FileMetadata': FileMetadata,
            'ApiError': ApiError,
            'WriteMode': WriteMode,
            'DeleteArg': DeleteArg
        })
    
    # construct collection name
        self.collection_name = collection_name
Exemple #54
0
    def login(self):
        if self.load_access_token() is None:
            self.obtain_access_token()

        self.api_client = Dropbox(self.load_access_token())
        self.api_account = None
        try:
            log.Debug('dpbx,users_get_current_account([token])')
            self.api_account = self.api_client.users_get_current_account()
            log.Debug("dpbx,%s" % self.api_account)

        except (BadInputError, AuthError) as e:
            log.Debug('dpbx,exception: %s' % e)
            log.Info("dpbx: Authentication failed. Trying to obtain new access token")

            self.obtain_access_token()

            # We're assuming obtain_access_token will throw exception. So this line should not be reached
            raise BackendException("dpbx: Please update DPBX_ACCESS_TOKEN and try again")

        log.Info("dpbx: Successfully authenticated as %s" % self.api_account.name.display_name)
 def setUp(self):
     self.dbx = Dropbox(oauth2_token)
Exemple #56
0
#         # Start the auth flow again.
#         redirect_to("/dropbox-auth-start")
#     except CsrfException as e:
#         http_status(403)
#     except NotApprovedException as e:
#         flash('Not approved?  Why not?')
#         return redirect_to("/home")
#     except ProviderException as e:
#         logger.log("Auth error: %s" % (e,))
#         http_status(403)

from dropbox import DropboxOAuth2FlowNoRedirect
from dropbox import Dropbox

APP_KEY='cbm74gzdx3jn00g'
APP_SECRET='chq2mprrc8ldtfg'
auth_flow = DropboxOAuth2FlowNoRedirect(APP_KEY, APP_SECRET)

authorize_url = auth_flow.start()
print ("1. Go to: " + authorize_url)
print ("2. Click \"Allow\" (you might have to log in first).")
print ("3. Copy the authorization code.")
auth_code = input("Enter the authorization code here: ").strip()

try:
    access_token, user_id = auth_flow.finish(auth_code)
except Exception as e:
    print('Error: %s' % (e,))

dbx = Dropbox(access_token)
print(dbx.users_get_current_account())
Exemple #57
0
class DPBXBackend(duplicity.backend.Backend):
    """Connect to remote store using Dr*pB*x service"""

    def __init__(self, parsed_url):
        duplicity.backend.Backend.__init__(self, parsed_url)

        self.api_account = None
        self.api_client = None
        self.auth_flow = None

        self.login()

    def load_access_token(self):
        return os.environ.get('DPBX_ACCESS_TOKEN', None)

    def save_access_token(self, access_token):
        raise BackendException('dpbx: Please set DPBX_ACCESS_TOKEN=\"%s\" environment variable' % access_token)

    def obtain_access_token(self):
        log.Info("dpbx: trying to obtain access token")
        for env_var in ['DPBX_APP_KEY', 'DPBX_APP_SECRET']:
            if env_var not in os.environ:
                raise BackendException('dpbx: %s environment variable not set' % env_var)

        app_key = os.environ['DPBX_APP_KEY']
        app_secret = os.environ['DPBX_APP_SECRET']

        if not sys.stdout.isatty() or not sys.stdin.isatty():
            log.FatalError('dpbx error: cannot interact, but need human attention', log.ErrorCode.backend_command_error)

        auth_flow = DropboxOAuth2FlowNoRedirect(app_key, app_secret)
        log.Debug('dpbx,auth_flow.start()')
        authorize_url = auth_flow.start()
        print
        print '-' * 72
        print "1. Go to: " + authorize_url
        print "2. Click \"Allow\" (you might have to log in first)."
        print "3. Copy the authorization code."
        print '-' * 72
        auth_code = raw_input("Enter the authorization code here: ").strip()
        try:
            log.Debug('dpbx,auth_flow.finish(%s)' % auth_code)
            access_token, _ = auth_flow.finish(auth_code)
        except Exception as e:
            raise BackendException('dpbx: Unable to obtain access token: %s' % e)
        log.Info("dpbx: Authentication successfull")
        self.save_access_token(access_token)

    def login(self):
        if self.load_access_token() is None:
            self.obtain_access_token()

        self.api_client = Dropbox(self.load_access_token())
        self.api_account = None
        try:
            log.Debug('dpbx,users_get_current_account([token])')
            self.api_account = self.api_client.users_get_current_account()
            log.Debug("dpbx,%s" % self.api_account)

        except (BadInputError, AuthError) as e:
            log.Debug('dpbx,exception: %s' % e)
            log.Info("dpbx: Authentication failed. Trying to obtain new access token")

            self.obtain_access_token()

            # We're assuming obtain_access_token will throw exception. So this line should not be reached
            raise BackendException("dpbx: Please update DPBX_ACCESS_TOKEN and try again")

        log.Info("dpbx: Successfully authenticated as %s" % self.api_account.name.display_name)

    def _error_code(self, operation, e):
        if isinstance(e, ApiError):
            err = e.error

            if isinstance(err, GetMetadataError) and err.is_path():
                if err.get_path().is_not_found():
                    return log.ErrorCode.backend_not_found
            elif isinstance(err, DeleteError) and err.is_path_lookup():
                lookup = e.error.get_path_lookup()
                if lookup.is_not_found():
                    return log.ErrorCode.backend_not_found

    @command()
    def _put(self, source_path, remote_filename):
        remote_dir = urllib.unquote(self.parsed_url.path.lstrip('/'))
        remote_path = '/' + os.path.join(remote_dir, remote_filename).rstrip()

        file_size = os.path.getsize(source_path.name)
        f = source_path.open('rb')
        try:
            progress.report_transfer(0, file_size)
            buf = f.read(DPBX_UPLOAD_CHUNK_SIZE)
            log.Debug('dpbx,files_upload_session_start([%d bytes]), total: %d' % (len(buf), file_size))
            upload_sid = self.api_client.files_upload_session_start(buf)
            log.Debug('dpbx,files_upload_session_start(): %s' % upload_sid)
            upload_cursor = UploadSessionCursor(upload_sid.session_id, f.tell())
            commit_info = CommitInfo(remote_path, mode=WriteMode.overwrite, autorename=False, client_modified=None, mute=True)
            res_metadata = None
            progress.report_transfer(f.tell(), file_size)

            requested_offset = None
            current_chunk_size = DPBX_UPLOAD_CHUNK_SIZE
            retry_number = globals.num_retries

            # We're doing our own error handling and retrying logic because
            # we can benefit from Dpbx chunked upload and retry only failed chunk
            while (f.tell() < file_size) or not res_metadata:
                try:
                    if requested_offset is not None:
                        upload_cursor.offset = requested_offset

                    if f.tell() != upload_cursor.offset:
                        f.seek(upload_cursor.offset)
                    buf = f.read(current_chunk_size)

                    # reset temporary status variables
                    requested_offset = None
                    current_chunk_size = DPBX_UPLOAD_CHUNK_SIZE
                    retry_number = globals.num_retries

                    if len(buf) != 0:
                        log.Debug('dpbx,files_upload_sesssion_append([%d bytes], offset=%d)' % (len(buf), upload_cursor.offset))
                        self.api_client.files_upload_session_append(buf, upload_cursor.session_id, upload_cursor.offset)
                    else:
                        log.Debug('dpbx,files_upload_sesssion_finish([%d bytes], offset=%d)' % (len(buf), upload_cursor.offset))
                        res_metadata = self.api_client.files_upload_session_finish(buf, upload_cursor, commit_info)

                    upload_cursor.offset = f.tell()
                    log.Debug('progress: %d of %d' % (upload_cursor.offset, file_size))
                    progress.report_transfer(upload_cursor.offset, file_size)
                except ApiError as e:
                    error = e.error
                    if isinstance(error, UploadSessionLookupError) and error.is_incorrect_offset():
                        # Server reports that we should send another chunk. Most likely this is caused by
                        # network error during previous upload attempt. In such case we'll get expected offset
                        # from server and it's enough to just seek() and retry again
                        new_offset = error.get_incorrect_offset().correct_offset
                        log.Debug('dpbx,files_upload_session_append: incorrect offset: %d (expected: %s)' % (upload_cursor.offset, new_offset))
                        if requested_offset is not None:
                            # chunk failed even after seek attempt. Something strange and no safe way to recover
                            raise BackendException("dpbx: unable to chunk upload")
                        else:
                            # will seek and retry
                            requested_offset = new_offset
                        continue
                    raise
                except ConnectionError as e:
                    log.Debug('dpbx,files_upload_session_append: %s' % e)

                    retry_number -= 1
                    if retry_number == 0:
                        raise

                    # We don't know for sure, was partial upload successfull or not. So it's better to retry smaller amount to avoid extra reupload
                    log.Info('dpbx: sleeping a bit before chunk retry')
                    time.sleep(30)
                    current_chunk_size = DPBX_UPLOAD_CHUNK_SIZE / 5
                    requested_offset = None
                    continue

            if f.tell() != file_size:
                raise BackendException('dpbx: something wrong')

            log.Debug('dpbx,files_upload_sesssion_finish(): %s' % res_metadata)
            progress.report_transfer(f.tell(), file_size)

            # A few sanity checks
            if res_metadata.path_display != remote_path:
                raise BackendException('dpbx: result path mismatch: %s (expected: %s)' % (res_metadata.path_display, remote_path))
            if res_metadata.size != file_size:
                raise BackendException('dpbx: result size mismatch: %s (expected: %s)' % (res_metadata.size, file_size))

        finally:
            f.close()

    @command()
    def _get(self, remote_filename, local_path):
        remote_dir = urllib.unquote(self.parsed_url.path.lstrip('/'))
        remote_path = '/' + os.path.join(remote_dir, remote_filename).rstrip()

        log.Debug('dpbx,files_download(%s)' % remote_path)
        res_metadata, http_fd = self.api_client.files_download(remote_path)
        log.Debug('dpbx,files_download(%s): %s, %s' % (remote_path, res_metadata, http_fd))
        file_size = res_metadata.size
        to_fd = None
        progress.report_transfer(0, file_size)
        try:
            to_fd = local_path.open('wb')
            for c in http_fd.iter_content(DPBX_DOWNLOAD_BUF_SIZE):
                to_fd.write(c)
                progress.report_transfer(to_fd.tell(), file_size)

        finally:
            if to_fd:
                to_fd.close()
            http_fd.close()

        # It's different from _query() check because we're not querying metadata again.
        # Since this check is free, it's better to have it here
        local_size = os.path.getsize(local_path.name)
        if local_size != file_size:
            raise BackendException("dpbx: wrong file size: %d (expected: %d)" % (local_size, file_size))

        local_path.setdata()

    @command()
    def _list(self):
        # Do a long listing to avoid connection reset
        remote_dir = '/' + urllib.unquote(self.parsed_url.path.lstrip('/')).rstrip()

        log.Debug('dpbx.files_list_folder(%s)' % remote_dir)
        resp = self.api_client.files_list_folder(remote_dir)
        log.Debug('dpbx.list(%s): %s' % (remote_dir, resp))

        res = []
        while True:
            res.extend([entry.name for entry in resp.entries])
            if not resp.has_more:
                break
            resp = self.api_client.files_list_folder_continue(resp.cursor)

        # Warn users of old version dpbx about automatically renamed files
        self.check_renamed_files(res)

        return res

    @command()
    def _delete(self, filename):
        remote_dir = urllib.unquote(self.parsed_url.path.lstrip('/'))
        remote_path = '/' + os.path.join(remote_dir, filename).rstrip()

        log.Debug('dpbx.files_delete(%s)' % remote_path)
        self.api_client.files_delete(remote_path)

        # files_permanently_delete seems to be better for backup purpose
        # but it's only available for Business accounts
        # self.api_client.files_permanently_delete(remote_path)

    @command()
    def _close(self):
        """close backend session? no! just "flush" the data"""
        log.Debug('dpbx.close():')

    @command()
    def _query(self, filename):
        remote_dir = urllib.unquote(self.parsed_url.path.lstrip('/'))
        remote_path = '/' + os.path.join(remote_dir, filename).rstrip()

        log.Debug('dpbx.files_get_metadata(%s)' % remote_path)
        info = self.api_client.files_get_metadata(remote_path)
        log.Debug('dpbx.files_get_metadata(%s): %s' % (remote_path, info))
        return {'size': info.size}

    def check_renamed_files(self, file_list):
        bad_list = [x for x in file_list if DPBX_AUTORENAMED_FILE_RE.search(x) is not None]
        if len(bad_list) == 0:
            return
        log.Warn('-' * 72)
        log.Warn('Warning! It looks like there are automatically renamed files on backend')
        log.Warn('They were probably created when using older version of duplicity.')
        log.Warn('')
        log.Warn('Please check your backup consistency. Most likely you will need to choose')
        log.Warn('largest file from duplicity-* (number).gpg and remove brackets from its name.')
        log.Warn('')
        log.Warn('These files are not managed by duplicity at all and will not be')
        log.Warn('removed/rotated automatically.')
        log.Warn('')
        log.Warn('Affected files:')
        for x in bad_list:
            log.Warn('\t%s' % x)
        log.Warn('')
        log.Warn('In any case it\'s better to create full backup.')
        log.Warn('-' * 72)
 def __init__(self, *args, **kw):
     from dropbox import Dropbox
     super(DropboxWriter, self).__init__(*args, **kw)
     access_token = self.read_option('access_token')
     self.set_metadata('files_counter', Counter())
     self.client = Dropbox(access_token)