Example #1
0
def repo_download_dir(request, repo_id):
    repo = get_repo(repo_id)
    if not repo:
        return render_error(request, _('Library does not exist'))

    path = request.GET.get('p', '/')
    if path[-1] != '/':         # Normalize dir path
        path += '/'

    if not seafile_api.get_dir_id_by_path(repo.id, path):
        return render_error(request, _('"%s" does not exist.') % path)

    if len(path) > 1:
        dirname = os.path.basename(path.rstrip('/')) # Here use `rstrip` to cut out last '/' in path
    else:
        dirname = repo.name

    allow_download = parse_repo_perm(check_folder_permission(
        request, repo_id, '/')).can_download

    if allow_download:

        dir_id = seafile_api.get_dir_id_by_commit_and_path(repo.id,
            repo.head_cmmt_id, path)
        try:
            total_size = seafile_api.get_dir_size(repo.store_id,
                repo.version, dir_id)
        except Exception as e:
            logger.error(str(e))
            return render_error(request, _('Internal Server Error'))

        if total_size > MAX_DOWNLOAD_DIR_SIZE:
            return render_error(request, _('Unable to download directory "%s": size is too large.') % dirname)

        is_windows = 0
        if is_windows_operating_system(request):
            is_windows = 1

        fake_obj_id = {
            'obj_id': dir_id,
            'dir_name': dirname,
            'is_windows': is_windows
        }

        token = seafile_api.get_fileserver_access_token(
                repo_id, json.dumps(fake_obj_id), 'download-dir', request.user.username)

        if not token:
            return render_error(request, _('Internal Server Error'))

    else:
        return render_error(request, _('Unable to download "%s"') % dirname )

    url = gen_file_get_url(token, dirname)
    from seahub.views.file import send_file_access_msg
    send_file_access_msg(request, repo, path, 'web')
    return redirect(url)
Example #2
0
def repo_download_dir(request, repo_id):
    repo = get_repo(repo_id)
    if not repo:
        return render_error(request, _(u'Library does not exist'))

    path = request.GET.get('p', '/')
    if path[-1] != '/':         # Normalize dir path
        path += '/'

    if not seafile_api.get_dir_id_by_path(repo.id, path):
        return render_error(request, _('"%s" does not exist.') % path)

    if len(path) > 1:
        dirname = os.path.basename(path.rstrip('/')) # Here use `rstrip` to cut out last '/' in path
    else:
        dirname = repo.name

    allow_download = True if check_folder_permission(request, repo_id, '/') else False

    if allow_download:

        dir_id = seafile_api.get_dir_id_by_commit_and_path(repo.id,
            repo.head_cmmt_id, path)
        try:
            total_size = seafile_api.get_dir_size(repo.store_id,
                repo.version, dir_id)
        except Exception, e:
            logger.error(str(e))
            return render_error(request, _(u'Internal Error'))

        if total_size > MAX_DOWNLOAD_DIR_SIZE:
            return render_error(request, _(u'Unable to download directory "%s": size is too large.') % dirname)

        is_windows = 0
        if is_windows_operating_system(request):
            is_windows = 1

        fake_obj_id = {
            'obj_id': dir_id,
            'dir_name': dirname,
            'is_windows': is_windows
        }

        token = seafile_api.get_fileserver_access_token(
                repo_id, json.dumps(fake_obj_id), 'download-dir', request.user.username)
Example #3
0
def repo_download_dir(request, repo_id):
    repo = get_repo(repo_id)
    if not repo:
        return render_error(request, _(u'Library does not exist'))

    path = request.GET.get('p', '/')
    if path[-1] != '/':  # Normalize dir path
        path += '/'

    if not seafile_api.get_dir_id_by_path(repo.id, path):
        return render_error(request, _('"%s" does not exist.') % path)

    if len(path) > 1:
        dirname = os.path.basename(
            path.rstrip('/'))  # Here use `rstrip` to cut out last '/' in path
    else:
        dirname = repo.name

    allow_download = True if check_folder_permission(request, repo_id,
                                                     '/') else False

    if allow_download:

        dir_id = seafile_api.get_dir_id_by_commit_and_path(
            repo.id, repo.head_cmmt_id, path)
        try:
            total_size = seafile_api.get_dir_size(repo.store_id, repo.version,
                                                  dir_id)
        except Exception, e:
            logger.error(str(e))
            return render_error(request, _(u'Internal Error'))

        if total_size > MAX_DOWNLOAD_DIR_SIZE:
            return render_error(
                request,
                _(u'Unable to download directory "%s": size is too large.') %
                dirname)

        token = seafile_api.get_fileserver_access_token(
            repo_id, dir_id, 'download-dir', request.user.username)
Example #4
0
        def _arguments_wrapper(request, repo_id, *args, **kwargs):
            if request.method != 'POST':
                raise Http404

            result = {}
            content_type = 'application/json; charset=utf-8'

            repo = get_repo(repo_id)
            if not repo:
                result['error'] = _(u'Library does not exist.')
                return HttpResponse(json.dumps(result), status=400,
                                    content_type=content_type)

            # arguments validation
            parent_dir = request.GET.get('parent_dir')
            obj_file_names = request.POST.getlist('file_names')
            obj_dir_names = request.POST.getlist('dir_names')
            dst_repo_id = request.POST.get('dst_repo')
            dst_path = request.POST.get('dst_path')
            if not (parent_dir and dst_repo_id and dst_path) and \
               not (obj_file_names or obj_dir_names):
                result['error'] = _('Argument missing')
                return HttpResponse(json.dumps(result), status=400,
                                    content_type=content_type)

            # check file path
            for obj_name in obj_file_names + obj_dir_names:
                if len(dst_path+obj_name) > settings.MAX_PATH:
                    result['error'] =  _('Destination path is too long for %s.') % escape(obj_name)
                    return HttpResponse(json.dumps(result), status=400,
                                        content_type=content_type)

            # when dst is the same as src
            if repo_id == dst_repo_id and parent_dir == dst_path:
                result['error'] = _('Invalid destination path')
                return HttpResponse(json.dumps(result), status=400,
                                    content_type=content_type)

            # check whether user has write permission to dest repo
            if check_folder_permission(request, dst_repo_id, dst_path) != 'rw':
                result['error'] = _('Permission denied')
                return HttpResponse(json.dumps(result), status=403,
                                    content_type=content_type)

            # Leave src folder/file permission checking to corresponding
            # views, only need to check folder permission when perform 'move'
            # operation, 1), if move file, check parent dir perm, 2), if move
            # folder, check that folder perm.

            file_obj_size = 0
            for obj_name in obj_file_names:
                full_obj_path = posixpath.join(parent_dir, obj_name)
                file_obj_id = seafile_api.get_file_id_by_path(repo_id, full_obj_path)
                file_obj_size += seafile_api.get_file_size(
                        repo.store_id, repo.version, file_obj_id)

            dir_obj_size = 0
            for obj_name in obj_dir_names:
                full_obj_path = posixpath.join(parent_dir, obj_name)
                dir_obj_id = seafile_api.get_dir_id_by_path(repo_id, full_obj_path)
                dir_obj_size += seafile_api.get_dir_size(
                        repo.store_id, repo.version, dir_obj_id)

            # check quota
            src_repo_owner = seafile_api.get_repo_owner(repo_id)
            dst_repo_owner = seafile_api.get_repo_owner(dst_repo_id)
            try:
                # always check quota when copy file
                if view_method.__name__ == 'cp_dirents':
                    out_of_quota = seafile_api.check_quota(
                            dst_repo_id, delta=file_obj_size + dir_obj_size)
                else:
                    # when move file
                    if src_repo_owner != dst_repo_owner:
                        # only check quota when src_repo_owner != dst_repo_owner
                        out_of_quota = seafile_api.check_quota(
                                dst_repo_id, delta=file_obj_size + dir_obj_size)
                    else:
                        # not check quota when src and dst repo are both mine
                        out_of_quota = False
            except Exception as e:
                logger.error(e)
                result['error'] = _(u'Internal server error')
                return HttpResponse(json.dumps(result), status=500,
                                content_type=content_type)

            if out_of_quota:
                result['error'] = _('Out of quota.')
                return HttpResponse(json.dumps(result), status=403,
                                    content_type=content_type)

            return view_method(request, repo_id, parent_dir, dst_repo_id,
                               dst_path, obj_file_names, obj_dir_names)
Example #5
0
    def get(self, request, repo_id, format=None):

        repo = seafile_api.get_repo(repo_id)
        if not repo:
            error_msg = 'Library %s not found.' % repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # argument checking
        parent_dir = request.GET.get('parent_dir', None)
        dirent_name_string = request.GET.get('dirents', None)

        if not parent_dir:
            error_msg = 'parent_dir invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not dirent_name_string:
            error_msg = 'dirents invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # folder exist checking
        if not seafile_api.get_dir_id_by_path(repo_id, parent_dir):
            error_msg = 'Folder %s not found.' % parent_dir
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # permission checking
        if check_folder_permission(request, repo_id, parent_dir) is None:
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        dirent_name_list = string2list(dirent_name_string)
        dirent_list = []
        total_size = 0
        for dirent_name in dirent_name_list:
            dirent_name = dirent_name.strip('/')
            dirent_list.append(dirent_name)

            full_dirent_path = posixpath.join(parent_dir, dirent_name)
            current_dirent = seafile_api.get_dirent_by_path(repo_id, full_dirent_path)
            if stat.S_ISDIR(current_dirent.mode):
                total_size += seafile_api.get_dir_size(repo.store_id,
                    repo.version, current_dirent.obj_id)
            else:
                total_size += current_dirent.size

        if total_size > seaserv.MAX_DOWNLOAD_DIR_SIZE:
            error_msg = _('Total size exceeds limit.')
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        fake_obj_id = {}
        fake_obj_id['file_list'] = dirent_list
        fake_obj_id['parent_dir'] = parent_dir

        username = request.user.username
        try:
            token = seafile_api.get_fileserver_access_token(repo_id,
                json.dumps(fake_obj_id), 'download-multi', username, False)
        except SearpcError as e:
            logger.error(e)
            error_msg = 'Internal Server Error'
            return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        if len(dirent_list) > 10:
            send_file_access_msg(request, repo, parent_dir, 'web')
        else:
            for dirent_name in dirent_list:
                full_dirent_path = posixpath.join(parent_dir, dirent_name)
                send_file_access_msg(request, repo, full_dirent_path, 'web')

        download_url = '%s/files/%s' % (get_fileserver_root(), token)
        return Response({'url': download_url})
Example #6
0
    def post(self, request):
        """ Only support move folder.

        Permission checking:

        User with 'rw' permission for src/dst folder.
        """
        src_repo_id = request.data.get('src_repo_id', None)
        src_parent_dir = request.data.get('src_parent_dir', None)
        src_folder_name = request.data.get('src_dirent_name', None)
        dst_repo_id = request.data.get('dst_repo_id', None)
        dst_parent_dir = request.data.get('dst_parent_dir', None)

        # argument check
        if not src_repo_id:
            error_msg = 'src_repo_id invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not src_parent_dir:
            error_msg = 'src_parent_dir invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not src_folder_name:
            error_msg = 'src_dirent_name invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not dst_repo_id:
            error_msg = 'dst_repo_id invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not dst_parent_dir:
            error_msg = 'dst_parent_dir invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if src_repo_id == dst_repo_id and src_parent_dir == dst_parent_dir:
            error_msg = _('Invalid destination path')
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if len(dst_parent_dir + src_folder_name) > MAX_PATH:
            error_msg = _('Destination path is too long.')
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # src resource check
        src_repo = seafile_api.get_repo(src_repo_id)
        if not src_repo:
            error_msg = 'Library %s not found.' % src_repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        src_folder_path = posixpath.join(src_parent_dir, src_folder_name)
        dir_id = seafile_api.get_dir_id_by_path(src_repo_id, src_folder_path)
        if not dir_id:
            error_msg = 'Folder %s not found.' % src_folder_path
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # dst resource check
        dst_repo = seafile_api.get_repo(dst_repo_id)
        if not dst_repo:
            error_msg = 'Library %s not found.' % dst_repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        if not seafile_api.get_dir_id_by_path(dst_repo_id, dst_parent_dir):
            error_msg = 'Folder %s not found.' % dst_parent_dir
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # permission check for src folder
        if check_folder_permission(request, src_repo_id,
                                   src_folder_path) != 'rw':
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # permission check for dst parent dir
        if check_folder_permission(request, dst_repo_id,
                                   dst_parent_dir) != 'rw':
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        ## check if above quota for dst repo
        if get_repo_owner(request, src_repo_id) != get_repo_owner(
                request, dst_repo_id):

            current_size = 0
            current_size = seafile_api.get_dir_size(src_repo.store_id,
                                                    src_repo.version, dir_id)

            if seafile_api.check_quota(dst_repo_id, current_size) < 0:
                return api_error(HTTP_443_ABOVE_QUOTA, _("Out of quota."))

        username = request.user.username
        move_folder_with_merge(username, src_repo_id, src_parent_dir,
                               src_folder_name, dst_repo_id, dst_parent_dir,
                               src_folder_name)

        seafile_api.del_file(src_repo_id, src_parent_dir, src_folder_name,
                             username)

        return Response({'success': True})
Example #7
0
    def post(self, request):
        """ Copy/move file/dir, and return task id.

        Permission checking:
        1. move: user with 'rw' permission for current file, 'rw' permission for dst parent dir;
        2. copy: user with 'r' permission for current file, 'rw' permission for dst parent dir;
        """
        src_repo_id = request.data.get('src_repo_id', None)
        src_parent_dir = request.data.get('src_parent_dir', None)
        src_dirent_name = request.data.get('src_dirent_name', None)
        dst_repo_id = request.data.get('dst_repo_id', None)
        dst_parent_dir = request.data.get('dst_parent_dir', None)
        operation = request.data.get('operation', None)
        dirent_type = request.data.get('dirent_type', None)

        # argument check
        if not src_repo_id:
            error_msg = 'src_repo_id invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not src_parent_dir:
            error_msg = 'src_parent_dir invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not src_dirent_name:
            error_msg = 'src_dirent_name invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not dst_repo_id:
            error_msg = 'dst_repo_id invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not dst_parent_dir:
            error_msg = 'dst_parent_dir invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not operation:
            error_msg = 'operation invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not dirent_type:
            error_msg = 'dirent_type invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if len(dst_parent_dir + src_dirent_name) > MAX_PATH:
            error_msg = _('Destination path is too long.')
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        operation = operation.lower()
        if operation not in ('move', 'copy'):
            error_msg = "operation can only be 'move' or 'copy'."
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if operation == 'move':
            if src_repo_id == dst_repo_id and src_parent_dir == dst_parent_dir:
                error_msg = _('Invalid destination path')
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        dirent_type = dirent_type.lower()
        if dirent_type not in ('file', 'dir'):
            error_msg = "operation can only be 'file' or 'dir'."
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # src resource check
        src_repo = seafile_api.get_repo(src_repo_id)
        if not src_repo:
            error_msg = 'Library %s not found.' % src_repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        src_dirent_path = posixpath.join(src_parent_dir, src_dirent_name)
        file_id = None
        if dirent_type == 'file':
            file_id = seafile_api.get_file_id_by_path(src_repo_id, src_dirent_path)
            if not file_id:
                error_msg = 'File %s not found.' % src_dirent_path
                return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        dir_id = None
        if dirent_type == 'dir':
            dir_id = seafile_api.get_dir_id_by_path(src_repo_id, src_dirent_path)
            if not dir_id:
                error_msg = 'Folder %s not found.' % src_dirent_path
                return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # dst resource check
        dst_repo = seafile_api.get_repo(dst_repo_id)
        if not dst_repo:
            error_msg = 'Library %s not found.' % dst_repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        if not seafile_api.get_dir_id_by_path(dst_repo_id,
                                              dst_parent_dir):
            error_msg = 'Folder %s not found.' % dst_parent_dir
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # permission check for dst parent dir
        if check_folder_permission(request, dst_repo_id, dst_parent_dir) != 'rw':
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        if operation == 'copy' or \
                operation == 'move' and \
                get_repo_owner(request, src_repo_id) != get_repo_owner(request, dst_repo_id):

            current_size = 0
            if file_id:
                current_size = seafile_api.get_file_size(src_repo.store_id,
                        src_repo.version, file_id)

            if dir_id:
                current_size = seafile_api.get_dir_size(src_repo.store_id,
                        src_repo.version, dir_id)

            # check if above quota for dst repo
            if seafile_api.check_quota(dst_repo_id, current_size) < 0:
                return api_error(HTTP_443_ABOVE_QUOTA, _(u"Out of quota."))

        new_dirent_name = check_filename_with_rename(dst_repo_id,
                dst_parent_dir, src_dirent_name)

        username = request.user.username
        if operation == 'move':
            # permission check for src parent dir
            if check_folder_permission(request, src_repo_id, src_parent_dir) != 'rw':
                error_msg = 'Permission denied.'
                return api_error(status.HTTP_403_FORBIDDEN, error_msg)

            if dirent_type == 'dir' and src_repo_id == dst_repo_id and \
                    dst_parent_dir.startswith(src_dirent_path + '/'):

                error_msg = _(u'Can not move directory %(src)s to its subdirectory %(des)s') \
                    % {'src': escape(src_dirent_path), 'des': escape(dst_parent_dir)}
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

            if dirent_type == 'file':
                # check file lock
                try:
                    is_locked, locked_by_me = check_file_lock(src_repo_id,
                            src_dirent_path, username)
                except Exception as e:
                    logger.error(e)
                    error_msg = 'Internal Server Error'
                    return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

                if is_locked and not locked_by_me:
                    error_msg = _("File is locked")
                    return api_error(status.HTTP_403_FORBIDDEN, error_msg)

            try:
                res = seafile_api.move_file(src_repo_id, src_parent_dir,
                                            src_dirent_name, dst_repo_id, dst_parent_dir,
                                            new_dirent_name, replace=False, username=username,
                                            need_progress=1)

            except Exception as e:
                logger.error(e)
                error_msg = 'Internal Server Error'
                return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        if operation == 'copy':
            # permission check for src parent dir
            if parse_repo_perm(check_folder_permission(
                            request, src_repo_id, src_parent_dir)).can_copy is False:
                error_msg = 'Permission denied.'
                return api_error(status.HTTP_403_FORBIDDEN, error_msg)

            try:
                res = seafile_api.copy_file(src_repo_id, src_parent_dir,
                                            src_dirent_name, dst_repo_id, dst_parent_dir,
                                            new_dirent_name, username=username,
                                            need_progress=1)
            except Exception as e:
                logger.error(e)
                error_msg = 'Internal Server Error'
                return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        if not res:
            error_msg = 'Internal Server Error'
            return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        result = {}
        if res.background:
            result['task_id'] = res.task_id

        return Response(result)
Example #8
0
    def get(self, request, repo_id, format=None):
        """ Get file server token for download-dir and download-multi.

        Permission checking:
        1. user with 'r' or 'rw' permission;
        """

        # argument check
        parent_dir = request.GET.get('parent_dir', None)
        if not parent_dir:
            error_msg = 'parent_dir invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        dirent_name_list = request.GET.getlist('dirents', None)
        if not dirent_name_list:
            error_msg = 'dirents invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if len(dirent_name_list) == 1:
            download_type = 'download-dir'
        elif len(dirent_name_list) > 1:
            download_type = 'download-multi'
        else:
            error_msg = 'dirents invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # recourse check
        repo = seafile_api.get_repo(repo_id)
        if not repo:
            error_msg = 'Library %s not found.' % repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        if not seafile_api.get_dir_id_by_path(repo_id, parent_dir):
            error_msg = 'Folder %s not found.' % parent_dir
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # permission check
        if not check_folder_permission(request, repo_id, parent_dir):
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # get file server access token
        is_windows = 0
        if is_windows_operating_system(request):
            is_windows = 1

        if download_type == 'download-dir':
            dir_name = dirent_name_list[0].strip('/')
            full_dir_path = posixpath.join(parent_dir, dir_name)

            dir_id = seafile_api.get_dir_id_by_path(repo_id, full_dir_path)
            if not dir_id:
                error_msg = 'Folder %s not found.' % full_dir_path
                return api_error(status.HTTP_404_NOT_FOUND, error_msg)

            dir_size = seafile_api.get_dir_size(repo.store_id, repo.version,
                                                dir_id)

            if dir_size > seaserv.MAX_DOWNLOAD_DIR_SIZE:
                error_msg = 'Unable to download directory "%s": size is too large.' % dir_name
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

            fake_obj_id = {
                'obj_id': dir_id,
                'dir_name': dir_name,
                'is_windows': is_windows
            }

        if download_type == 'download-multi':
            dirent_list = []
            total_size = 0
            for dirent_name in dirent_name_list:
                dirent_name = dirent_name.strip('/')
                dirent_list.append(dirent_name)

                full_dirent_path = posixpath.join(parent_dir, dirent_name)
                current_dirent = seafile_api.get_dirent_by_path(
                    repo_id, full_dirent_path)
                if not current_dirent:
                    continue

                if stat.S_ISDIR(current_dirent.mode):
                    total_size += seafile_api.get_dir_size(
                        repo.store_id, repo.version, current_dirent.obj_id)
                else:
                    total_size += current_dirent.size

            if total_size > seaserv.MAX_DOWNLOAD_DIR_SIZE:
                error_msg = _('Total size exceeds limit.')
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

            fake_obj_id = {
                'parent_dir': parent_dir,
                'file_list': dirent_list,
                'is_windows': is_windows
            }

        username = request.user.username
        try:
            zip_token = seafile_api.get_fileserver_access_token(
                repo_id, json.dumps(fake_obj_id), download_type, username)
        except Exception as e:
            logger.error(e)
            error_msg = 'Internal Server Error'
            return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        if len(dirent_name_list) > 10:
            send_file_access_msg(request, repo, parent_dir, 'web')
        else:
            for dirent_name in dirent_name_list:
                full_dirent_path = posixpath.join(parent_dir, dirent_name)
                send_file_access_msg(request, repo, full_dirent_path, 'web')

        return Response({'zip_token': zip_token})
Example #9
0
    def post(self, request, format=None):
        """ Only used for download dirents in a folder share link.

        Permission checking:
        1, If enable SHARE_LINK_LOGIN_REQUIRED, user must have been authenticated.
        2, If enable ENABLE_SHARE_LINK_AUDIT, user must have been authenticated, or have been audited.
        3, If share link is encrypted, share link password must have been checked.
        """

        # argument check
        share_link_token = request.data.get('token', None)
        if not share_link_token:
            error_msg = 'share_link_token invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        parent_dir = request.data.get('parent_dir', '/')
        if not parent_dir:
            error_msg = 'parent_dir invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        dirent_name_list = request.data.get('dirents', None)
        if not dirent_name_list:
            error_msg = 'dirent_name invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # resource check
        try:
            share_link= FileShare.objects.get(token=share_link_token)
        except FileShare.DoesNotExist:
            error_msg = 'Share link %s not found.' % share_link_token
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        if share_link.s_type != 'd':
            error_msg = 'Share link %s is not a folder share link.' % share_link_token
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        repo_id = share_link.repo_id
        repo = seafile_api.get_repo(repo_id)
        if not repo:
            error_msg = 'Library %s not found.' % repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        full_parent_dir = posixpath.join(normalize_dir_path(share_link.path),
                parent_dir.strip('/'))
        full_parent_dir = normalize_dir_path(full_parent_dir)
        dir_id = seafile_api.get_dir_id_by_path(repo_id, full_parent_dir)
        if not dir_id:
            error_msg = 'Folder %s not found.' % parent_dir
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # permission check
        # check if login required
        if SHARE_LINK_LOGIN_REQUIRED and \
                not request.user.is_authenticated():
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # check share link audit
        if is_pro_version() and ENABLE_SHARE_LINK_AUDIT and \
                not request.user.is_authenticated() and \
                not request.session.get('anonymous_email'):
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # check share link password
        if share_link.is_encrypted() and not check_share_link_access(request,
                share_link_token):
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # check if has download permission for share link creator
        if not parse_repo_perm(seafile_api.check_permission_by_path(
                    repo_id, full_parent_dir, share_link.username)).can_download:
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # check if share link has download permission
        if not share_link.get_permissions()['can_download']:
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # get file server access token
        is_windows = 0
        if is_windows_operating_system(request):
            is_windows = 1

        dirent_list = []
        total_size = 0
        for dirent_name in dirent_name_list:

            dirent_name = dirent_name.strip('/')
            full_dirent_path = posixpath.join(full_parent_dir, dirent_name)

            current_dirent = seafile_api.get_dirent_by_path(repo_id, full_dirent_path)
            if not current_dirent:
                continue

            if stat.S_ISDIR(current_dirent.mode):
                total_size += seafile_api.get_dir_size(repo.store_id,
                    repo.version, current_dirent.obj_id)
            else:
                total_size += current_dirent.size

            dirent_list.append(dirent_name)

        if total_size > seaserv.MAX_DOWNLOAD_DIR_SIZE:
            error_msg = _('Total size exceeds limit.')
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not dirent_list:
            error_msg = 'No valid dirent.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        fake_obj_id = {
            'parent_dir': full_parent_dir,
            'file_list': dirent_list,
            'is_windows': is_windows
        }

        try:
            zip_token = seafile_api.get_fileserver_access_token(
                repo_id, json.dumps(fake_obj_id), 'download-multi', '',
                use_onetime=settings.FILESERVER_TOKEN_ONCE_ONLY)
        except Exception as e:
            logger.error(e)
            error_msg = 'Internal Server Error'
            return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        if not zip_token:
            error_msg = 'Internal Server Error'
            return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        return Response({'zip_token': zip_token})
Example #10
0
def test_file_property_and_dir_listing():

    t_repo_version = 1
    t_repo_id = api.create_repo('test_file_property_and_dir_listing',
                                '',
                                USER,
                                passwd=None)

    create_the_file()

    api.post_file(t_repo_id, file_path, '/', file_name, USER)
    api.post_dir(t_repo_id, '/', dir_name, USER)
    api.post_file(t_repo_id, file_path, '/' + dir_name, file_name, USER)

    #test is_valid_filename
    t_valid_file_name = 'valid_filename'
    t_invalid_file_name = '/invalid_filename'
    assert api.is_valid_filename(t_repo_id, t_valid_file_name)
    assert api.is_valid_filename(t_repo_id, t_invalid_file_name) == 0

    #test get_file_id_by_path
    t_file_id = api.get_file_id_by_path(t_repo_id, '/test.txt')
    assert t_file_id

    #test get_dir_id_by_path
    t_dir_id = api.get_dir_id_by_path(t_repo_id, '/test_dir')
    assert t_dir_id

    #test get_file_size
    t_file_size = len(file_content)
    assert t_file_size == api.get_file_size(t_repo_id, t_repo_version,
                                            t_file_id)

    #test get_dir_size
    t_dir_size = len(file_content)
    assert t_dir_size == api.get_dir_size(t_repo_id, t_repo_version, t_dir_id)

    #test get_file_count_info_by_path
    t_file_count_info = api.get_file_count_info_by_path(t_repo_id, '/')
    assert t_file_count_info.file_count == 2
    assert t_file_count_info.dir_count == 1
    assert t_file_count_info.size == t_file_size + t_dir_size

    #test get_file_id_by_commit_and_path
    t_file_id_tmp = t_file_id
    t_repo = api.get_repo(t_repo_id)
    assert t_repo
    t_commit_id = t_repo.head_cmmt_id
    t_file_id = api.get_file_id_by_commit_and_path(t_repo_id, t_commit_id,
                                                   '/test.txt')

    assert t_file_id == t_file_id_tmp

    #test get_dirent_by_path
    std_file_mode = 0100000 | 0644
    t_dirent_obj = api.get_dirent_by_path(t_repo_id, '/test.txt')
    assert t_dirent_obj
    assert t_dirent_obj.obj_id == t_file_id
    assert t_dirent_obj.obj_name == 'test.txt'
    assert t_dirent_obj.mode == std_file_mode
    assert t_dirent_obj.version == t_repo_version
    assert t_dirent_obj.size == t_file_size
    assert t_dirent_obj.modifier == USER

    #test list_file_by_file_id
    t_block_list = api.list_file_by_file_id(t_repo_id, t_file_id)
    assert t_block_list

    #test list_blocks_by_file_id
    t_block_list = api.list_blocks_by_file_id(t_repo_id, t_file_id)
    assert t_block_list

    #test list_dir_by_dir_id
    t_dir_list = api.list_dir_by_dir_id(t_repo_id, t_dir_id)
    assert len(t_dir_list) == 1

    #test list_dir_by_path
    t_dir_list = api.list_dir_by_path(t_repo_id, '/test_dir')
    assert len(t_dir_list) == 1

    #test get_dir_id_by_commit_and_path
    t_dir_id = api.get_dir_id_by_commit_and_path(t_repo_id, t_commit_id,
                                                 '/test_dir')
    assert t_dir_id

    #test list_dir_by_commit_and_path
    t_dir_list = api.list_dir_by_commit_and_path(t_repo_id, t_commit_id,
                                                 '/test_dir')
    assert len(t_dir_list) == 1

    #test list_dir_with_perm
    t_dir_list = api.list_dir_with_perm(t_repo_id, '/test_dir', t_dir_id, USER)
    assert len(t_dir_list) == 1

    #test mkdir_with_parent
    api.mkdir_with_parents(t_repo_id, '/test_dir', 'test_subdir', USER)
    t_dir_id = api.get_dir_id_by_path(t_repo_id, '/test_dir/test_subdir')
    assert t_dir_id

    #test get_total_storage
    t_total_size = api.get_total_storage()
    t_repo_size = api.get_repo_size(t_repo_id)
    assert t_total_size == t_repo_size

    #get_total_file_number
    time.sleep(1)
    assert api.get_total_file_number() == 2

    api.remove_repo(t_repo_id)
Example #11
0
    def post(self, request):
        """ Copy/move file/dir, and return task id.

        Permission checking:
        1. move: user with 'rw' permission for current file, 'rw' permission for dst parent dir;
        2. copy: user with 'r' permission for current file, 'rw' permission for dst parent dir;
        """
        src_repo_id = request.data.get('src_repo_id', None)
        src_parent_dir = request.data.get('src_parent_dir', None)
        src_dirent_name = request.data.get('src_dirent_name', None)
        dst_repo_id = request.data.get('dst_repo_id', None)
        dst_parent_dir = request.data.get('dst_parent_dir', None)
        operation = request.data.get('operation', None)
        dirent_type = request.data.get('dirent_type', None)

        # argument check
        if not src_repo_id:
            error_msg = 'src_repo_id invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not src_parent_dir:
            error_msg = 'src_parent_dir invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not src_dirent_name:
            error_msg = 'src_dirent_name invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not dst_repo_id:
            error_msg = 'dst_repo_id invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not dst_parent_dir:
            error_msg = 'dst_parent_dir invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not operation:
            error_msg = 'operation invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not dirent_type:
            error_msg = 'dirent_type invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if len(dst_parent_dir + src_dirent_name) > MAX_PATH:
            error_msg = _('Destination path is too long.')
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        operation = operation.lower()
        if operation not in ('move', 'copy'):
            error_msg = "operation can only be 'move' or 'copy'."
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if operation == 'move':
            if src_repo_id == dst_repo_id and src_parent_dir == dst_parent_dir:
                error_msg = _('Invalid destination path')
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        dirent_type = dirent_type.lower()
        if dirent_type not in ('file', 'dir'):
            error_msg = "operation can only be 'file' or 'dir'."
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # src resource check
        src_repo = seafile_api.get_repo(src_repo_id)
        if not src_repo:
            error_msg = 'Library %s not found.' % src_repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        src_dirent_path = posixpath.join(src_parent_dir, src_dirent_name)
        file_id = None
        if dirent_type == 'file':
            file_id = seafile_api.get_file_id_by_path(src_repo_id, src_dirent_path)
            if not file_id:
                error_msg = 'File %s not found.' % src_dirent_path
                return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        dir_id = None
        if dirent_type == 'dir':
            dir_id = seafile_api.get_dir_id_by_path(src_repo_id, src_dirent_path)
            if not dir_id:
                error_msg = 'Folder %s not found.' % src_dirent_path
                return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # dst resource check
        dst_repo = seafile_api.get_repo(dst_repo_id)
        if not dst_repo:
            error_msg = 'Library %s not found.' % dst_repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        if not seafile_api.get_dir_id_by_path(dst_repo_id,
                                              dst_parent_dir):
            error_msg = 'Folder %s not found.' % dst_parent_dir
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # permission check for dst parent dir
        if check_folder_permission(request, dst_repo_id, dst_parent_dir) != 'rw':
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        if operation == 'copy' or \
                operation == 'move' and \
                get_repo_owner(request, src_repo_id) != get_repo_owner(request, dst_repo_id):

            current_size = 0
            if file_id:
                current_size = seafile_api.get_file_size(src_repo.store_id,
                        src_repo.version, file_id)

            if dir_id:
                current_size = seafile_api.get_dir_size(src_repo.store_id,
                        src_repo.version, dir_id)

            # check if above quota for dst repo
            if seafile_api.check_quota(dst_repo_id, current_size) < 0:
                return api_error(HTTP_443_ABOVE_QUOTA, _("Out of quota."))

        new_dirent_name = check_filename_with_rename(dst_repo_id,
                dst_parent_dir, src_dirent_name)

        username = request.user.username
        if operation == 'move':
            # permission check for src parent dir
            if check_folder_permission(request, src_repo_id, src_parent_dir) != 'rw':
                error_msg = 'Permission denied.'
                return api_error(status.HTTP_403_FORBIDDEN, error_msg)

            if dirent_type == 'dir' and src_repo_id == dst_repo_id and \
                    dst_parent_dir.startswith(src_dirent_path + '/'):

                error_msg = _('Can not move directory %(src)s to its subdirectory %(des)s') \
                    % {'src': escape(src_dirent_path), 'des': escape(dst_parent_dir)}
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

            if dirent_type == 'file':
                # check file lock
                try:
                    is_locked, locked_by_me = check_file_lock(src_repo_id,
                            src_dirent_path, username)
                except Exception as e:
                    logger.error(e)
                    error_msg = 'Internal Server Error'
                    return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

                if is_locked and not locked_by_me:
                    error_msg = _("File is locked")
                    return api_error(status.HTTP_403_FORBIDDEN, error_msg)

            try:
                res = seafile_api.move_file(src_repo_id, src_parent_dir,
                                            src_dirent_name, dst_repo_id, dst_parent_dir,
                                            new_dirent_name, replace=False, username=username,
                                            need_progress=1)

            except Exception as e:
                logger.error(e)
                error_msg = 'Internal Server Error'
                return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        if operation == 'copy':
            # permission check for src parent dir
            if parse_repo_perm(check_folder_permission(
                            request, src_repo_id, src_parent_dir)).can_copy is False:
                error_msg = 'Permission denied.'
                return api_error(status.HTTP_403_FORBIDDEN, error_msg)

            try:
                res = seafile_api.copy_file(src_repo_id, src_parent_dir,
                                            src_dirent_name, dst_repo_id, dst_parent_dir,
                                            new_dirent_name, username=username,
                                            need_progress=1)
            except Exception as e:
                logger.error(e)
                error_msg = 'Internal Server Error'
                return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        if not res:
            error_msg = 'Internal Server Error'
            return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        result = {}
        if res.background:
            result['task_id'] = res.task_id

        return Response(result)
Example #12
0
    def get(self, request, format=None):
        """ Only used for download dir when view dir share link from web.


        Permission checking:
        1. authenticated user OR anonymous user has passed email code check(if necessary);
        """

        # permission check
        if is_pro_version() and settings.ENABLE_SHARE_LINK_AUDIT:
            if not request.user.is_authenticated() and \
                not request.session.get('anonymous_email'):
                # if anonymous user has passed email code check,
                # then his/her email info will be in session.

                error_msg = 'Permission denied.'
                return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # argument check
        share_link_token = request.GET.get('share_link_token', None)
        if not share_link_token:
            error_msg = 'share_link_token invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        req_path = request.GET.get('path', None)
        if not req_path:
            error_msg = 'path invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # recourse check
        fileshare = FileShare.objects.get_valid_dir_link_by_token(share_link_token)
        if not fileshare:
            error_msg = 'share_link_token %s not found.' % share_link_token
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        if req_path[-1] != '/':
            req_path += '/'

        if req_path == '/':
            real_path = fileshare.path
        else:
            real_path = posixpath.join(fileshare.path, req_path.lstrip('/'))

        if real_path[-1] != '/':
            real_path += '/'

        repo_id = fileshare.repo_id
        repo = seafile_api.get_repo(repo_id)
        if not repo:
            error_msg = 'Library %s not found.' % repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        dir_id = seafile_api.get_dir_id_by_path(repo_id, real_path)
        if not dir_id:
            error_msg = 'Folder %s not found.' % real_path
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # get file server access token
        dir_name = repo.name if real_path == '/' else \
                os.path.basename(real_path.rstrip('/'))

        dir_size = seafile_api.get_dir_size(
                repo.store_id, repo.version, dir_id)
        if dir_size > seaserv.MAX_DOWNLOAD_DIR_SIZE:
            error_msg = 'Unable to download directory "%s": size is too large.' % dir_name
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        is_windows = 0
        if is_windows_operating_system(request):
            is_windows = 1

        fake_obj_id = {
            'obj_id': dir_id,
            'dir_name': dir_name,
            'is_windows': is_windows
        }

        username = request.user.username
        try:
            zip_token = seafile_api.get_fileserver_access_token(
                    repo_id, json.dumps(fake_obj_id), 'download-dir', username)
        except Exception as e:
            logger.error(e)
            error_msg = 'Internal Server Error'
            return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        if request.session.get('anonymous_email'):
            request.user.username = request.session.get('anonymous_email')

        send_file_access_msg(request, repo, real_path, 'share-link')

        return Response({'zip_token': zip_token})
Example #13
0
    def get(self, request, repo_id, format=None):
        """ Get file server token for download-dir and download-multi.

        Permission checking:
        1. user with 'r' or 'rw' permission;
        """

        # argument check
        parent_dir = request.GET.get('parent_dir', None)
        if not parent_dir:
            error_msg = 'parent_dir invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        dirent_name_list = request.GET.getlist('dirents', None)
        if not dirent_name_list:
            error_msg = 'dirents invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if len(dirent_name_list) == 1:
            download_type = 'download-dir'
        elif len(dirent_name_list) > 1:
            download_type = 'download-multi'
        else:
            error_msg = 'dirents invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # recourse check
        repo = seafile_api.get_repo(repo_id)
        if not repo:
            error_msg = 'Library %s not found.' % repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        if not seafile_api.get_dir_id_by_path(repo_id, parent_dir):
            error_msg = 'Folder %s not found.' % parent_dir
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # permission check
        if not check_folder_permission(request, repo_id, parent_dir):
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # get file server access token
        is_windows = 0
        if is_windows_operating_system(request):
            is_windows = 1

        if download_type == 'download-dir':
            dir_name = dirent_name_list[0].strip('/')
            full_dir_path = posixpath.join(parent_dir, dir_name)

            dir_id = seafile_api.get_dir_id_by_path(repo_id, full_dir_path)
            if not dir_id:
                error_msg = 'Folder %s not found.' % full_dir_path
                return api_error(status.HTTP_404_NOT_FOUND, error_msg)

            dir_size = seafile_api.get_dir_size(
                    repo.store_id, repo.version, dir_id)

            if dir_size > seaserv.MAX_DOWNLOAD_DIR_SIZE:
                error_msg = 'Unable to download directory "%s": size is too large.' % dir_name
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

            fake_obj_id = {
                'obj_id': dir_id,
                'dir_name': dir_name,
                'is_windows': is_windows
            }

        if download_type == 'download-multi':
            dirent_list = []
            total_size = 0
            for dirent_name in dirent_name_list:
                dirent_name = dirent_name.strip('/')
                dirent_list.append(dirent_name)

                full_dirent_path = posixpath.join(parent_dir, dirent_name)
                current_dirent = seafile_api.get_dirent_by_path(repo_id, full_dirent_path)
                if not current_dirent:
                    continue

                if stat.S_ISDIR(current_dirent.mode):
                    total_size += seafile_api.get_dir_size(repo.store_id,
                        repo.version, current_dirent.obj_id)
                else:
                    total_size += current_dirent.size

            if total_size > seaserv.MAX_DOWNLOAD_DIR_SIZE:
                error_msg = _('Total size exceeds limit.')
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

            fake_obj_id = {
                'parent_dir': parent_dir,
                'file_list': dirent_list,
                'is_windows': is_windows
            }

        username = request.user.username
        try:
            zip_token = seafile_api.get_fileserver_access_token(
                    repo_id, json.dumps(fake_obj_id), download_type, username)
        except Exception as e:
            logger.error(e)
            error_msg = 'Internal Server Error'
            return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        if len(dirent_name_list) > 10:
            send_file_access_msg(request, repo, parent_dir, 'web')
        else:
            for dirent_name in dirent_name_list:
                full_dirent_path = posixpath.join(parent_dir, dirent_name)
                send_file_access_msg(request, repo, full_dirent_path, 'web')

        return Response({'zip_token': zip_token})
    def get(self, request, repo_id, format=None):

        repo = seafile_api.get_repo(repo_id)
        if not repo:
            error_msg = 'Library %s not found.' % repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # argument checking
        parent_dir = request.GET.get('parent_dir', None)
        dirent_name_string = request.GET.get('dirents', None)

        if not parent_dir:
            error_msg = 'parent_dir invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not dirent_name_string:
            error_msg = 'dirents invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # folder exist checking
        if not seafile_api.get_dir_id_by_path(repo_id, parent_dir):
            error_msg = 'Folder %s not found.' % parent_dir
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # permission checking
        if check_folder_permission(request, repo_id, parent_dir) is None:
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        dirent_name_list = string2list(dirent_name_string)
        dirent_list = []
        total_size = 0
        for dirent_name in dirent_name_list:
            dirent_name = dirent_name.strip('/')
            dirent_list.append(dirent_name)

            full_dirent_path = posixpath.join(parent_dir, dirent_name)
            current_dirent = seafile_api.get_dirent_by_path(
                repo_id, full_dirent_path)
            if stat.S_ISDIR(current_dirent.mode):
                total_size += seafile_api.get_dir_size(repo.store_id,
                                                       repo.version,
                                                       current_dirent.obj_id)
            else:
                total_size += current_dirent.size

        if total_size > seaserv.MAX_DOWNLOAD_DIR_SIZE:
            error_msg = _('Total size exceeds limit.')
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        fake_obj_id = {}
        fake_obj_id['file_list'] = dirent_list
        fake_obj_id['parent_dir'] = parent_dir

        username = request.user.username
        try:
            token = seafile_api.get_fileserver_access_token(
                repo_id, json.dumps(fake_obj_id), 'download-multi', username,
                False)
        except SearpcError as e:
            logger.error(e)
            error_msg = 'Internal Server Error'
            return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        if len(dirent_list) > 10:
            send_file_access_msg(request, repo, parent_dir, 'web')
        else:
            for dirent_name in dirent_list:
                full_dirent_path = posixpath.join(parent_dir, dirent_name)
                send_file_access_msg(request, repo, full_dirent_path, 'web')

        download_url = '%s/files/%s' % (get_fileserver_root(), token)
        return Response({'url': download_url})
Example #15
0
    def post(self, request):
        """ Multi copy folders.

        Permission checking:
        1. User must has `r/rw` permission for src folder.
        2. User must has `rw` permission for dst folder.

        Parameter:
        {
            "src_repo_id":"7460f7ac-a0ff-4585-8906-bb5a57d2e118",
            "dst_repo_id":"a3fa768d-0f00-4343-8b8d-07b4077881db",
            "paths":[
                {"src_path":"/1/2/3/","dst_path":"/4/5/6/"},
                {"src_path":"/a/b/c/","dst_path":"/d/e/f/"},
            ]
        }
        """

        # argument check
        path_list = request.data.get('paths', None)
        if not path_list:
            error_msg = 'paths invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        src_repo_id = request.data.get('src_repo_id', None)
        if not src_repo_id:
            error_msg = 'src_repo_id invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        dst_repo_id = request.data.get('dst_repo_id', None)
        if not dst_repo_id:
            error_msg = 'dst_repo_id invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # permission check, user must has `r/rw` permission for src repo.
        if check_folder_permission(request, src_repo_id, '/') is None:
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # permission check, user must has `rw` permission for dst repo.
        if check_folder_permission(request, dst_repo_id, '/') != 'rw':
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # resource check
        src_repo = seafile_api.get_repo(src_repo_id)
        if not src_repo:
            error_msg = 'Library %s not found.' % src_repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        dst_repo = seafile_api.get_repo(dst_repo_id)
        if not dst_repo:
            error_msg = 'Library %s not found.' % dst_repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # get total size of file/dir to be copied
        total_size = 0
        for path_item in path_list:
            src_path = path_item['src_path']
            src_path = normalize_dir_path(src_path)

            current_size = 0
            current_dir_id = seafile_api.get_dir_id_by_path(
                src_repo_id, src_path)
            current_size = seafile_api.get_dir_size(src_repo.store_id,
                                                    src_repo.version,
                                                    current_dir_id)

            total_size += current_size

        # check if above quota for dst repo
        if seafile_api.check_quota(dst_repo_id, total_size) < 0:
            return api_error(HTTP_443_ABOVE_QUOTA, _(u"Out of quota."))

        result = {}
        result['failed'] = []
        result['success'] = []
        username = request.user.username

        for path_item in path_list:

            src_path = path_item['src_path']
            src_path = normalize_dir_path(src_path)
            src_parent_dir = os.path.dirname(src_path.rstrip('/'))
            src_parent_dir = normalize_dir_path(src_parent_dir)
            src_obj_name = os.path.basename(src_path.rstrip('/'))

            dst_path = path_item['dst_path']
            dst_path = normalize_dir_path(dst_path)
            dst_parent_dir = dst_path
            dst_obj_name = src_obj_name

            common_dict = {
                'src_repo_id': src_repo_id,
                'src_path': src_path,
                'dst_repo_id': dst_repo_id,
                'dst_path': dst_path,
            }

            # src/dst parameter check
            if src_repo_id == dst_repo_id and \
                    dst_path.startswith(src_path):
                error_dict = {
                    'error_msg':
                    "The destination directory is the same as the source, or is it's subfolder."
                }
                common_dict.update(error_dict)
                result['failed'].append(common_dict)
                continue

            if src_path == '/':
                error_dict = {'error_msg': "The source path can not be '/'."}
                common_dict.update(error_dict)
                result['failed'].append(common_dict)
                continue

            if len(dst_parent_dir + dst_obj_name) > MAX_PATH:
                error_dict = {'error_msg': "'Destination path is too long."}
                common_dict.update(error_dict)
                result['failed'].append(common_dict)
                continue

            # src resource check
            if not seafile_api.get_dir_id_by_path(src_repo_id, src_path):
                error_dict = {'error_msg': 'Folder %s not found.' % src_path}
                common_dict.update(error_dict)
                result['failed'].append(common_dict)
                continue

            # dst resource check
            if not seafile_api.get_dir_id_by_path(dst_repo_id, dst_path):
                error_dict = {'error_msg': 'Folder %s not found.' % dst_path}
                common_dict.update(error_dict)
                result['failed'].append(common_dict)
                continue

            # src path permission check, user must has `r/rw` permission for src folder.
            if check_folder_permission(request, src_repo_id,
                                       src_parent_dir) is None:
                error_dict = {'error_msg': 'Permission denied.'}
                common_dict.update(error_dict)
                result['failed'].append(common_dict)
                continue

            # dst path permission check, user must has `rw` permission for dst folder.
            if check_folder_permission(request, dst_repo_id, dst_path) != 'rw':
                error_dict = {'error_msg': 'Permission denied.'}
                common_dict.update(error_dict)
                result['failed'].append(common_dict)
                continue

            try:
                # need_progress=0, synchronous=1
                seafile_api.copy_file(src_repo_id, src_parent_dir,
                                      src_obj_name, dst_repo_id,
                                      dst_parent_dir, dst_obj_name, username,
                                      0, 1)
            except Exception as e:
                logger.error(e)
                error_dict = {'error_msg': 'Internal Server Error'}
                common_dict.update(error_dict)
                result['failed'].append(common_dict)
                continue

            result['success'].append(common_dict)

        return Response(result)
Example #16
0
    def post(self, request):
        """ Only support move folder.

        Permission checking:

        User with 'rw' permission for src/dst folder.
        """
        src_repo_id = request.data.get('src_repo_id', None)
        src_parent_dir = request.data.get('src_parent_dir', None)
        src_folder_name = request.data.get('src_dirent_name', None)
        dst_repo_id = request.data.get('dst_repo_id', None)
        dst_parent_dir = request.data.get('dst_parent_dir', None)

        # argument check
        if not src_repo_id:
            error_msg = 'src_repo_id invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not src_parent_dir:
            error_msg = 'src_parent_dir invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not src_folder_name:
            error_msg = 'src_dirent_name invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not dst_repo_id:
            error_msg = 'dst_repo_id invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if not dst_parent_dir:
            error_msg = 'dst_parent_dir invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if src_repo_id == dst_repo_id and src_parent_dir == dst_parent_dir:
            error_msg = _('Invalid destination path')
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if len(dst_parent_dir + src_folder_name) > MAX_PATH:
            error_msg = _('Destination path is too long.')
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # src resource check
        src_repo = seafile_api.get_repo(src_repo_id)
        if not src_repo:
            error_msg = 'Library %s not found.' % src_repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        src_folder_path = posixpath.join(src_parent_dir, src_folder_name)
        dir_id = seafile_api.get_dir_id_by_path(src_repo_id, src_folder_path)
        if not dir_id:
            error_msg = 'Folder %s not found.' % src_folder_path
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # dst resource check
        dst_repo = seafile_api.get_repo(dst_repo_id)
        if not dst_repo:
            error_msg = 'Library %s not found.' % dst_repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        if not seafile_api.get_dir_id_by_path(dst_repo_id, dst_parent_dir):
            error_msg = 'Folder %s not found.' % dst_parent_dir
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # permission check for src folder
        if check_folder_permission(request, src_repo_id, src_folder_path) != 'rw':
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # permission check for dst parent dir
        if check_folder_permission(request, dst_repo_id, dst_parent_dir) != 'rw':
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        ## check if above quota for dst repo
        if get_repo_owner(request, src_repo_id) != get_repo_owner(request, dst_repo_id):

            current_size = 0
            current_size = seafile_api.get_dir_size(src_repo.store_id,
                    src_repo.version, dir_id)

            if seafile_api.check_quota(dst_repo_id, current_size) < 0:
                return api_error(HTTP_443_ABOVE_QUOTA, _(u"Out of quota."))

        username = request.user.username
        move_folder_with_merge(username,
                src_repo_id, src_parent_dir, src_folder_name,
                dst_repo_id, dst_parent_dir, src_folder_name)

        seafile_api.del_file(src_repo_id, src_parent_dir, src_folder_name, username)

        return Response({'success': True})
Example #17
0
    def get(self, request, format=None):
        """ Only used for download dir when view dir share link from web.


        Permission checking:
        1. authenticated user OR anonymous user has passed email code check(if necessary);
        """

        # permission check
        if is_pro_version() and settings.ENABLE_SHARE_LINK_AUDIT:
            if not request.user.is_authenticated() and \
                not request.session.get('anonymous_email'):
                # if anonymous user has passed email code check,
                # then his/her email info will be in session.

                error_msg = 'Permission denied.'
                return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # argument check
        share_link_token = request.GET.get('share_link_token', None)
        if not share_link_token:
            error_msg = 'share_link_token invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        req_path = request.GET.get('path', None)
        if not req_path:
            error_msg = 'path invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # recourse check
        fileshare = FileShare.objects.get_valid_dir_link_by_token(
            share_link_token)
        if not fileshare:
            error_msg = 'share_link_token %s not found.' % share_link_token
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        if req_path[-1] != '/':
            req_path += '/'

        if req_path == '/':
            real_path = fileshare.path
        else:
            real_path = posixpath.join(fileshare.path, req_path.lstrip('/'))

        if real_path[-1] != '/':
            real_path += '/'

        repo_id = fileshare.repo_id
        repo = seafile_api.get_repo(repo_id)
        if not repo:
            error_msg = 'Library %s not found.' % repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        dir_id = seafile_api.get_dir_id_by_path(repo_id, real_path)
        if not dir_id:
            error_msg = 'Folder %s not found.' % real_path
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        if not seafile_api.check_permission_by_path(repo_id, '/',
                                                    fileshare.username):
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # get file server access token
        dir_name = repo.name if real_path == '/' else \
                os.path.basename(real_path.rstrip('/'))

        dir_size = seafile_api.get_dir_size(repo.store_id, repo.version,
                                            dir_id)
        if dir_size > seaserv.MAX_DOWNLOAD_DIR_SIZE:
            error_msg = _(
                'Unable to download directory "%s": size is too large.'
            ) % dir_name
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        try:
            seaserv.send_message(
                'seahub.stats', 'dir-download\t%s\t%s\t%s\t%s' %
                (repo_id, fileshare.username, dir_id, dir_size))
        except Exception as e:
            logger.error(e)

        is_windows = 0
        if is_windows_operating_system(request):
            is_windows = 1

        fake_obj_id = {
            'obj_id': dir_id,
            'dir_name': dir_name,
            'is_windows': is_windows
        }

        username = request.user.username
        try:
            zip_token = seafile_api.get_fileserver_access_token(
                repo_id,
                json.dumps(fake_obj_id),
                'download-dir',
                username,
                use_onetime=settings.FILESERVER_TOKEN_ONCE_ONLY)
        except Exception as e:
            logger.error(e)
            error_msg = 'Internal Server Error'
            return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        if not zip_token:
            error_msg = 'Internal Server Error'
            return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        if request.session.get('anonymous_email'):
            request.user.username = request.session.get('anonymous_email')

        send_file_access_msg(request, repo, real_path, 'share-link')

        return Response({'zip_token': zip_token})
Example #18
0
    def get(self, request, repo_id, format=None):
        """ Deprecated.

        Sometimes when user download too many files in one request,
        Nginx will return 414-Request-URI Too Large error.

        So, use the following POST request instead.
        Put all parameters in request body.
        """

        # argument check
        parent_dir = request.GET.get('parent_dir', None)
        if not parent_dir:
            error_msg = 'parent_dir invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        dirent_name_list = request.GET.getlist('dirents', None)
        if not dirent_name_list:
            error_msg = 'dirents invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        if len(dirent_name_list) == 1:
            download_type = 'download-dir'
        elif len(dirent_name_list) > 1:
            download_type = 'download-multi'
        else:
            error_msg = 'dirents invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # recourse check
        repo = seafile_api.get_repo(repo_id)
        if not repo:
            error_msg = 'Library %s not found.' % repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        if not seafile_api.get_dir_id_by_path(repo_id, parent_dir):
            error_msg = 'Folder %s not found.' % parent_dir
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # permission check
        repo_folder_permission = check_folder_permission(
            request, repo_id, parent_dir)
        if not repo_folder_permission:
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # get file server access token
        is_windows = 0
        if is_windows_operating_system(request):
            is_windows = 1

        if download_type == 'download-dir':
            dir_name = dirent_name_list[0].strip('/')
            full_dir_path = posixpath.join(parent_dir, dir_name)

            dir_id = seafile_api.get_dir_id_by_path(repo_id, full_dir_path)
            if not dir_id:
                error_msg = 'Folder %s not found.' % full_dir_path
                return api_error(status.HTTP_404_NOT_FOUND, error_msg)

            if not json.loads(seafile_api.is_dir_downloadable(repo_id, json.dumps([full_dir_path]), \
                    request.user.username, repo_folder_permission))['is_downloadable']:
                error_msg = 'Permission denied.'
                return api_error(status.HTTP_403_FORBIDDEN, error_msg)

            dir_size = seafile_api.get_dir_size(repo.store_id, repo.version,
                                                dir_id)

            if dir_size > seaserv.MAX_DOWNLOAD_DIR_SIZE:
                error_msg = _(
                    'Unable to download directory "%s": size is too large.'
                ) % dir_name
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

            fake_obj_id = {
                'obj_id': dir_id,
                'dir_name': dir_name,
                'is_windows': is_windows
            }

        if download_type == 'download-multi':
            dirent_list = []
            total_size = 0
            full_dirent_path_list = []
            for dirent_name in dirent_name_list:
                dirent_name = dirent_name.strip('/')
                dirent_list.append(dirent_name)

                full_dirent_path = posixpath.join(parent_dir, dirent_name)
                current_dirent = seafile_api.get_dirent_by_path(
                    repo_id, full_dirent_path)
                if not current_dirent:
                    continue

                if stat.S_ISDIR(current_dirent.mode):
                    total_size += seafile_api.get_dir_size(
                        repo.store_id, repo.version, current_dirent.obj_id)
                else:
                    total_size += current_dirent.size

                full_dirent_path_list.append(full_dirent_path)

            if not json.loads(seafile_api.is_dir_downloadable(repo_id, json.dumps(full_dirent_path_list), \
                    request.user.username, repo_folder_permission))['is_downloadable']:
                error_msg = 'Permission denied.'
                return api_error(status.HTTP_403_FORBIDDEN, error_msg)

            if total_size > seaserv.MAX_DOWNLOAD_DIR_SIZE:
                error_msg = _('Total size exceeds limit.')
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

            fake_obj_id = {
                'parent_dir': parent_dir,
                'file_list': dirent_list,
                'is_windows': is_windows
            }

        username = request.user.username
        try:
            zip_token = seafile_api.get_fileserver_access_token(
                repo_id,
                json.dumps(fake_obj_id),
                download_type,
                username,
                use_onetime=settings.FILESERVER_TOKEN_ONCE_ONLY)
        except Exception as e:
            logger.error(e)
            error_msg = 'Internal Server Error'
            return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        if not zip_token:
            error_msg = 'Internal Server Error'
            return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        if len(dirent_name_list) > 10:
            send_file_access_msg(request, repo, parent_dir, 'web')
        else:
            for dirent_name in dirent_name_list:
                full_dirent_path = posixpath.join(parent_dir, dirent_name)
                send_file_access_msg(request, repo, full_dirent_path, 'web')

        return Response({'zip_token': zip_token})
Example #19
0
    def get(self, request, token):
        """ Get FileServer download url of the shared file/dir.

        Permission checking:
        1. only admin can perform this action.
        """

        try:
            sharelink = FileShare.objects.get(token=token)
        except FileShare.DoesNotExist:
            error_msg = 'Share link %s not found.' % token
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        repo_id = sharelink.repo_id
        repo = seafile_api.get_repo(repo_id)
        if not repo:
            error_msg = 'Library not found.'
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        result = {}
        obj_path = sharelink.path
        if sharelink.s_type == 'f':
            # download shared file
            obj_id = seafile_api.get_file_id_by_path(repo_id, obj_path)
            if not obj_id:
                error_msg = 'File not found.'
                return api_error(status.HTTP_404_NOT_FOUND, error_msg)

            try:
                # `username` parameter only used for encrypted repo
                download_token = seafile_api.get_fileserver_access_token(
                    repo_id,
                    obj_id,
                    'download-link',
                    sharelink.username,
                    use_onetime=False)
            except Exception as e:
                logger.error(e)
                error_msg = 'Internal Server Error'
                return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR,
                                 error_msg)

            if not download_token:
                error_msg = 'Internal Server Error'
                return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR,
                                 error_msg)

            obj_name = os.path.basename(obj_path.rstrip('/'))
            result['download_link'] = gen_file_get_url(download_token,
                                                       obj_name)
        else:
            # download (sub) file/folder in shared dir
            obj_id = seafile_api.get_dir_id_by_path(repo_id, obj_path)
            if not obj_id:
                error_msg = 'Folder not found.'
                return api_error(status.HTTP_404_NOT_FOUND, error_msg)

            download_type = request.GET.get('type', None)
            if not download_type or download_type not in ('file', 'folder'):
                error_msg = 'type invalid.'
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

            req_path = request.GET.get('path', None)
            if not req_path:
                error_msg = 'path invalid.'
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

            if req_path == '/':
                real_path = obj_path
            else:
                real_path = posixpath.join(obj_path, req_path.strip('/'))

            if download_type == 'file':
                # download sub file in shared dir
                real_obj_id = seafile_api.get_file_id_by_path(
                    repo_id, real_path)
                if not real_obj_id:
                    error_msg = 'File not found.'
                    return api_error(status.HTTP_404_NOT_FOUND, error_msg)

                try:
                    download_token = seafile_api.get_fileserver_access_token(
                        repo_id,
                        real_obj_id,
                        'download-link',
                        sharelink.username,
                        use_onetime=False)
                except Exception as e:
                    logger.error(e)
                    error_msg = 'Internal Server Error'
                    return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR,
                                     error_msg)

                if not download_token:
                    error_msg = 'Internal Server Error'
                    return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR,
                                     error_msg)

                file_name = os.path.basename(real_path.rstrip('/'))
                result['download_link'] = gen_file_get_url(
                    download_token, file_name)
            else:
                # download sub folder in shared dir
                if real_path[-1] != '/':
                    real_path += '/'

                real_obj_id = seafile_api.get_dir_id_by_path(
                    repo_id, real_path)
                if not real_obj_id:
                    error_msg = 'Folder %s not found.' % req_path
                    return api_error(status.HTTP_404_NOT_FOUND, error_msg)

                dir_name = repo.name if real_path == '/' else \
                        os.path.basename(real_path.rstrip('/'))

                dir_size = seafile_api.get_dir_size(repo.store_id,
                                                    repo.version, real_obj_id)
                if dir_size > seaserv.MAX_DOWNLOAD_DIR_SIZE:
                    error_msg = 'Unable to download directory "%s": size is too large.' % dir_name
                    return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

                # get file server access token
                is_windows = 0
                if is_windows_operating_system(request):
                    is_windows = 1

                fake_obj_id = {
                    'obj_id': real_obj_id,
                    'dir_name': dir_name,
                    'is_windows': is_windows
                }

                try:
                    zip_token = seafile_api.get_fileserver_access_token(
                        repo_id,
                        json.dumps(fake_obj_id),
                        'download-dir-link',
                        sharelink.username,
                        use_onetime=False)
                except Exception as e:
                    logger.error(e)
                    error_msg = 'Internal Server Error'
                    return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR,
                                     error_msg)

                result['download_link'] = gen_dir_zip_download_url(zip_token)

        return Response(result)
Example #20
0
    def post(self, request):
        """ Multi copy folders.

        Permission checking:
        1. User must has `r/rw` permission for src folder.
        2. User must has `rw` permission for dst folder.

        Parameter:
        {
            "src_repo_id":"7460f7ac-a0ff-4585-8906-bb5a57d2e118",
            "dst_repo_id":"a3fa768d-0f00-4343-8b8d-07b4077881db",
            "paths":[
                {"src_path":"/1/2/3/","dst_path":"/4/5/6/"},
                {"src_path":"/a/b/c/","dst_path":"/d/e/f/"},
            ]
        }
        """

        # argument check
        path_list = request.data.get('paths', None)
        if not path_list:
            error_msg = 'paths invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        src_repo_id = request.data.get('src_repo_id', None)
        if not src_repo_id:
            error_msg = 'src_repo_id invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        dst_repo_id = request.data.get('dst_repo_id', None)
        if not dst_repo_id:
            error_msg = 'dst_repo_id invalid.'
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # permission check, user must has `r/rw` permission for src repo.
        if check_folder_permission(request, src_repo_id, '/') is None:
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # permission check, user must has `rw` permission for dst repo.
        if check_folder_permission(request, dst_repo_id, '/') != 'rw':
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        # resource check
        src_repo = seafile_api.get_repo(src_repo_id)
        if not src_repo:
            error_msg = 'Library %s not found.' % src_repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        dst_repo = seafile_api.get_repo(dst_repo_id)
        if not dst_repo:
            error_msg = 'Library %s not found.' % dst_repo_id
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # get total size of file/dir to be copied
        total_size = 0
        for path_item in path_list:
            src_path = path_item['src_path']
            src_path = normalize_dir_path(src_path)

            current_size = 0
            current_dir_id = seafile_api.get_dir_id_by_path(src_repo_id,
                    src_path)
            current_size = seafile_api.get_dir_size(src_repo.store_id,
                    src_repo.version, current_dir_id)

            total_size += current_size

        # check if above quota for dst repo
        if seafile_api.check_quota(dst_repo_id, total_size) < 0:
            return api_error(HTTP_443_ABOVE_QUOTA,  _(u"Out of quota."))

        result = {}
        result['failed'] = []
        result['success'] = []
        username = request.user.username

        for path_item in path_list:

            src_path = path_item['src_path']
            src_path = normalize_dir_path(src_path)
            src_parent_dir = os.path.dirname(src_path.rstrip('/'))
            src_parent_dir = normalize_dir_path(src_parent_dir)
            src_obj_name = os.path.basename(src_path.rstrip('/'))

            dst_path = path_item['dst_path']
            dst_path = normalize_dir_path(dst_path)
            dst_parent_dir = dst_path
            dst_obj_name = src_obj_name

            common_dict = {
                'src_repo_id': src_repo_id,
                'src_path': src_path,
                'dst_repo_id': dst_repo_id,
                'dst_path': dst_path,
            }

            # src/dst parameter check
            if src_repo_id == dst_repo_id and \
                    dst_path.startswith(src_path):
                error_dict = {
                    'error_msg': "The destination directory is the same as the source, or is it's subfolder."
                }
                common_dict.update(error_dict)
                result['failed'].append(common_dict)
                continue

            if src_path == '/':
                error_dict = {
                    'error_msg': "The source path can not be '/'."
                }
                common_dict.update(error_dict)
                result['failed'].append(common_dict)
                continue

            if len(dst_parent_dir + dst_obj_name) > MAX_PATH:
                error_dict = {
                    'error_msg': "'Destination path is too long."
                }
                common_dict.update(error_dict)
                result['failed'].append(common_dict)
                continue

            # src resource check
            if not seafile_api.get_dir_id_by_path(src_repo_id, src_path):
                error_dict = {
                    'error_msg': 'Folder %s not found.' % src_path
                }
                common_dict.update(error_dict)
                result['failed'].append(common_dict)
                continue

            # dst resource check
            if not seafile_api.get_dir_id_by_path(dst_repo_id, dst_path):
                error_dict = {
                    'error_msg': 'Folder %s not found.' % dst_path
                }
                common_dict.update(error_dict)
                result['failed'].append(common_dict)
                continue

            # src path permission check, user must has `r/rw` permission for src folder.
            if check_folder_permission(request, src_repo_id, src_parent_dir) is None:
                error_dict = {
                    'error_msg': 'Permission denied.'
                }
                common_dict.update(error_dict)
                result['failed'].append(common_dict)
                continue

            # dst path permission check, user must has `rw` permission for dst folder.
            if check_folder_permission(request, dst_repo_id, dst_path) != 'rw':
                error_dict = {
                    'error_msg': 'Permission denied.'
                }
                common_dict.update(error_dict)
                result['failed'].append(common_dict)
                continue

            try:
                # need_progress=0, synchronous=1
                seafile_api.copy_file(src_repo_id, src_parent_dir, src_obj_name,
                        dst_repo_id, dst_parent_dir, dst_obj_name, username, 0, 1)
            except Exception as e:
                logger.error(e)
                error_dict = {
                    'error_msg': 'Internal Server Error'
                }
                common_dict.update(error_dict)
                result['failed'].append(common_dict)
                continue

            result['success'].append(common_dict)

        return Response(result)