Esempio n. 1
0
    def test_can_unlock_file(self):

        if not LOCAL_PRO_DEV_ENV:
            return

        self.login_as(self.user)

        # lock file for test
        seafile_api.lock_file(self.repo_id, self.file_path.lstrip('/'),
                              self.user.username, -1)

        # check file has been locked when init
        return_value = seafile_api.check_file_lock(self.repo_id,
                                                   self.file_path.lstrip('/'),
                                                   self.user.username)
        assert return_value == 2

        # unlock file
        data = 'operation=unlock'
        resp = self.client.put(self.url + '?p=' + self.file_path, data,
                               'application/x-www-form-urlencoded')

        self.assertEqual(200, resp.status_code)

        # check file has been unlocked
        return_value = seafile_api.check_file_lock(self.repo_id,
                                                   self.file_path.lstrip('/'),
                                                   self.user.username)
        assert return_value == 0
Esempio n. 2
0
    def test_can_get_file_with_lock_info(self):

        if not LOCAL_PRO_DEV_ENV:
            return

        self.login_as(self.user)

        # no lock owner info returned
        resp = self.client.get(self.url + '?t=f')
        self.assertEqual(200, resp.status_code)
        json_resp = json.loads(resp.content)
        assert len(json_resp['dirent_list']) == 1
        assert json_resp['dirent_list'][0]['type'] == 'file'
        assert json_resp['dirent_list'][0]['name'] == self.file_name
        assert json_resp['dirent_list'][0]['lock_owner'] == ''

        # lock file
        seafile_api.lock_file(self.repo_id, self.file_path, self.admin_name, 1)

        # return lock owner info
        resp = self.client.get(self.url + '?t=f')
        self.assertEqual(200, resp.status_code)
        json_resp = json.loads(resp.content)
        assert len(json_resp['dirent_list']) == 1
        assert json_resp['dirent_list'][0]['type'] == 'file'
        assert json_resp['dirent_list'][0]['name'] == self.file_name
        assert json_resp['dirent_list'][0]['lock_owner'] == self.admin_name
Esempio n. 3
0
    def test_can_unlock_file(self):

        if not LOCAL_PRO_DEV_ENV:
            return

        self.login_as(self.user)

        # lock file for test
        seafile_api.lock_file(self.repo_id, self.file_path.lstrip('/'),
                self.user.username, -1)

        # check file has been locked when init
        return_value = seafile_api.check_file_lock(self.repo_id,
            self.file_path.lstrip('/'), self.user.username)
        assert return_value == 2

        # unlock file
        data = 'operation=unlock'
        resp = self.client.put(self.url + '?p=' + self.file_path, data, 'application/x-www-form-urlencoded')

        self.assertEqual(200, resp.status_code)

        # check file has been unlocked
        return_value = seafile_api.check_file_lock(self.repo_id,
            self.file_path.lstrip('/'), self.user.username)
        assert return_value == 0
Esempio n. 4
0
    def put(self, request, repo_id, format=None):
        """ Currently only for lock and unlock file operation.

        Permission checking:
        1. user with 'rw' permission for current file;
        """

        if not is_pro_version():
            error_msg = 'file lock feature only supported in professional edition.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

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

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

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

        # resource 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)

        file_id = seafile_api.get_file_id_by_path(repo_id, path)
        if not file_id:
            error_msg = 'File %s not found.' % path
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # permission check
        parent_dir = os.path.dirname(path)
        if check_folder_permission(request, repo_id, parent_dir) != 'rw':
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        username = request.user.username
        is_locked, locked_by_me = check_file_lock(repo_id, path, username)
        if operation == 'lock':
            if not is_locked:
                # lock file
                expire = request.data.get('expire', FILE_LOCK_EXPIRATION_DAYS)
                try:
                    seafile_api.lock_file(repo_id, path.lstrip('/'), username,
                                          expire)
                except SearpcError, e:
                    logger.error(e)
                    error_msg = 'Internal Server Error'
                    return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR,
                                     error_msg)
Esempio n. 5
0
    def put(self, request, repo_id, format=None):
        """ Currently only for lock and unlock file operation.

        Permission checking:
        1. user with 'rw' permission for current file;
        """

        if not is_pro_version():
            error_msg = 'file lock feature only supported in professional edition.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

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

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

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

        # resource 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)

        file_id = seafile_api.get_file_id_by_path(repo_id, path)
        if not file_id:
            error_msg = 'File %s not found.' % path
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # permission check
        parent_dir = os.path.dirname(path)
        if check_folder_permission(request, repo_id, parent_dir) != 'rw':
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        username = request.user.username
        is_locked, locked_by_me = check_file_lock(repo_id, path, username)
        if operation == 'lock':
            if not is_locked:
                # lock file
                expire = request.data.get('expire', FILE_LOCK_EXPIRATION_DAYS)
                try:
                    seafile_api.lock_file(repo_id, path.lstrip('/'), username, expire)
                except SearpcError, e:
                    logger.error(e)
                    error_msg = 'Internal Server Error'
                    return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
Esempio n. 6
0
def lock_file(request):

    key, value = generate_file_lock_key_value(request)
    cache.set(key, value, WOPI_LOCK_EXPIRATION)

    token = request.GET.get('access_token', None)
    info_dict = get_file_info_by_token(token)
    repo_id = info_dict['repo_id']
    file_path = info_dict['file_path']
    seafile_api.lock_file(repo_id, file_path, ONLINE_OFFICE_LOCK_OWNER,
                          int(time.time()) + 40 * 60)
Esempio n. 7
0
    def put(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)

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

        file_id = seafile_api.get_file_id_by_path(repo_id, path)
        if not file_id:
            error_msg = 'File %s not found.' % path
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        if check_folder_permission(request, repo_id, path) != 'rw':
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        username = request.user.username
        operation = request.data.get('operation', '')
        if operation.lower() == 'lock':
            is_locked, locked_by_me = check_file_lock(repo_id, path, username)
            if is_locked:
                error_msg = 'File is already locked.'
                return api_error(status.HTTP_403_FORBIDDEN, error_msg)

            # lock file
            expire = request.data.get('expire', FILE_LOCK_EXPIRATION_DAYS)
            try:
                seafile_api.lock_file(repo_id, path.lstrip('/'), username,
                                      expire)
                return Response({'success': True})
            except SearpcError, e:
                logger.error(e)
                error_msg = 'Internal Server Error'
                return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR,
                                 error_msg)
Esempio n. 8
0
    def put(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)

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

        file_id = seafile_api.get_file_id_by_path(repo_id, path)
        if not file_id:
            error_msg = 'File %s not found.' % path
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        if check_folder_permission(request, repo_id, path) != 'rw':
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        username = request.user.username
        operation = request.data.get('operation', '')
        if operation.lower() == 'lock':
            is_locked, locked_by_me = check_file_lock(repo_id, path, username)
            if is_locked:
                error_msg = 'File is already locked.'
                return api_error(status.HTTP_403_FORBIDDEN, error_msg)

            # lock file
            expire = request.data.get('expire', FILE_LOCK_EXPIRATION_DAYS)
            try:
                seafile_api.lock_file(repo_id, path.lstrip('/'), username, expire)
                return Response({'success': True})
            except SearpcError, e:
                logger.error(e)
                error_msg = 'Internal Server Error'
                return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
Esempio n. 9
0
    def put(self, request, repo_id, format=None):
        """ Currently only support lock, unlock, refresh-lock file.

        Permission checking:
        1. user with 'rw' permission for current file;
        """

        if not is_pro_version():
            error_msg = 'file lock feature only supported in professional edition.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

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

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

        operation = operation.lower()
        if operation not in ('lock', 'unlock', 'refresh-lock'):
            error_msg = "operation can only be 'lock', 'unlock' or 'refresh-lock'."
            return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

        # resource 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)

        file_id = seafile_api.get_file_id_by_path(repo_id, path)
        if not file_id:
            error_msg = 'File %s not found.' % path
            return api_error(status.HTTP_404_NOT_FOUND, error_msg)

        # permission check
        parent_dir = os.path.dirname(path)
        if check_folder_permission(request, repo_id, parent_dir) != PERMISSION_READ_WRITE:
            error_msg = 'Permission denied.'
            return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        username = request.user.username
        try:
            is_locked, locked_by_me = check_file_lock(repo_id, 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)

        # check if is locked by online office
        locked_by_online_office = if_locked_by_online_office(repo_id, path)

        if operation == 'lock':

            if is_locked:
                error_msg = _("File is locked")
                return api_error(status.HTTP_400_BAD_REQUEST, error_msg)

            # lock file
            expire = request.data.get('expire', FILE_LOCK_EXPIRATION_DAYS)
            try:
                seafile_api.lock_file(repo_id, path, username, expire)
            except SearpcError as e:
                logger.error(e)
                error_msg = 'Internal Server Error'
                return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)

        if operation == 'unlock':

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

            if locked_by_me or locked_by_online_office:
                # unlock file
                try:
                    seafile_api.unlock_file(repo_id, path)
                except SearpcError as e:
                    logger.error(e)
                    error_msg = 'Internal Server Error'
                    return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
            else:
                error_msg = 'You can not unlock this file.'
                return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        if operation == 'refresh-lock':

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

            if locked_by_me or locked_by_online_office:
                # refresh lock file
                try:
                    seafile_api.refresh_file_lock(repo_id, path)
                except SearpcError as e:
                    logger.error(e)
                    error_msg = 'Internal Server Error'
                    return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
            else:
                error_msg = _("You can not refresh this file's lock.")
                return api_error(status.HTTP_403_FORBIDDEN, error_msg)

        file_info = self.get_file_info(username, repo_id, path)
        return Response(file_info)
Esempio n. 10
0
def onlyoffice_editor_callback(request):
    """ Callback func of OnlyOffice.

    The document editing service informs the document storage service about status of the document editing using the callbackUrl from JavaScript API. The document editing service use the POST request with the information in body.

    https://api.onlyoffice.com/editors/callback
    """

    if request.method != 'POST':
        logger.error('Request method if not POST.')
        # The document storage service must return the following response.
        # otherwise the document editor will display an error message.
        return HttpResponse('{"error": 0}')

    #### body info of POST rquest when open file on browser
    # {u'actions': [{u'type': 1, u'userid': u'uid-1527736776860'}],
    #  u'key': u'8062bdccf9b4cf809ae3',
    #  u'status': 1,
    #  u'users': [u'uid-1527736776860']}

    #### body info of POST rquest when close file's web page (save file)
    # {u'actions': [{u'type': 0, u'userid': u'uid-1527736951523'}],
    # u'changesurl': u'...',
    # u'history': {u'changes': [{u'created': u'2018-05-31 03:17:17',
    #                            u'user': {u'id': u'uid-1527736577058',
    #                                      u'name': u'lian'}},
    #                           {u'created': u'2018-05-31 03:23:55',
    #                            u'user': {u'id': u'uid-1527736951523',
    #                                      u'name': u'lian'}}],
    #              u'serverVersion': u'5.1.4'},
    # u'key': u'61484dec693009f3d506',
    # u'lastsave': u'2018-05-31T03:23:55.767Z',
    # u'notmodified': False,
    # u'status': 2,
    # u'url': u'...',
    # u'users': [u'uid-1527736951523']}

    # Defines the status of the document. Can have the following values:
    # 0 - no document with the key identifier could be found,
    # 1 - document is being edited,
    # 2 - document is ready for saving,
    # 3 - document saving error has occurred,
    # 4 - document is closed with no changes,
    # 6 - document is being edited, but the current document state is saved,
    # 7 - error has occurred while force saving the document.

    # Status 1 is received every user connection to or disconnection from document co-editing.
    #
    # Status 2 (3) is received 10 seconds after the document is closed for editing with the identifier of the user who was the last to send the changes to the document editing service.
    #
    # Status 4 is received after the document is closed for editing with no changes by the last user.
    #
    # Status 6 (7) is received when the force saving request is performed.

    post_data = json.loads(request.body)
    status = int(post_data.get('status', -1))

    # When forcesave is initiated, document editing service performs request to
    # the callback handler with the link to the document as the url parameter and
    # with the 6 value for the status parameter.
    if status in (2, 6):

        # Defines the link to the edited document to be saved with the document storage service.
        # The link is present when the status value is equal to 2 or 3 only.
        url = post_data.get('url')
        onlyoffice_resp = requests.get(url,
                                       verify=VERIFY_ONLYOFFICE_CERTIFICATE)
        if not onlyoffice_resp:
            logger.error('[OnlyOffice] No response from file content url.')
            return HttpResponse('{"error": 0}')

        # get file basic info
        doc_key = post_data.get('key')
        doc_info = json.loads(cache.get("ONLYOFFICE_%s" % doc_key))

        repo_id = doc_info['repo_id']
        file_path = doc_info['file_path']
        username = doc_info['username']

        cache_key = generate_onlyoffice_cache_key(repo_id, file_path)
        # cache document key when forcesave
        if status == 6:
            cache.set(cache_key, doc_key)

        # remove document key from cache when document is ready for saving
        # no one is editting
        if status == 2:
            if if_locked_by_online_office(repo_id, file_path):
                seafile_api.unlock_file(repo_id, file_path)
                cache.delete(cache_key)
                cache.delete("ONLYOFFICE_%s" % doc_key)

        fake_obj_id = {
            'online_office_update': True,
        }
        update_token = seafile_api.get_fileserver_access_token(
            repo_id, json.dumps(fake_obj_id), 'update', username)

        if not update_token:
            logger.error('[OnlyOffice] No fileserver access token.')
            return HttpResponse('{"error": 0}')

        # get file content
        files = {
            'file': onlyoffice_resp.content,
            'file_name': os.path.basename(file_path),
            'target_file': file_path,
        }

        # update file
        update_url = gen_inner_file_upload_url('update-api', update_token)
        requests.post(update_url, files=files)

    if status == 4:
        doc_key = post_data.get('key')
        doc_info = json.loads(cache.get("ONLYOFFICE_%s" % doc_key))

        repo_id = doc_info['repo_id']
        file_path = doc_info['file_path']

        cache_key = generate_onlyoffice_cache_key(repo_id, file_path)

        if if_locked_by_online_office(repo_id, file_path):
            seafile_api.unlock_file(repo_id, file_path)
            cache.delete(cache_key)

    if status == 1:
        connected_users = post_data.get('users')
        if len(connected_users) > 0:
            doc_key = post_data.get('key')
            doc_info = json.loads(cache.get("ONLYOFFICE_%s" % doc_key))
            repo_id = doc_info['repo_id']
            file_path = doc_info['file_path']
            cache_key = generate_onlyoffice_cache_key(repo_id, file_path)
            if not if_locked_by_online_office(repo_id, file_path):
                seafile_api.lock_file(repo_id, file_path,
                                      ONLINE_OFFICE_LOCK_OWNER, 0)
                cache.set(cache_key, doc_key)

    return HttpResponse('{"error": 0}')