def revoke_remote_oauth_access(self, external_account): """Overrides default behavior during external_account deactivation. Tells Dropbox to remove the grant for the OSF associated with this account. """ client = DropboxClient(external_account.oauth_key) try: client.disable_access_token() except ErrorResponse: pass
def disconnect_dropbox(request): if request.method == 'POST': dropbox_token = request.user.profile.dropbox_token if dropbox_token is not None: client = DropboxClient(dropbox_token) client.disable_access_token() request.user.profile.dropbox_token = None request.user.save() messages.success(request, 'Your Dropbox account were disconnected successfully!') return redirect(r('settings:connections'))
def disconnect_dropbox(request): if request.method == 'POST': dropbox_token = request.user.profile.dropbox_token if dropbox_token is not None: client = DropboxClient(dropbox_token) client.disable_access_token() request.user.profile.dropbox_token = None request.user.save() messages.success(request, _('Your Dropbox account were disconnected successfully!')) return redirect(r('settings:connections'))
def revoke_remote_oauth_access(self, external_account): """Overrides default behavior during external_account deactivation. Tells DropBox to remove the grant for the OSF associated with this account. """ client = DropboxClient(external_account.oauth_key) try: client.disable_access_token() except ErrorResponse: pass
def dropbox_deauthorize(): user = get_current_user() if not user: abort(403) settings = get_dropbox_settings(user) client = DropboxClient(settings.access_token) client.disable_access_token() settings.remove() flash('Removed token') return redirect(url_for('user_detail', uid=user._primary_key))
def get(self): conference_data = self.get_conference_data() access_token = conference_data.dbox_access_token #access_token = data_cache.get('access_token') if access_token: try: client = DropboxClient(access_token, locale='en_US', rest_client=None) client.disable_access_token() conference_data.dbox_access_token = None data_cache.set('%s-conference_data' % self.module, None) conference_data.put() except: return self.render_response('utilities.html') return self.render_response('utilities.html', access_token=access_token)
class DropPy: def __init__(self, directory="/", key=None, secret=None, key_save="./", cursor=None): """Intialize a Dropbox connection, at directory specified or root. string directory. Location to consider root, relative to Dropbox root. string keysLoc. Location to store authentication json Any exceptions during the authorization process are not caught. See https://www.dropbox.com/developers/core/docs/python """ self.key = key self.secret = secret self.key_save = key_save self._dropbox_date = "%a, %d %b %Y %H:%M:%S %z" access_token = self._auth() self.cursor = cursor if directory[-1] != "/": directory += "/" self.directory = directory self.client = DropboxClient(access_token) def _auth(self): """Attempts to load an access token from key_save If unavailable, will guide the user through authentication """ pathname = _path(self.key_save, ".droppy") if path.exists(pathname): try: with open(pathname) as token: access_token = token.read() return access_token except: # If this fails for any reason, just have them reauth pass client = DropboxOAuth2FlowNoRedirect(self.key, self.secret) auth_url = client.start() print("Visit for authorization:\n{}".format(auth_url)) auth_code = input("Enter the authorization key: ") access_token, user_id = client.finish(auth_code) self._writeToken(access_token) return access_token def _writeToken(self, access_token=""): """Writes the access token to specified key location""" pathname = _path(self.key_save, ".droppy") with open(pathname, "w+") as token_file: token_file.write(access_token) def _get_dropbox_datetime(self, date_string): return datetime.strptime(date_string, self._dropbox_date) def _set_dropbox_datetime(self, datetime_obj): return datetime_obj.strftime(self._dropbox_date) def logout(self): """Destroys the current access token. The user will have to reauth.""" self.client.disable_access_token() def account_info(self): """Returns account info such as quota, email and display name.""" return self.client.account_info() def download(self, target, to="./", rev=None, start=None, length=None): """Downloads the current file to the specified, or local, directory target The path to the file that will be downloaded. If the first character is the forward slash ("/"), it will ignore the relative path of the DropPy instance, and instead begin from the Dropbox root to The local directory to download the file to. Defaults to current directory rev Optional previous rev value of the file to be downloaded. start Optional byte value from which to start downloading. length Optional length in bytes for partially downloading the file. If length is specified but start is not, then the last length bytes will be downloaded. Raises 400: Bad request (may be due to many things; check e.error for details). 404: No file was found at the given path, or the file that was there was deleted. 200: Request was okay but response was malformed in some way. """ filename = target.split("/").pop() target = _path(self.directory, target) with open(_path(to, filename), "wb") as out: with self.client.get_file(target, rev, start, length) as download: out.write(download.read()) def upload_chunked(self, fd, to=None, length=None): """Creates a chunked uploader If the file exists on the server, another is uploaded with (#) as a suffix fd File object from which the data will be sourced from to Optional path to upload to. Defaults to initialized directory length The number of bytes to upload. Defaults to full file. """ if length is None: length = path.getsize(fd.name) if to is None: to = self.directory to = _path(self.directory, to) filename = path.split(fd.name)[1] if length < 1: self.client.put_file(_path(to, filename), fd) else: uploader = self.client.get_chunked_uploader(fd, length) while uploader.offset < length: uploader.upload_chunked() uploader.finish(_path(to, filename)) def delta(self): """Retreive delta information from Dropbox. Allows you to monitor for changes. First change, cursor of None, returns all files. Subsequent calls, with cursor provided by previous calls, will provide changed files Returns all entries """ result = self.client.delta(self.cursor, _trim_d(self.directory)) self.cursor = result["cursor"] entries = result["entries"] while result["has_more"]: result = self.client.delta(self.cursor, _trim_d(self.directory)) self.cursor = result["cursor"] entries = entries + result["entries"] return entries def longpoll(self): pass def move(self, source, destination): """Moves a file from one place to another. Both source and destination are relative to initalized folder, unless preceded by directory altering prefix (eg. "/", "../", "../newFolder") source Origin of the file to move destination Place to move the file to Raises 400: Bad request (may be due to many things; check e.error for details). 403: An invalid move operation was attempted (e.g. there is already a file at the given destination, or moving a shared folder into a shared folder). 404: No file was found at given from_path. 503: User over storage quota. """ source = _path(self.directory, source) destination = _path(self.directory, destination) self.client.file_move(source, destination) def get_remote_files(self, directory="", deleted=False): remote_path = _path(self.directory, directory) metadata = self.client.metadata(remote_path, include_deleted=deleted) remote_files = metadata["contents"] for item in remote_files: if item["is_dir"]: remote_files = remote_files + self.get_remote_files(item["path"], deleted) return remote_files def sync(self, local=getcwd(), deleted=False, hidden=False): """Syncs the local file system to the remote file system. By default, will not delete any files that differ, only add new files local The local file directory to recusively sync with the remote. Default ./ delete Delete local files to keep in sync Does not delete remote files as it may not be running 24/7, tracking deletions Default False hidden Include hidden files in sync Default False """ local = path.abspath(local) if not path.isdir(local): raise ValueError("sync requires local to be a directory.") if local[-1] != "/": local += "/" local_files = {} for item in list(Path(local).glob("**/*")): if not hidden and ( search("/\.\w+", str(item)) \ or match("\.\w+", str(item)) ): continue local_files[str(item)[len(local):]] = { "mtime": int(item.stat().st_mtime) } remote_files_meta = self.get_remote_files(deleted=deleted) remote_files = {} remote_dirs = [] for item in remote_files_meta: isDeleted = "is_deleted" in item and item["is_deleted"] i = item["path"] mtime = self._get_dropbox_datetime(item["modified"]) if not hidden and (search("/\.\w+", str(i)) or match("\.\w+", str(i))): continue # Dropbox is not case sensitive, so make sure we preserve for local if i.startswith(self.directory) or i.startswith(self.directory.lower()): i = i[len(self.directory):] if item["is_dir"]: remote_dirs.append(i) remote_files[i] = { "mtime": int(mtime.strftime("%s")), "deleted": isDeleted } download = sorted([item for item in remote_files if item not in \ local_files and not remote_files[item]["deleted"]]) delete = sorted([item for item in remote_files if item in \ local_files and remote_files[item]["deleted"]]) #upload = sorted([item for item in local_files if item not in remote_files]) #for item in upload: # item_path = local / Path(item) # # if item_path.is_dir(): # self.client.file_create_folder(_path(self.directory, item)) # else: # parts = [part for part in item_path.parts if part not in Path(local).parts] # to = "/".join(parts[:-1]) # with open(str(item_path), "rb") as f: # self.upload_chunked(f,to=to) for item in download: item_path = Path(item) if item in remote_dirs: mkdir(_path(local, item)) else: parts = item_path.parts to = _path(local, "/".join(parts[:-1])) self.download(_path(self.directory + item), to=to) for item in delete: p = Path(local) / item if p.is_dir(): rmtree( str(p) ) elif p.is_file(): remove( str(p) )