xybu/onedrived-dev

View on GitHub
onedrived/od_tasks/move_item.py

Summary

Maintainability
A
1 hr
Test Coverage
import logging
import os

import onedrivesdk.error
from onedrivesdk import Item, ItemReference

from . import update_mtime
from ..od_api_helper import item_request_call


class MoveItemTask(update_mtime.UpdateTimestampTask):

    def __init__(self, repo, task_pool, parent_relpath, item_name,
                 new_parent_relpath=None, new_name=None, item_id=None, is_folder=False):
        """
        :param onedrived.od_repo.OneDriveLocalRepository repo:
        :param onedrived.od_task.TaskPool task_pool:
        :param str parent_relpath:
        :param str item_name:
        :param str | None new_parent_relpath:
        :param str | None new_name:
        :param str | None item_id:
        :param True | False is_folder:
        """
        super().__init__(repo=repo, task_pool=task_pool, parent_relpath=parent_relpath,
                         item_name=item_name, item_id=item_id, is_folder=is_folder)
        if new_parent_relpath is None and new_name is None:
            raise ValueError('New parent directory or name cannot both be None in MoveItemTask.')
        if new_parent_relpath is None:
            new_parent_relpath = parent_relpath
        if new_name is None:
            new_name = item_name
        if new_parent_relpath == parent_relpath and new_name == item_name:
            raise ValueError('Old path and new path are the same. No move is needed.')
        self.new_parent_relpath = new_parent_relpath
        self.new_name = new_name
        self.new_relpath = new_parent_relpath + '/' + new_name
        self.new_local_abspath = self.repo.local_root + self.new_relpath

    def _get_new_item(self):
        item = Item()
        if self.new_parent_relpath != self.parent_relpath:
            ref = ItemReference()
            # Refer to https://dev.onedrive.com/items/move.htm for Move API request.
            ref.path = '/drives/' + self.repo.drive.id + '/root:'
            if self.new_parent_relpath != '':
                ref.path += self.new_parent_relpath
            item.parent_reference = ref
        if self.new_name != self.item_name:
            item.name = self.new_name
        return item

    def __repr__(self):
        return type(self).__name__ + '(from=%s, to=%s, is_folder=%s)' % (
            self.rel_path, self.new_relpath, self.is_folder)

    def handle(self):
        logging.info('Moving item "%s" to "%s".', self.rel_path, self.new_relpath)

        # The routine assumes that the directory to save the new path exists remotely.
        item_request = self.get_item_request()
        try:
            item_stat = os.stat(self.new_local_abspath)
            item = item_request_call(self.repo, item_request.update, self._get_new_item())
            # TODO: update all records or rebuild records after deletion?
            # self.repo.delete_item(self.item_name, self.parent_relpath, self.is_folder)
            self.repo.move_item(item_name=self.item_name, parent_relpath=self.parent_relpath,
                                new_name=self.new_name, new_parent_relpath=self.new_parent_relpath,
                                is_folder=self.is_folder)
            self.update_timestamp_and_record(item, item_stat)
            return True
        except (onedrivesdk.error.OneDriveError, OSError) as e:
            logging.error('Error moving item "%s" to "%s": %s.', self.rel_path, self.new_relpath, e)
            return False