Пример #1
0
    def create_remote_file_folder(self, local_file_folder, local_node):
        logger.debug('create_remote_file_folder')
        assert local_file_folder is not None
        assert isinstance(local_file_folder, File)
        assert local_node is not None
        assert isinstance(local_node, Node)
        assert local_file_folder.locally_created

        if local_file_folder.is_folder:
            remote_file_folder = yield from self.osf_query.upload_folder(
                local_file_folder)
        elif local_file_folder.is_file:
            try:
                remote_file_folder = yield from self.osf_query.upload_file(
                    local_file_folder)
            except FileNotFoundError:
                logger.warning(
                    'file not created on remote server because does not exist locally: {}'
                    .format(local_file_folder.name))
                return

        local_file_folder.osf_id = remote_file_folder.id
        local_file_folder.osf_path = remote_file_folder.id
        local_file_folder.locally_created = False

        save(session, local_file_folder)

        return remote_file_folder
Пример #2
0
    def create_remote_file_folder(self, local_file_folder, local_node):
        logger.debug('create_remote_file_folder')
        assert local_file_folder is not None
        assert isinstance(local_file_folder, File)
        assert local_node is not None
        assert isinstance(local_node, Node)
        assert local_file_folder.locally_created

        if local_file_folder.is_folder:
            remote_file_folder = yield from self.osf_query.upload_folder(local_file_folder)
        elif local_file_folder.is_file:
            try:
                remote_file_folder = yield from self.osf_query.upload_file(local_file_folder)
            except FileNotFoundError:
                logger.warning('file not created on remote server because does not exist locally: {}'.format(
                    local_file_folder.name))
                return

        local_file_folder.osf_id = remote_file_folder.id
        local_file_folder.osf_path = remote_file_folder.id
        local_file_folder.locally_created = False

        save(session, local_file_folder)

        return remote_file_folder
Пример #3
0
 def update_sync_nodes(self):
     user = session.query(User).filter(User.logged_in).one()
     guid_list = self.get_guid_list()
     # FIXME: This needs a try-except block but is waiting on a preferences refactor to be merged
     user.guid_for_top_level_nodes_to_sync = guid_list
     save(session, user)
     self.checked_items = guid_list
     self.close()
Пример #4
0
    def delete_local_node(self, local_node):
        logger.debug('delete_local_node')
        assert isinstance(local_node, Node)

        path = local_node.path

        # delete model
        session.delete(local_node)
        save(session)

        yield from self.queue.put(DeleteFolder(path))
Пример #5
0
    def delete_local_node(self, local_node):
        logger.debug('delete_local_node')
        assert isinstance(local_node, Node)

        path = local_node.path

        # delete model
        session.delete(local_node)
        save(session)

        yield from self.queue.put(DeleteFolder(path))
    def on_deleted(self, event):
        """Called when a file or directory is deleted.

        :param event:
            Event representing file/directory deletion.
        :type event:
            :class:`DirDeletedEvent` or :class:`FileDeletedEvent`
        """
        try:
            src_path = ProperPath(event.src_path, event.is_directory)
        except Exception:
            logging.exception('Exception caught: Invalid path')
            AlertHandler.warn(
                'invalid path specified. {} will not be synced'.format(
                    os.path.basename(event.src_path)))
        else:
            if not self._already_exists(src_path):
                return

            # get item
            try:
                item = self._get_item_by_path(src_path)
            except ItemNotInDB:
                logging.exception(
                    'Exception caught: Tried to delete item {}, but it was not found in DB'
                    .format(src_path.name))
            else:
                # put item in delete state after waiting a second and
                # checking to make sure the file was actually deleted
                yield from asyncio.sleep(1)
                if not os.path.exists(item.path):
                    item.locally_deleted = True
                    # nodes cannot be deleted online. THUS, delete it inside database. It will be recreated locally.
                    if isinstance(item, Node):
                        session.delete(item)
                        try:
                            save(session)
                        except SQLAlchemyError as e:
                            logging.exception(
                                'Exception caught: Error deleting node {} from database.'
                                .format(item.name))
                        return
                    try:
                        save(session, item)
                    except SQLAlchemyError as e:
                        logging.exception(
                            'Exception caught: Error deleting {} {} from database.'
                            .format('folder' if event.is_directory else 'file',
                                    item.name))
                    else:
                        logging.info('{} set to be deleted'.format(
                            src_path.full_path))
Пример #7
0
    def logout(self):
        user = session.query(User).filter(User.logged_in).one()
        user.logged_in = False
        try:
            save(session, user)
        except SQLAlchemyError:
            session.query(User).delete()

        self.tray.tray_icon.hide()
        if self.preferences.isVisible():
            self.preferences.close()

        self.start_screen.open_window()
Пример #8
0
    def logout(self):
        user = session.query(User).filter(User.logged_in).one()
        user.logged_in = False
        try:
            save(session, user)
        except SQLAlchemyError:
            session.query(User).delete()

        self.tray.tray_icon.hide()
        if self.preferences.isVisible():
            self.preferences.close()

        self.start_screen.open_window()
Пример #9
0
    def modify_local_node(self, local_node, remote_node):
        logger.debug('modify_local_node')
        assert isinstance(local_node, Node)
        assert isinstance(remote_node, RemoteNode)
        assert remote_node.id == local_node.osf_id

        old_path = local_node.path
        local_node.title = remote_node.name

        local_node.category = remote_node.category

        save(session, local_node)

        yield from self.queue.put(RenameFolder(old_path, local_node.path))
Пример #10
0
    def modify_local_node(self, local_node, remote_node):
        logger.debug('modify_local_node')
        assert isinstance(local_node, Node)
        assert isinstance(remote_node, RemoteNode)
        assert remote_node.id == local_node.osf_id

        old_path = local_node.path
        local_node.title = remote_node.name

        local_node.category = remote_node.category

        save(session, local_node)

        yield from self.queue.put(RenameFolder(old_path, local_node.path))
Пример #11
0
    def on_modified(self, event):
        """Called when a file or directory is modified.

        :param event:
            Event representing file/directory modification.
        :type event:
            :class:`DirModifiedEvent` or :class:`FileModifiedEvent`
        """

        if isinstance(event, DirModifiedEvent):
            return
        try:
            src_path = ProperPath(event.src_path, event.is_directory)
        except Exception:
            logging.exception('Exception caught: Invalid path')
            AlertHandler.warn(
                'invalid path specified. {} will not be synced'.format(
                    os.path.basename(event.src_path)))
        else:
            # get item
            try:
                item = self._get_item_by_path(src_path)
            except ItemNotInDB:
                # todo: create file folder
                logging.warning(
                    'file {} was modified but not already in db. create it in db.'
                    .format(src_path))
                return  # todo: remove this once above is implemented

            # update hash
            try:
                item.update_hash()
            except OSError:
                logging.exception('File inaccessible during update_hash')
                AlertHandler.warn(
                    'Error updating {}. {} inaccessible, will stop syncing.'.
                    format('Folder' if event.is_directory else 'File',
                           item.name))
                return

            # save
            try:
                save(session, item)
            except SQLAlchemyError:
                logging.exception(
                    'Exception caught: Could not save data for {}'.format(
                        item))
                AlertHandler.warn(
                    'Error updating {}. {} will stop syncing.'.format(
                        'folder' if event.is_directory else 'file', item.name))
Пример #12
0
    def on_deleted(self, event):
        """Called when a file or directory is deleted.

        :param event:
            Event representing file/directory deletion.
        :type event:
            :class:`DirDeletedEvent` or :class:`FileDeletedEvent`
        """
        try:
            src_path = ProperPath(event.src_path, event.is_directory)
        except Exception:
            logging.exception("Exception caught: Invalid path")
            AlertHandler.warn("invalid path specified. {} will not be synced".format(os.path.basename(event.src_path)))
        else:
            if not self._already_exists(src_path):
                return

            # get item
            try:
                item = self._get_item_by_path(src_path)
            except ItemNotInDB:
                logging.exception(
                    "Exception caught: Tried to delete item {}, but it was not found in DB".format(src_path.name)
                )
            else:
                # put item in delete state after waiting a second and
                # checking to make sure the file was actually deleted
                yield from asyncio.sleep(1)
                if not os.path.exists(item.path):
                    item.locally_deleted = True
                    # nodes cannot be deleted online. THUS, delete it inside database. It will be recreated locally.
                    if isinstance(item, Node):
                        session.delete(item)
                        try:
                            save(session)
                        except SQLAlchemyError as e:
                            logging.exception(
                                "Exception caught: Error deleting node {} from database.".format(item.name)
                            )
                        return
                    try:
                        save(session, item)
                    except SQLAlchemyError as e:
                        logging.exception(
                            "Exception caught: Error deleting {} {} from database.".format(
                                "folder" if event.is_directory else "file", item.name
                            )
                        )
                    else:
                        logging.info("{} set to be deleted".format(src_path.full_path))
Пример #13
0
    def delete_local_file_folder(self, local_file_folder):
        logger.debug('delete_local_file_folder')
        assert isinstance(local_file_folder, File)

        path = local_file_folder.path
        is_folder = local_file_folder.is_folder
        # delete model
        session.delete(local_file_folder)
        save(session)

        # delete from local
        if is_folder:
            yield from self.queue.put(DeleteFolder(path))
        else:
            yield from self.queue.put(DeleteFile(path))
Пример #14
0
    def delete_remote_file_folder(self, local_file_folder, remote_file_folder):
        logger.debug('delete_remote_file_folder')
        assert local_file_folder is not None
        assert remote_file_folder is not None
        assert local_file_folder.osf_id == self.get_id(remote_file_folder)
        assert local_file_folder.locally_deleted

        if local_file_folder.is_file:
            yield from self.osf_query.delete_remote_file(remote_file_folder)
        elif local_file_folder.is_folder:
            yield from self.osf_query.delete_remote_folder(remote_file_folder)

        local_file_folder.deleted = False
        session.delete(local_file_folder)
        save(session)
Пример #15
0
    def delete_remote_file_folder(self, local_file_folder, remote_file_folder):
        logger.debug('delete_remote_file_folder')
        assert local_file_folder is not None
        assert remote_file_folder is not None
        assert local_file_folder.osf_id == self.get_id(remote_file_folder)
        assert local_file_folder.locally_deleted

        if local_file_folder.is_file:
            yield from self.osf_query.delete_remote_file(remote_file_folder)
        elif local_file_folder.is_folder:
            yield from self.osf_query.delete_remote_folder(remote_file_folder)

        local_file_folder.deleted = False
        session.delete(local_file_folder)
        save(session)
Пример #16
0
    def delete_local_file_folder(self, local_file_folder):
        logger.debug('delete_local_file_folder')
        assert isinstance(local_file_folder, File)

        path = local_file_folder.path
        is_folder = local_file_folder.is_folder
        # delete model
        session.delete(local_file_folder)
        save(session)

        # delete from local
        if is_folder:
            yield from self.queue.put(DeleteFolder(path))
        else:
            yield from self.queue.put(DeleteFile(path))
Пример #17
0
    def on_modified(self, event):
        """Called when a file or directory is modified.

        :param event:
            Event representing file/directory modification.
        :type event:
            :class:`DirModifiedEvent` or :class:`FileModifiedEvent`
        """

        if isinstance(event, DirModifiedEvent):
            return
        try:
            src_path = ProperPath(event.src_path, event.is_directory)
        except Exception:
            logging.exception("Exception caught: Invalid path")
            AlertHandler.warn("invalid path specified. {} will not be synced".format(os.path.basename(event.src_path)))
        else:
            # get item
            try:
                item = self._get_item_by_path(src_path)
            except ItemNotInDB:
                # todo: create file folder
                logging.warning("file {} was modified but not already in db. create it in db.".format(src_path))
                return  # todo: remove this once above is implemented

            # update hash
            try:
                item.update_hash()
            except OSError:
                logging.exception("File inaccessible during update_hash")
                AlertHandler.warn(
                    "Error updating {}. {} inaccessible, will stop syncing.".format(
                        "Folder" if event.is_directory else "File", item.name
                    )
                )
                return

            # save
            try:
                save(session, item)
            except SQLAlchemyError:
                logging.exception("Exception caught: Could not save data for {}".format(item))
                AlertHandler.warn(
                    "Error updating {}. {} will stop syncing.".format(
                        "folder" if event.is_directory else "file", item.name
                    )
                )
Пример #18
0
    def quit(self):
        try:
            if self.background_worker.is_alive():
                logger.info('Stopping background worker')
                self.background_worker.stop()

            try:
                user = session.query(User).filter(User.logged_in).one()
            except NoResultFound:
                pass
            else:
                logger.info('Saving user data')
                save(session, user)
            session.close()
        finally:
            logger.info('Quitting application')
            QApplication.instance().quit()
Пример #19
0
    def rename_local_file_folder(self, local_file_folder, remote_file_folder):
        logger.debug('rename_local_file_folder')
        assert isinstance(local_file_folder, File)
        assert isinstance(remote_file_folder, RemoteFileFolder)
        assert remote_file_folder.id == local_file_folder.osf_path

        # handle renaming local file and local folder
        old_path = local_file_folder.path
        # update model
        local_file_folder.name = remote_file_folder.name

        save(session, local_file_folder)

        if local_file_folder.is_folder:
            yield from self.queue.put(RenameFolder(old_path, local_file_folder.path))
        elif local_file_folder.is_file:
            yield from self.queue.put(RenameFile(old_path, local_file_folder.path))
Пример #20
0
    def quit(self):
        try:
            if self.background_worker.is_alive():
                logger.info('Stopping background worker')
                self.background_worker.stop()

            try:
                user = session.query(User).filter(User.logged_in).one()
            except NoResultFound:
                pass
            else:
                logger.info('Saving user data')
                save(session, user)
            session.close()
        finally:
            logger.info('Quitting application')
            QApplication.instance().quit()
Пример #21
0
    def rename_local_file_folder(self, local_file_folder, remote_file_folder):
        logger.debug('rename_local_file_folder')
        assert isinstance(local_file_folder, File)
        assert isinstance(remote_file_folder, RemoteFileFolder)
        assert remote_file_folder.id == local_file_folder.osf_path

        # handle renaming local file and local folder
        old_path = local_file_folder.path
        # update model
        local_file_folder.name = remote_file_folder.name

        save(session, local_file_folder)

        if local_file_folder.is_folder:
            yield from self.queue.put(
                RenameFolder(old_path, local_file_folder.path))
        elif local_file_folder.is_file:
            yield from self.queue.put(
                RenameFile(old_path, local_file_folder.path))
Пример #22
0
    def start(self):
        logger.debug('Start in main called.')

        try:
            user = session.query(User).filter(User.logged_in).one()
        except MultipleResultsFound:
            session.query(User).delete()
            self.login_signal.emit()
            return
        except NoResultFound:
            self.login_signal.emit()
            return

        try:
            # Simple request to ensure user logged in with valid oauth_token
            user = asyncio.get_event_loop().run_until_complete(
                AuthClient().populate_user_data(user))
        except AuthError as e:
            logging.exception(e.message)
            self.login_signal.emit()

        containing_folder = os.path.dirname(user.osf_local_folder_path)
        while not validate_containing_folder(containing_folder):
            logger.warning(
                'Invalid containing folder: {}'.format(containing_folder))
            AlertHandler.warn(
                'Invalid containing folder. Please choose another.')
            containing_folder = os.path.abspath(
                self.set_containing_folder_initial())

        user.osf_local_folder_path = os.path.join(containing_folder, 'OSF')

        save(session, user)
        self.tray.set_containing_folder(containing_folder)

        if not os.path.isdir(user.osf_local_folder_path):
            os.makedirs(user.osf_local_folder_path)

        self.start_tray_signal.emit()
        logger.debug('starting background worker from main.start')

        self.background_worker = BackgroundWorker()
        self.background_worker.start()
Пример #23
0
    def _create_file_or_folder(self, event, src_path):
        # assert: whats being created is a file folder
        try:
            containing_item = self._get_parent_item_from_path(src_path)
        except ItemNotInDB:
            logging.error(
                "tried to create item {} for parent {} but parent does not exist".format(
                    src_path.full_path, src_path.parent.full_path
                )
            )
            return

        if isinstance(containing_item, Node):
            node = containing_item
        else:  # file
            node = containing_item.node
        new_item = File(
            name=src_path.name,
            type=File.FOLDER if event.is_directory else File.FILE,
            user=self.user,
            locally_created=True,
            provider=File.DEFAULT_PROVIDER,
            node=node,
        )
        containing_item.files.append(new_item)
        if new_item.is_file:
            try:
                new_item.update_hash()
            except FileNotFoundError:
                # if file doesnt exist just as we create it, then file is likely temp file. thus don't put it in db.
                return
        try:
            save(session, new_item, containing_item)
        except SQLAlchemyError:
            logging.exception("Exception caught: Could not save data for {} in {}".format(new_item, containing_item))
            AlertHandler.warn(
                "Error creating {}: {} will not be synced.".format(
                    "file" if new_item.is_file else "folder", new_item.name
                )
            )
        else:
            logging.info("created new {} {}".format("folder" if event.is_directory else "file", src_path.full_path))
Пример #24
0
    def _create_file_or_folder(self, event, src_path):
        # assert: whats being created is a file folder
        try:
            containing_item = self._get_parent_item_from_path(src_path)
        except ItemNotInDB:
            logging.error(
                'tried to create item {} for parent {} but parent does not exist'
                .format(src_path.full_path, src_path.parent.full_path))
            return

        if isinstance(containing_item, Node):
            node = containing_item
        else:  # file
            node = containing_item.node
        new_item = File(name=src_path.name,
                        type=File.FOLDER if event.is_directory else File.FILE,
                        user=self.user,
                        locally_created=True,
                        provider=File.DEFAULT_PROVIDER,
                        node=node)
        containing_item.files.append(new_item)
        if new_item.is_file:
            try:
                new_item.update_hash()
            except FileNotFoundError:
                # if file doesnt exist just as we create it, then file is likely temp file. thus don't put it in db.
                return
        try:
            save(session, new_item, containing_item)
        except SQLAlchemyError:
            logging.exception(
                'Exception caught: Could not save data for {} in {}'.format(
                    new_item, containing_item))
            AlertHandler.warn(
                'Error creating {}: {} will not be synced.'.format(
                    'file' if new_item.is_file else 'folder', new_item.name))
        else:
            logging.info("created new {} {}".format(
                'folder' if event.is_directory else 'file',
                src_path.full_path))
Пример #25
0
    def log_in(self, user=None, username=None, password=None):
        """ Takes standard auth credentials, returns authenticated user or raises AuthError.
        """
        if not username or not password:
            raise AuthError('Username and password required for login.')

        if user:
            user.oauth_token = yield from self._authenticate(username, password)
            if user.osf_login != username:
                #Different user authenticated, drop old user and allow login
                clear_models()
                user = yield from self._create_user(username, password)
        else:
            user = yield from self._create_user(username, password)

        user.logged_in = True
        try:
            save(session, user)
        except SQLAlchemyError as e:
            raise AuthError('Unable to save user data. Please try again later')
        else:
            return user
Пример #26
0
    def create_local_node(self, remote_node, local_parent_node):
        logger.debug('create_local_node')
        assert isinstance(remote_node, RemoteNode)
        assert isinstance(local_parent_node, Node) or local_parent_node is None

        # create local node in db
        category = Node.PROJECT if remote_node.category == 'project' else Node.COMPONENT
        new_node = Node(title=remote_node.name,
                        category=category,
                        osf_id=remote_node.id,
                        user=self.user,
                        parent=local_parent_node)
        save(session, new_node)

        if local_parent_node:
            yield from self._ensure_components_folder(local_parent_node)
        yield from self.queue.put(CreateFolder(new_node.path))
        yield from self._ensure_components_folder(new_node)

        assert local_parent_node is None or (new_node
                                             in local_parent_node.child_nodes)
        return new_node
Пример #27
0
    def start(self):
        logger.debug('Start in main called.')

        try:
            user = session.query(User).filter(User.logged_in).one()
        except MultipleResultsFound:
            session.query(User).delete()
            self.login_signal.emit()
            return
        except NoResultFound:
            self.login_signal.emit()
            return

        try:
            # Simple request to ensure user logged in with valid oauth_token
            user = asyncio.get_event_loop().run_until_complete(AuthClient().populate_user_data(user))
        except AuthError as e:
            logging.exception(e.message)
            self.login_signal.emit()

        containing_folder = os.path.dirname(user.osf_local_folder_path)
        while not validate_containing_folder(containing_folder):
            logger.warning('Invalid containing folder: {}'.format(containing_folder))
            AlertHandler.warn('Invalid containing folder. Please choose another.')
            containing_folder = os.path.abspath(self.set_containing_folder_initial())

        user.osf_local_folder_path = os.path.join(containing_folder, 'OSF')

        save(session, user)
        self.tray.set_containing_folder(containing_folder)

        if not os.path.isdir(user.osf_local_folder_path):
            os.makedirs(user.osf_local_folder_path)

        self.start_tray_signal.emit()
        logger.debug('starting background worker from main.start')

        self.background_worker = BackgroundWorker()
        self.background_worker.start()
Пример #28
0
    def log_in(self, user=None, username=None, password=None):
        """ Takes standard auth credentials, returns authenticated user or raises AuthError.
        """
        if not username or not password:
            raise AuthError('Username and password required for login.')

        if user:
            user.oauth_token = yield from self._authenticate(
                username, password)
            if user.osf_login != username:
                #Different user authenticated, drop old user and allow login
                clear_models()
                user = yield from self._create_user(username, password)
        else:
            user = yield from self._create_user(username, password)

        user.logged_in = True
        try:
            save(session, user)
        except SQLAlchemyError as e:
            raise AuthError('Unable to save user data. Please try again later')
        else:
            return user
Пример #29
0
    def create_local_node(self, remote_node, local_parent_node):
        logger.debug('create_local_node')
        assert isinstance(remote_node, RemoteNode)
        assert isinstance(local_parent_node, Node) or local_parent_node is None

        # create local node in db
        category = Node.PROJECT if remote_node.category == 'project' else Node.COMPONENT
        new_node = Node(
            title=remote_node.name,
            category=category,
            osf_id=remote_node.id,
            user=self.user,
            parent=local_parent_node
        )
        save(session, new_node)

        if local_parent_node:
            yield from self._ensure_components_folder(local_parent_node)
        yield from self.queue.put(CreateFolder(new_node.path))
        yield from self._ensure_components_folder(new_node)

        assert local_parent_node is None or (new_node in local_parent_node.child_nodes)
        return new_node
Пример #30
0
    def create_local_file_folder(self, remote_file_folder, local_parent_folder, local_node):
        logger.debug('creating local file folder')
        assert remote_file_folder is not None
        assert isinstance(remote_file_folder, RemoteFileFolder)
        assert isinstance(local_parent_folder, File) or local_parent_folder is None
        assert local_parent_folder is None or (local_parent_folder.is_folder)
        assert isinstance(local_node, Node)

        # NOTE: develop is not letting me download files. dont know why.

        # create local file folder in db
        file_type = File.FILE if isinstance(remote_file_folder, RemoteFile) else File.FOLDER
        new_file_folder = File(
            name=remote_file_folder.name,
            type=file_type,
            osf_id=remote_file_folder.id,
            provider=remote_file_folder.provider,
            osf_path=remote_file_folder.id,
            user=self.user,
            parent=local_parent_folder,
            node=local_node
        )
        save(session, new_file_folder)

        if file_type == File.FILE:
            event = CreateFile(
                path=new_file_folder.path,
                download_url=remote_file_folder.download_url,
                osf_query=self.osf_query
            )
            yield from self.queue.put(event)
        elif file_type == File.FOLDER:
            yield from self.queue.put(CreateFolder(new_file_folder.path))
        else:
            raise ValueError('file type is unknown')

        return new_file_folder
Пример #31
0
    def create_local_file_folder(self, remote_file_folder, local_parent_folder,
                                 local_node):
        logger.debug('creating local file folder')
        assert remote_file_folder is not None
        assert isinstance(remote_file_folder, RemoteFileFolder)
        assert isinstance(local_parent_folder,
                          File) or local_parent_folder is None
        assert local_parent_folder is None or (local_parent_folder.is_folder)
        assert isinstance(local_node, Node)

        # NOTE: develop is not letting me download files. dont know why.

        # create local file folder in db
        file_type = File.FILE if isinstance(remote_file_folder,
                                            RemoteFile) else File.FOLDER
        new_file_folder = File(name=remote_file_folder.name,
                               type=file_type,
                               osf_id=remote_file_folder.id,
                               provider=remote_file_folder.provider,
                               osf_path=remote_file_folder.id,
                               user=self.user,
                               parent=local_parent_folder,
                               node=local_node)
        save(session, new_file_folder)

        if file_type == File.FILE:
            event = CreateFile(path=new_file_folder.path,
                               download_url=remote_file_folder.download_url,
                               osf_query=self.osf_query)
            yield from self.queue.put(event)
        elif file_type == File.FOLDER:
            yield from self.queue.put(CreateFolder(new_file_folder.path))
        else:
            raise ValueError('file type is unknown')

        return new_file_folder
Пример #32
0
    def on_moved(self, event):
        """Called when a file or a directory is moved or renamed.

        :param event:
            Event representing file/directory movement.
        :type event:
            :class:`DirMovedEvent` or :class:`FileMovedEvent`
        """
        try:
            src_path = ProperPath(event.src_path, event.is_directory)
            dest_path = ProperPath(event.dest_path, event.is_directory)
        except Exception:
            logging.exception("Exception caught: Invalid path specified")
            AlertHandler.warn(
                "Error moving {}. {} will not be synced.".format(
                    "folder" if event.is_directory else "file", os.path.basename(event.src_path)
                )
            )
        else:
            # determine and get what moved
            if not self._already_exists(src_path):
                try:
                    self._get_parent_item_from_path(src_path)
                except ItemNotInDB:
                    # This means it was put into a place on the hierarchy being watched but otherwise not attached to a
                    # node, so it needs to be added just like a new event rather than as a move.

                    new_event = (
                        DirCreatedEvent(event.dest_path) if event.is_directory else FileCreatedEvent(event.dest_path)
                    )
                    yield from self._create_file_or_folder(new_event, src_path=dest_path)
                    return
                logging.warning("Tried to move item that does not exist: {}".format(src_path.name))
                return

            try:
                item = self._get_item_by_path(src_path)
            except ItemNotInDB:
                logging.exception(
                    "Exception caught: Tried to move or rename item {}, but it could not be found in DB".format(
                        src_path.name
                    )
                )
                AlertHandler.warn("Could not find item to manipulate. {} will not be synced".format(src_path.name))
            else:
                if isinstance(item, Node):
                    AlertHandler.warn("Cannot manipulate components locally. {} will stop syncing".format(item.title))
                    return

                # File

                # rename
                if item.name != dest_path.name:
                    item.name = dest_path.name
                    item.locally_renamed = True
                    try:
                        save(session, item)
                    except SQLAlchemyError:
                        logging.exception("Exception caught: Could not save data for {}".format(item))
                        AlertHandler.warn("Error renaming file. {} will stop syncing.".format(item.name))
                    else:
                        logging.info("renamed a file {}".format(dest_path.full_path))
                # move
                elif src_path != dest_path:
                    # check if file already exists in this moved location. If so, delete it from db.
                    try:
                        item_to_replace = self._get_item_by_path(dest_path)
                        session.delete(item_to_replace)
                        save(session)
                    except ItemNotInDB:
                        logging.info("file does not already exist in moved destination: {}".format(dest_path.full_path))
                    except SQLAlchemyError:
                        logging.exception("Exception caught: Could not save data for {}".format(item_to_replace))
                        AlertHandler.warn("Error moving file. {} will stop syncing.".format(dest_path.name))

                    try:
                        new_parent_item = self._get_parent_item_from_path(dest_path)
                    except ItemNotInDB:
                        AlertHandler.warn(
                            "{} {} placed into invalid containing folder. It will not be synced.".format(
                                "Folder" if event.is_directory else "File", dest_path.name
                            )
                        )
                    else:
                        # move item

                        # set previous fields
                        item.previous_provider = item.provider
                        item.previous_node_osf_id = item.node.osf_id

                        # update parent and node fields
                        # NOTE: this line makes it so the file no longer exists in the database.
                        # NOTE: item at this point is stale. Unclear why it matters though.
                        # NOTE: fix is above: session.refresh(item)
                        item.parent = new_parent_item if isinstance(new_parent_item, File) else None
                        item.node = new_parent_item if isinstance(new_parent_item, Node) else new_parent_item.node

                        # basically always osfstorage. this is just meant to be extendible in the future to other providers
                        item.provider = (
                            new_parent_item.provider if isinstance(new_parent_item, File) else File.DEFAULT_PROVIDER
                        )

                        # flags
                        item.locally_moved = True
                        try:
                            save(session, item)
                        except SQLAlchemyError:
                            logging.exception("Exception caught: Could not save data for {}".format(item))
                            AlertHandler.warn("Error moving file. {} will stop syncing.".format(item.name))
                        else:
                            logging.info("moved from {} to {}".format(src_path.full_path, dest_path.full_path))
Пример #33
0
    def _check_file_folder(self, local_file_folder, remote_file_folder,
                           local_parent_file_folder, local_node):
        """
        VARIOUS STATES (update as neccessary):
        (None, None) -> Error                                     --
        (None, remote) ->
            if locally moved -> do nothing
            else -> create local
        (local.create, None) -> create remote                     --
        (local.create, remote) -> ERROR                           --
        (local.delete, None) -> ERROR                             --
        (local.delete, remote) - > delete remote                  --
        (local, None) ->
            if locally moved -> move
            else -> delete local
        (local, remote) -> check modifications                    --

        """

        assert local_file_folder or remote_file_folder  # both shouldnt be None.
        logger.debug('checking file_folder internal')
        if local_file_folder is None:
            locally_moved = yield from self.is_locally_moved(
                remote_file_folder)
            if locally_moved:
                return
            else:
                local_file_folder = yield from self.create_local_file_folder(
                    remote_file_folder, local_parent_file_folder, local_node)
        elif local_file_folder.locally_created and remote_file_folder is None:
            if not local_file_folder.is_provider:
                remote_file_folder = yield from self.create_remote_file_folder(
                    local_file_folder, local_node)
            return
        elif local_file_folder.locally_created and remote_file_folder is not None:
            raise ValueError(
                'newly created local file_folder was already on server')
        elif local_file_folder.locally_deleted and remote_file_folder is None:
            session.delete(local_file_folder)
            save(session)
            logger.warning(
                'local file_folder is to be deleted, however, it was never on the server.'
            )
            return
        elif local_file_folder.locally_deleted and remote_file_folder is not None:
            yield from self.delete_remote_file_folder(local_file_folder,
                                                      remote_file_folder)
            return
        elif local_file_folder is not None and remote_file_folder is None:
            if local_file_folder.locally_moved:
                # todo: we are ignoring return value for now because to start going down new tree would require
                # todo: us to have the new node. we currently use the head node instead of dynamically determining
                # todo: node. This is problematic. And Bad. FIX IT.
                remote_file_folder = yield from self.move_remote_file_folder(
                    local_file_folder)
                return
            else:
                logger.warning('delete_local_file_folder called on {}'.format(
                    local_file_folder.name))
                yield from self.delete_local_file_folder(local_file_folder)
                return
        elif local_file_folder is not None and remote_file_folder is not None:
            possibly_new_remote_file_folder = yield from self.modify_file_folder_logic(
                local_file_folder, remote_file_folder)
            # if we do not need to modify things, remote file folder and local file folder does not change
            # we do not need to get a new local file folder because it is updated internally by the db
            if possibly_new_remote_file_folder:
                remote_file_folder = possibly_new_remote_file_folder
        else:
            raise ValueError('in some weird state. figure it out.')

        assert local_file_folder is not None
        assert remote_file_folder is not None

        # recursively handle folder's children
        if local_file_folder.is_folder:

            remote_children = yield from self.osf_query.get_child_files(
                remote_file_folder)

            local_remote_file_folders = self.make_local_remote_tuple_list(
                local_file_folder.files, remote_children)

            for local, remote in local_remote_file_folders:
                yield from self._check_file_folder(
                    local,
                    remote,
                    local_parent_file_folder=local_file_folder,
                    local_node=local_node)
Пример #34
0
    def on_moved(self, event):
        """Called when a file or a directory is moved or renamed.

        :param event:
            Event representing file/directory movement.
        :type event:
            :class:`DirMovedEvent` or :class:`FileMovedEvent`
        """
        try:
            src_path = ProperPath(event.src_path, event.is_directory)
            dest_path = ProperPath(event.dest_path, event.is_directory)
        except Exception:
            logging.exception('Exception caught: Invalid path specified')
            AlertHandler.warn('Error moving {}. {} will not be synced.'.format(
                'folder' if event.is_directory else 'file',
                os.path.basename(event.src_path)))
        else:
            # determine and get what moved
            if not self._already_exists(src_path):
                try:
                    self._get_parent_item_from_path(src_path)
                except ItemNotInDB:
                    # This means it was put into a place on the hierarchy being watched but otherwise not attached to a
                    # node, so it needs to be added just like a new event rather than as a move.

                    new_event = DirCreatedEvent(
                        event.dest_path
                    ) if event.is_directory else FileCreatedEvent(
                        event.dest_path)
                    yield from self._create_file_or_folder(new_event,
                                                           src_path=dest_path)
                    return
                logging.warning(
                    'Tried to move item that does not exist: {}'.format(
                        src_path.name))
                return

            try:
                item = self._get_item_by_path(src_path)
            except ItemNotInDB:
                logging.exception(
                    'Exception caught: Tried to move or rename item {}, but it could not be found in DB'
                    .format(src_path.name))
                AlertHandler.warn(
                    'Could not find item to manipulate. {} will not be synced'.
                    format(src_path.name))
            else:
                if isinstance(item, Node):
                    AlertHandler.warn(
                        'Cannot manipulate components locally. {} will stop syncing'
                        .format(item.title))
                    return

                # File

                # rename
                if item.name != dest_path.name:
                    item.name = dest_path.name
                    item.locally_renamed = True
                    try:
                        save(session, item)
                    except SQLAlchemyError:
                        logging.exception(
                            'Exception caught: Could not save data for {}'.
                            format(item))
                        AlertHandler.warn(
                            'Error renaming file. {} will stop syncing.'.
                            format(item.name))
                    else:
                        logging.info("renamed a file {}".format(
                            dest_path.full_path))
                # move
                elif src_path != dest_path:
                    # check if file already exists in this moved location. If so, delete it from db.
                    try:
                        item_to_replace = self._get_item_by_path(dest_path)
                        session.delete(item_to_replace)
                        save(session)
                    except ItemNotInDB:
                        logging.info(
                            'file does not already exist in moved destination: {}'
                            .format(dest_path.full_path))
                    except SQLAlchemyError:
                        logging.exception(
                            'Exception caught: Could not save data for {}'.
                            format(item_to_replace))
                        AlertHandler.warn(
                            'Error moving file. {} will stop syncing.'.format(
                                dest_path.name))

                    try:
                        new_parent_item = self._get_parent_item_from_path(
                            dest_path)
                    except ItemNotInDB:
                        AlertHandler.warn(
                            '{} {} placed into invalid containing folder. It will not be synced.'
                            .format('Folder' if event.is_directory else 'File',
                                    dest_path.name))
                    else:
                        # move item

                        # set previous fields
                        item.previous_provider = item.provider
                        item.previous_node_osf_id = item.node.osf_id

                        # update parent and node fields
                        # NOTE: this line makes it so the file no longer exists in the database.
                        # NOTE: item at this point is stale. Unclear why it matters though.
                        # NOTE: fix is above: session.refresh(item)
                        item.parent = new_parent_item if isinstance(
                            new_parent_item, File) else None
                        item.node = new_parent_item if isinstance(
                            new_parent_item, Node) else new_parent_item.node

                        # basically always osfstorage. this is just meant to be extendible in the future to other providers
                        item.provider = new_parent_item.provider if isinstance(
                            new_parent_item, File) else File.DEFAULT_PROVIDER

                        # flags
                        item.locally_moved = True
                        try:
                            save(session, item)
                        except SQLAlchemyError:
                            logging.exception(
                                'Exception caught: Could not save data for {}'.
                                format(item))
                            AlertHandler.warn(
                                'Error moving file. {} will stop syncing.'.
                                format(item.name))
                        else:
                            logging.info('moved from {} to {}'.format(
                                src_path.full_path, dest_path.full_path))
Пример #35
0
    def _check_file_folder(self,
                           local_file_folder,
                           remote_file_folder,
                           local_parent_file_folder,
                           local_node):
        """
        VARIOUS STATES (update as neccessary):
        (None, None) -> Error                                     --
        (None, remote) ->
            if locally moved -> do nothing
            else -> create local
        (local.create, None) -> create remote                     --
        (local.create, remote) -> ERROR                           --
        (local.delete, None) -> ERROR                             --
        (local.delete, remote) - > delete remote                  --
        (local, None) ->
            if locally moved -> move
            else -> delete local
        (local, remote) -> check modifications                    --

        """

        assert local_file_folder or remote_file_folder  # both shouldnt be None.
        logger.debug('checking file_folder internal')
        if local_file_folder is None:
            locally_moved = yield from self.is_locally_moved(remote_file_folder)
            if locally_moved:
                return
            else:
                local_file_folder = yield from self.create_local_file_folder(
                    remote_file_folder,
                    local_parent_file_folder,
                    local_node
                )
        elif local_file_folder.locally_created and remote_file_folder is None:
            if not local_file_folder.is_provider:
                remote_file_folder = yield from self.create_remote_file_folder(local_file_folder, local_node)
            return
        elif local_file_folder.locally_created and remote_file_folder is not None:
            raise ValueError('newly created local file_folder was already on server')
        elif local_file_folder.locally_deleted and remote_file_folder is None:
            session.delete(local_file_folder)
            save(session)
            logger.warning('local file_folder is to be deleted, however, it was never on the server.')
            return
        elif local_file_folder.locally_deleted and remote_file_folder is not None:
            yield from self.delete_remote_file_folder(local_file_folder, remote_file_folder)
            return
        elif local_file_folder is not None and remote_file_folder is None:
            if local_file_folder.locally_moved:
                # todo: we are ignoring return value for now because to start going down new tree would require
                # todo: us to have the new node. we currently use the head node instead of dynamically determining
                # todo: node. This is problematic. And Bad. FIX IT.
                remote_file_folder = yield from self.move_remote_file_folder(local_file_folder)
                return
            else:
                logger.warning('delete_local_file_folder called on {}'.format(local_file_folder.name))
                yield from self.delete_local_file_folder(local_file_folder)
                return
        elif local_file_folder is not None and remote_file_folder is not None:
            possibly_new_remote_file_folder = yield from self.modify_file_folder_logic(local_file_folder,
                                                                                       remote_file_folder)
            # if we do not need to modify things, remote file folder and local file folder does not change
            # we do not need to get a new local file folder because it is updated internally by the db
            if possibly_new_remote_file_folder:
                remote_file_folder = possibly_new_remote_file_folder
        else:
            raise ValueError('in some weird state. figure it out.')

        assert local_file_folder is not None
        assert remote_file_folder is not None

        # recursively handle folder's children
        if local_file_folder.is_folder:

            remote_children = yield from self.osf_query.get_child_files(remote_file_folder)

            local_remote_file_folders = self.make_local_remote_tuple_list(local_file_folder.files, remote_children)

            for local, remote in local_remote_file_folders:
                yield from self._check_file_folder(
                    local,
                    remote,
                    local_parent_file_folder=local_file_folder,
                    local_node=local_node
                )