def generate_file_lock_key_value(request): 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'] repo = seafile_api.get_repo(repo_id) if repo.is_virtual: origin_repo_id = repo.origin_repo_id origin_file_path = posixpath.join(repo.origin_path, file_path.strip('/')) file_path_hash = hashlib.sha256( origin_file_path.encode('utf8')).hexdigest() lock_cache_key = '_'.join( ['HTTP_X_WOPI_LOCK', origin_repo_id, file_path_hash]) else: file_path_hash = hashlib.sha256(file_path.encode('utf8')).hexdigest() lock_cache_key = '_'.join( ['HTTP_X_WOPI_LOCK', repo_id, file_path_hash]) x_wopi_lock = request.META.get('HTTP_X_WOPI_LOCK', None) return lock_cache_key, x_wopi_lock
def file_is_locked(request): 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'] return if_locked_by_online_office(repo_id, file_path)
def _decorated(view, request, file_id, *args, **kwargs): token = request.GET.get('access_token', None) if not token: logger.error('access_token invalid.') return HttpResponse(json.dumps({}), status=401, content_type=json_content_type) info_dict = get_file_info_by_token(token) if not info_dict: logger.error('Get wopi cache value failed: wopi_access_token_%s.' % token) return HttpResponse(json.dumps({}), status=404, content_type=json_content_type) request_user = info_dict['request_user'] repo_id = info_dict['repo_id'] file_path = info_dict['file_path'] obj_id = info_dict['obj_id'] if not request_user or not repo_id or not file_path: logger.error( 'File info invalid, user: %s, repo_id: %s, path: %s.' % (request_user, repo_id, file_path)) return HttpResponse(json.dumps({}), status=404, content_type=json_content_type) if request_user != ANONYMOUS_EMAIL: try: User.objects.get(email=request_user) except User.DoesNotExist: logger.error('User %s not found.' % request_user) return HttpResponse(json.dumps({}), status=404, content_type=json_content_type) repo = seafile_api.get_repo(repo_id) if not repo: logger.error('Library %s not found.' % repo_id) return HttpResponse(json.dumps({}), status=404, content_type=json_content_type) if not obj_id: # if not cache file obj_id, then get it from seafile_api obj_id = seafile_api.get_file_id_by_path(repo_id, file_path) if not obj_id: logger.error('File %s not found.' % file_path) return HttpResponse(json.dumps({}), status=404, content_type=json_content_type) return func(view, request, file_id, *args, **kwargs)
def unlock_file(request): key, value = generate_file_lock_key_value(request) cache.delete(key) 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.unlock_file(repo_id, file_path)
def refresh_file_lock(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.refresh_file_lock(repo_id, file_path, int(time.time()) + 40 * 60)
def lock_file(request): key, value = generate_file_lock_key_value(request) cache.set(key, value, WOPI_LOCK_EXPIRATION) if is_pro_version(): 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)
def file_is_locked(request): if not is_pro_version(): key, value = generate_file_lock_key_value(request) return True if cache.get(key, '') else False 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'] return if_locked_by_online_office(repo_id, file_path)
def get(self, request, file_id, format=None): """ WOPI endpoint for get file content """ 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'] obj_id = info_dict['obj_id'] if not obj_id: # if not cache file obj_id, then get it from seafile_api obj_id = seafile_api.get_file_id_by_path(repo_id, file_path) file_name = os.path.basename(file_path) try: fileserver_token = seafile_api.get_fileserver_access_token( repo_id, obj_id, 'view', '', use_onetime=False) except SearpcError as e: logger.error(e) return HttpResponse(json.dumps({}), status=500, content_type=json_content_type) if not fileserver_token: return HttpResponse(json.dumps({}), status=500, content_type=json_content_type) inner_path = gen_inner_file_get_url(fileserver_token, file_name) try: file_content = urllib.request.urlopen(inner_path).read() except urllib.error.URLError as e: logger.error(e) return HttpResponse(json.dumps({}), status=500, content_type=json_content_type) return HttpResponse(file_content, content_type="application/octet-stream")
def post(self, request, file_id, format=None): token = request.GET.get('access_token', None) info_dict = get_file_info_by_token(token) request_user = info_dict['request_user'] repo_id = info_dict['repo_id'] file_path = info_dict['file_path'] try: file_obj = request.read() # get file update url fake_obj_id = { 'online_office_update': True, } token = seafile_api.get_fileserver_access_token( repo_id, json.dumps(fake_obj_id), 'update', request_user) if not token: return HttpResponse(json.dumps({}), status=500, content_type=json_content_type) update_url = gen_inner_file_upload_url('update-api', token) # update file files = { 'file': file_obj, 'file_name': os.path.basename(file_path), 'target_file': file_path, } requests.post(update_url, files=files) except Exception as e: logger.error(e) return HttpResponse(json.dumps({}), status=500, content_type=json_content_type) return HttpResponse(json.dumps({}), status=200, content_type=json_content_type)
def post(self, request, file_id, format=None): token = request.GET.get('access_token', None) info_dict = get_file_info_by_token(token) request_user = info_dict['request_user'] repo_id = info_dict['repo_id'] file_path = info_dict['file_path'] try: file_obj = request.read() # get file update url fake_obj_id = {'online_office_update': True} token = seafile_api.get_fileserver_access_token(repo_id, json.dumps(fake_obj_id), 'update', request_user) if not token: return HttpResponse(json.dumps({}), status=500, content_type=json_content_type) update_url = gen_inner_file_upload_url('update-api', token) # update file files = {'file': (os.path.basename(file_path), file_obj)} data = {'target_file': file_path} resp = requests.post(update_url, files=files, data=data) if resp.status_code != 200: logger.error('update_url: {}'.format(update_url)) logger.error('parameter file: {}'.format(files['file'][:100])) logger.error('parameter file_name: {}'.format(files['file_name'])) logger.error('parameter target_file: {}'.format(files['target_file'])) logger.error('response: {}'.format(resp.__dict__)) except Exception as e: logger.error(e) return HttpResponse(json.dumps({}), status=500, content_type=json_content_type) return HttpResponse(json.dumps({}), status=200, content_type=json_content_type)
def get(self, request, file_id, format=None): """ WOPI endpoint for check file info """ token = request.GET.get('access_token', None) info_dict = get_file_info_by_token(token) request_user = info_dict['request_user'] repo_id = info_dict['repo_id'] file_path = info_dict['file_path'] obj_id = info_dict['obj_id'] can_edit = info_dict['can_edit'] can_download = info_dict['can_download'] repo = seafile_api.get_repo(repo_id) if not obj_id: # if not cache file obj_id, then get it from seafile_api obj_id = seafile_api.get_file_id_by_path(repo_id, file_path) try: file_size = seafile_api.get_file_size(repo.store_id, repo.version, obj_id) except SearpcError as e: logger.error(e) return HttpResponse(json.dumps({}), status=500, content_type=json_content_type) if file_size == -1: logger.error('File %s not found.' % file_path) return HttpResponse(json.dumps({}), status=401, content_type=json_content_type) result = {} # necessary result['BaseFileName'] = os.path.basename(file_path) result['Size'] = file_size result['UserId'] = request_user result['Version'] = obj_id result['LastModifiedTime'] = '' try: if is_pro_version(): result['OwnerId'] = seafile_api.get_repo_owner(repo_id) or \ seafile_api.get_org_repo_owner(repo_id) else: result['OwnerId'] = seafile_api.get_repo_owner(repo_id) dirent = seafile_api.get_dirent_by_path(repo_id, file_path) if dirent: last_modified = datetime.datetime.utcfromtimestamp( dirent.mtime) result['LastModifiedTime'] = last_modified.isoformat() except Exception as e: logger.error(e) return HttpResponse(json.dumps({}), status=500, content_type=json_content_type) # optional if request_user != ANONYMOUS_EMAIL: result['UserFriendlyName'] = email2nickname(request_user) result['IsAnonymousUser'] = False else: result['IsAnonymousUser'] = True absolute_uri = request.build_absolute_uri('/') result['PostMessageOrigin'] = urllib.parse.urljoin( absolute_uri, SITE_ROOT).strip('/') result['HideSaveOption'] = True result['HideExportOption'] = True result['EnableOwnerTermination'] = True result['SupportsLocks'] = True result['SupportsGetLock'] = True result['DisablePrint'] = True if not can_download else False result['HidePrintOption'] = True if not can_download else False result['SupportsUpdate'] = True if can_edit else False result['UserCanWrite'] = True if can_edit else False result['ReadOnly'] = True if not can_edit else False # new file creation feature is not implemented on wopi host(seahub) # hide save as button on view/edit file page result['UserCanNotWriteRelative'] = True return HttpResponse(json.dumps(result), status=200, content_type=json_content_type)