mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-24 12:58:34 +00:00
move to seafevents process
This commit is contained in:
41
frontend/src/components/dialog/import-wiki-page-dialog.js
Normal file
41
frontend/src/components/dialog/import-wiki-page-dialog.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Modal, ModalBody } from 'reactstrap';
|
||||||
|
import { gettext } from '../../utils/constants';
|
||||||
|
import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
||||||
|
import Loading from '../loading';
|
||||||
|
|
||||||
|
import '../../css/seahub-io-dialog.css';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
toggleDialog: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ImportWikiPageDialog extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggle = () => {
|
||||||
|
this.props.toggleDialog();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Modal className='seahub-io-dialog' isOpen={true} toggle={this.toggle}>
|
||||||
|
<SeahubModalHeader toggle={this.toggle}>{gettext('Import page')}</SeahubModalHeader>
|
||||||
|
<ModalBody>
|
||||||
|
<>
|
||||||
|
<Loading/>
|
||||||
|
<div className="seahub-io-dialog-parsing-text">{gettext('Importing page...')}</div>
|
||||||
|
</>
|
||||||
|
</ModalBody>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportWikiPageDialog.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default ImportWikiPageDialog;
|
@@ -17,7 +17,8 @@ import { DEFAULT_PAGE_NAME } from './constant';
|
|||||||
import Wiki2Search from '../../components/search/wiki2-search';
|
import Wiki2Search from '../../components/search/wiki2-search';
|
||||||
import CommonUndoTool from '../../components/common/common-undo-tool';
|
import CommonUndoTool from '../../components/common/common-undo-tool';
|
||||||
import PublishedWikiExtrance from '../../components/published-wiki-entrance';
|
import PublishedWikiExtrance from '../../components/published-wiki-entrance';
|
||||||
|
import { userAPI } from '../../utils/user-api';
|
||||||
|
import ImportWikiPageDialog from '../../components/dialog/import-wiki-page-dialog';
|
||||||
import './side-panel.css';
|
import './side-panel.css';
|
||||||
|
|
||||||
const { repoName, publishUrl } = window.wiki.config;
|
const { repoName, publishUrl } = window.wiki.config;
|
||||||
@@ -107,13 +108,51 @@ class SidePanel extends PureComponent {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
queryImportPageStatus = (task_id, task_type, new_page) => {
|
||||||
|
userAPI.queryIOStatus(task_id, task_type).then(res => {
|
||||||
|
if (res.data.is_finished === true) {
|
||||||
|
toaster.success('Import page success.');
|
||||||
|
this.setState({
|
||||||
|
isShowImportPageDialog: false
|
||||||
|
});
|
||||||
|
this.addPage(new_page, '', null, null, true);
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.queryImportPageStatus(task_id, task_type, new_page);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
this.setState({
|
||||||
|
isShowImportPageDialog: false
|
||||||
|
});
|
||||||
|
toaster.danger(gettext('Failed to import page. '));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
importPage = async (fromPageConfig, successCallback, errorCallback, jumpToNewPage = true) => {
|
importPage = async (fromPageConfig, successCallback, errorCallback, jumpToNewPage = true) => {
|
||||||
const { from_page_id, file } = fromPageConfig;
|
const { from_page_id, file } = fromPageConfig;
|
||||||
|
let newPage;
|
||||||
|
let task_id = ''
|
||||||
|
this.setState({
|
||||||
|
isShowImportPageDialog: true
|
||||||
|
})
|
||||||
wikiAPI.importWiki2Page(wikiId, from_page_id, file).then(res => {
|
wikiAPI.importWiki2Page(wikiId, from_page_id, file).then(res => {
|
||||||
const { page_id, name, path, docUuid } = res.data;
|
const { page_id, name, path, docUuid } = res.data;
|
||||||
const newPage = new Page({ id: page_id, name, icon: '', path, docUuid });
|
task_id = res.data.task_id;
|
||||||
this.addPage(newPage, '', successCallback, errorCallback, jumpToNewPage);
|
newPage = new Page({ id: page_id, name, icon: '', path, docUuid });
|
||||||
successCallback && successCallback();
|
this.setState({
|
||||||
|
taskId: task_id
|
||||||
|
});
|
||||||
|
return userAPI.queryIOStatus(task_id, 'import');
|
||||||
|
}).then(res => {
|
||||||
|
if (res.data.is_finished === true) {
|
||||||
|
this.setState({
|
||||||
|
isShowImportPageDialog: false
|
||||||
|
});
|
||||||
|
this.addPage(newPage, '', successCallback, errorCallback, jumpToNewPage);
|
||||||
|
} else {
|
||||||
|
this.queryImportPageStatus(task_id, 'import', newPage);
|
||||||
|
}
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
let errMessage = Utils.getErrorMsg(error);
|
let errMessage = Utils.getErrorMsg(error);
|
||||||
toaster.danger(errMessage);
|
toaster.danger(errMessage);
|
||||||
@@ -159,6 +198,10 @@ class SidePanel extends PureComponent {
|
|||||||
this.setState({ isShowTrashDialog: !this.state.isShowTrashDialog });
|
this.setState({ isShowTrashDialog: !this.state.isShowTrashDialog });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
toggleImportPageDialog = () => {
|
||||||
|
this.setState({ isShowImportPageDialog: !this.state.isShowImportPageDialog })
|
||||||
|
}
|
||||||
|
|
||||||
renderWikiNav = () => {
|
renderWikiNav = () => {
|
||||||
const { config, onUpdatePage } = this.props;
|
const { config, onUpdatePage } = this.props;
|
||||||
const { pages, navigation } = config;
|
const { pages, navigation } = config;
|
||||||
@@ -262,6 +305,11 @@ class SidePanel extends PureComponent {
|
|||||||
getWikiConfig={this.props.getWikiConfig}
|
getWikiConfig={this.props.getWikiConfig}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{this.state.isShowImportPageDialog && (
|
||||||
|
<ImportWikiPageDialog
|
||||||
|
toggleDialog={this.toggleImportPageDialog}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{wikiPermission === 'rw' &&
|
{wikiPermission === 'rw' &&
|
||||||
<WikiExternalOperations onAddWikiPage={this.onAddWikiPage.bind(false)} />
|
<WikiExternalOperations onAddWikiPage={this.onAddWikiPage.bind(false)} />
|
||||||
}
|
}
|
||||||
|
@@ -250,7 +250,7 @@ class WikiAPI {
|
|||||||
importWiki2Page(wikiId, pageId, file) {
|
importWiki2Page(wikiId, pageId, file) {
|
||||||
const url = this.server + '/api/v2.1/wiki2/' + wikiId + '/import-page/';
|
const url = this.server + '/api/v2.1/wiki2/' + wikiId + '/import-page/';
|
||||||
let form = new FormData();
|
let form = new FormData();
|
||||||
form.append('page_id', pageId);
|
form.append('from_page_id', pageId);
|
||||||
if (file) {
|
if (file) {
|
||||||
form.append('file', file);
|
form.append('file', file);
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,6 @@ import posixpath
|
|||||||
import datetime
|
import datetime
|
||||||
import uuid
|
import uuid
|
||||||
import re
|
import re
|
||||||
import requests
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from constance import config
|
from constance import config
|
||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
@@ -24,7 +23,7 @@ from django.http import HttpResponse, HttpResponseRedirect
|
|||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from seahub.api2.authentication import TokenAuthentication
|
from seahub.api2.authentication import TokenAuthentication
|
||||||
from seahub.api2.endpoints.utils import sdoc_export_to_md, convert_file
|
from seahub.api2.endpoints.utils import sdoc_export_to_md
|
||||||
from seahub.api2.throttling import UserRateThrottle
|
from seahub.api2.throttling import UserRateThrottle
|
||||||
from seahub.api2.utils import api_error, is_wiki_repo
|
from seahub.api2.utils import api_error, is_wiki_repo
|
||||||
from seahub.utils.db_api import SeafileDB
|
from seahub.utils.db_api import SeafileDB
|
||||||
@@ -35,11 +34,10 @@ from seahub.wiki2.utils import is_valid_wiki_name, get_wiki_config, WIKI_PAGES_D
|
|||||||
check_wiki_admin_permission, check_wiki_permission, get_all_wiki_ids, get_and_gen_page_nav_by_id, \
|
check_wiki_admin_permission, check_wiki_permission, get_all_wiki_ids, get_and_gen_page_nav_by_id, \
|
||||||
get_current_level_page_ids, save_wiki_config, gen_unique_id, gen_new_page_nav_by_id, pop_nav, \
|
get_current_level_page_ids, save_wiki_config, gen_unique_id, gen_new_page_nav_by_id, pop_nav, \
|
||||||
delete_page, move_nav, revert_nav, get_sub_ids_by_page_id, get_parent_id_stack, add_convert_wiki_task, \
|
delete_page, move_nav, revert_nav, get_sub_ids_by_page_id, get_parent_id_stack, add_convert_wiki_task, \
|
||||||
import_conflunece_to_wiki
|
import_conflunece_to_wiki, import_wiki_page
|
||||||
|
|
||||||
from seahub.utils import is_org_context, get_user_repos, is_pro_version, is_valid_dirent_name, \
|
from seahub.utils import is_org_context, get_user_repos, is_pro_version, is_valid_dirent_name, \
|
||||||
get_no_duplicate_obj_name, HAS_FILE_SEARCH, HAS_FILE_SEASEARCH, gen_file_get_url, get_service_url, \
|
get_no_duplicate_obj_name, HAS_FILE_SEARCH, HAS_FILE_SEASEARCH, gen_file_get_url, get_service_url
|
||||||
gen_file_upload_url
|
|
||||||
if HAS_FILE_SEARCH or HAS_FILE_SEASEARCH:
|
if HAS_FILE_SEARCH or HAS_FILE_SEASEARCH:
|
||||||
from seahub.search.utils import search_wikis, ai_search_wikis
|
from seahub.search.utils import search_wikis, ai_search_wikis
|
||||||
|
|
||||||
@@ -62,7 +60,6 @@ from seahub.constants import PERMISSION_READ_WRITE
|
|||||||
from seaserv import ccnet_api
|
from seaserv import ccnet_api
|
||||||
from seahub.share.utils import is_repo_admin
|
from seahub.share.utils import is_repo_admin
|
||||||
from seahub.group.utils import group_id_to_name
|
from seahub.group.utils import group_id_to_name
|
||||||
from seahub.seadoc.apis import batch_upload_sdoc_images
|
|
||||||
|
|
||||||
|
|
||||||
HTTP_520_OPERATION_FAILED = 520
|
HTTP_520_OPERATION_FAILED = 520
|
||||||
@@ -1583,6 +1580,8 @@ class WikiPageExport(APIView):
|
|||||||
export_type = request.GET.get('export_type')
|
export_type = request.GET.get('export_type')
|
||||||
if export_type not in WIKI_PAGE_EXPORT_TYPES:
|
if export_type not in WIKI_PAGE_EXPORT_TYPES:
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, 'Invalid export type')
|
return api_error(status.HTTP_400_BAD_REQUEST, 'Invalid export type')
|
||||||
|
|
||||||
|
# resource check
|
||||||
wiki = Wiki.objects.get(wiki_id=wiki_id)
|
wiki = Wiki.objects.get(wiki_id=wiki_id)
|
||||||
if not wiki:
|
if not wiki:
|
||||||
error_msg = "Wiki not found."
|
error_msg = "Wiki not found."
|
||||||
@@ -1754,12 +1753,13 @@ class Wiki2ImportPageView(APIView):
|
|||||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (IsAuthenticated,)
|
||||||
throttle_classes = (UserRateThrottle,)
|
throttle_classes = (UserRateThrottle,)
|
||||||
|
|
||||||
def post(self, request, wiki_id):
|
def post(self, request, wiki_id):
|
||||||
page_id = request.data.get('page_id', None)
|
from_page_id = request.data.get('from_page_id', None)
|
||||||
file = request.data.get('file', None)
|
file = request.data.get('file', None)
|
||||||
|
|
||||||
if not page_id:
|
if not from_page_id:
|
||||||
error_msg = 'page_id invalid.'
|
error_msg = 'from_page_id invalid.'
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
if not file:
|
if not file:
|
||||||
error_msg = 'file invalid.'
|
error_msg = 'file invalid.'
|
||||||
@@ -1775,7 +1775,7 @@ class Wiki2ImportPageView(APIView):
|
|||||||
if not wiki:
|
if not wiki:
|
||||||
error_msg = "Wiki not found."
|
error_msg = "Wiki not found."
|
||||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
repo_id = wiki.repo_id
|
|
||||||
wiki.owner = get_repo_owner(request, wiki_id)
|
wiki.owner = get_repo_owner(request, wiki_id)
|
||||||
username = request.user.username
|
username = request.user.username
|
||||||
if not check_wiki_admin_permission(wiki, username):
|
if not check_wiki_admin_permission(wiki, username):
|
||||||
@@ -1786,98 +1786,48 @@ class Wiki2ImportPageView(APIView):
|
|||||||
if check_quota(repo_id) < 0:
|
if check_quota(repo_id) < 0:
|
||||||
return api_error(443, _("Out of quota."))
|
return api_error(443, _("Out of quota."))
|
||||||
|
|
||||||
wiki_config = get_wiki_config(wiki_id, request.user.username)
|
tmp_wiki_path = '/tmp/wiki/page'
|
||||||
|
if not os.path.exists(tmp_wiki_path):
|
||||||
|
os.makedirs(tmp_wiki_path)
|
||||||
|
|
||||||
|
local_file_path = os.path.join(tmp_wiki_path, filename)
|
||||||
|
with open(local_file_path, 'wb') as f:
|
||||||
|
f.write(file.read())
|
||||||
|
|
||||||
|
wiki_config = get_wiki_config(repo_id, username)
|
||||||
navigation = wiki_config.get('navigation', [])
|
navigation = wiki_config.get('navigation', [])
|
||||||
page_ids = []
|
page_ids = []
|
||||||
get_current_level_page_ids(navigation, page_id, page_ids)
|
get_current_level_page_ids(navigation, from_page_id, page_ids)
|
||||||
pages = wiki_config.get('pages', [])
|
pages = wiki_config.get('pages', [])
|
||||||
exist_page_names = [page.get('name') for page in pages if page.get('id') in page_ids]
|
exist_page_names = [page.get('name') for page in pages if page.get('id') in page_ids]
|
||||||
|
|
||||||
page_name = os.path.splitext(filename)[0]
|
page_name = os.path.splitext(filename)[0]
|
||||||
page_name = get_no_duplicate_obj_name(page_name, exist_page_names)
|
page_name = get_no_duplicate_obj_name(page_name, exist_page_names)
|
||||||
sdoc_uuid = uuid.uuid4()
|
sdoc_uuid_str = str(uuid.uuid4())
|
||||||
parent_dir = os.path.join(WIKI_PAGES_DIR, str(sdoc_uuid))
|
parent_dir = os.path.join(WIKI_PAGES_DIR, sdoc_uuid_str)
|
||||||
file_path = os.path.join(parent_dir, filename)
|
|
||||||
|
|
||||||
if extension == 'docx':
|
|
||||||
uuid_filename = f'{filename.split(extension)[0]}sdoc'
|
|
||||||
FileUUIDMap.objects.create_fileuuidmap_by_uuid(sdoc_uuid, repo_id, parent_dir, uuid_filename, is_dir=False)
|
|
||||||
elif extension == 'md':
|
|
||||||
uuid_filename = f'{filename.split(extension)[0]}sdoc'
|
|
||||||
FileUUIDMap.objects.create_fileuuidmap_by_uuid(sdoc_uuid, repo_id, parent_dir, uuid_filename, is_dir=False)
|
|
||||||
id_set = get_all_wiki_ids(navigation)
|
id_set = get_all_wiki_ids(navigation)
|
||||||
new_page_id = gen_unique_id(id_set)
|
new_page_id = gen_unique_id(id_set)
|
||||||
dir_id = seafile_api.get_dir_id_by_path(repo_id, parent_dir)
|
if extension == 'docx':
|
||||||
if not dir_id:
|
uuid_filename = f'{filename.split(extension)[0]}sdoc'
|
||||||
seafile_api.mkdir_with_parents(repo_id, '/', parent_dir.strip('/'), request.user.username)
|
elif extension == 'md':
|
||||||
|
uuid_filename = f'{filename.split(extension)[0]}sdoc'
|
||||||
obj_id = json.dumps({'parent_dir': parent_dir})
|
|
||||||
try:
|
|
||||||
token = seafile_api.get_fileserver_access_token(repo_id,
|
|
||||||
obj_id, 'upload', request.user.username, use_onetime=False)
|
|
||||||
except Exception as e:
|
|
||||||
if str(e) == 'Too many files in library.':
|
|
||||||
error_msg = _("The number of files in library exceeds the limit")
|
|
||||||
return api_error(HTTP_447_TOO_MANY_FILES_IN_LIBRARY, error_msg)
|
|
||||||
else:
|
|
||||||
logger.error(e)
|
|
||||||
error_msg = 'Internal Server Error'
|
|
||||||
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
|
||||||
if not token:
|
|
||||||
error_msg = 'Internal Server Error'
|
|
||||||
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
|
||||||
|
|
||||||
upload_link = gen_file_upload_url(token, 'upload-api')
|
sdoc_file_path = os.path.join(parent_dir, uuid_filename)
|
||||||
upload_link += '?ret-json=1'
|
|
||||||
if extension == 'md' or extension == 'docx':
|
|
||||||
src_type = 'docx' if extension == 'docx' else 'markdown'
|
|
||||||
files = {'file': file}
|
|
||||||
data = {'parent_dir': parent_dir, 'replace': 1}
|
|
||||||
resp = requests.post(upload_link, files=files, data=data)
|
|
||||||
if not resp.ok:
|
|
||||||
logger.error('save file: %s failed: %s' % (filename, resp.text))
|
|
||||||
return api_error(resp.status_code, resp.content)
|
|
||||||
file_id = seafile_api.get_file_id_by_path(repo_id, file_path)
|
|
||||||
download_token = seafile_api.get_fileserver_access_token(repo_id, file_id, 'download', username)
|
|
||||||
download_url = gen_file_get_url(download_token, filename)
|
|
||||||
convert_file(file_path, username, str(sdoc_uuid), download_url, upload_link, src_type, 'sdoc')
|
|
||||||
file_path = os.path.join(parent_dir, uuid_filename)
|
|
||||||
|
|
||||||
new_page = {
|
task_id = import_wiki_page({
|
||||||
'id': new_page_id,
|
'repo_id': repo_id,
|
||||||
'name': page_name,
|
'file_path': local_file_path,
|
||||||
'path': file_path,
|
'username': username,
|
||||||
'icon': '',
|
'page_id': new_page_id,
|
||||||
'docUuid': str(sdoc_uuid),
|
'page_name': page_name,
|
||||||
'locked': False
|
'sdoc_uuid_str': sdoc_uuid_str,
|
||||||
}
|
'parent_dir': parent_dir,
|
||||||
pages.append(new_page)
|
})
|
||||||
if len(wiki_config) == 0:
|
|
||||||
wiki_config['version'] = 1
|
|
||||||
|
|
||||||
new_nav = {
|
|
||||||
'id': new_page_id,
|
|
||||||
'type': 'page',
|
|
||||||
}
|
|
||||||
navigation.append(new_nav)
|
|
||||||
wiki_config['navigation'] = navigation
|
|
||||||
wiki_config['pages'] = pages
|
|
||||||
wiki_config = json.dumps(wiki_config)
|
|
||||||
save_wiki_config(wiki, request.user.username, wiki_config)
|
|
||||||
|
|
||||||
try:
|
|
||||||
# remove tmp md/docx
|
|
||||||
if extension in ['md', 'docx']:
|
|
||||||
seafile_api.del_file(repo_id, parent_dir,
|
|
||||||
json.dumps([filename]), username)
|
|
||||||
except SearpcError as e:
|
|
||||||
logger.warning(e)
|
|
||||||
|
|
||||||
return Response({
|
return Response({
|
||||||
'page_id': new_page_id,
|
'page_id': new_page_id,
|
||||||
'path': file_path,
|
'path': sdoc_file_path,
|
||||||
'name': page_name,
|
'name': page_name,
|
||||||
'icon': '',
|
'docUuid': sdoc_uuid_str,
|
||||||
'docUuid': str(sdoc_uuid),
|
'task_id': task_id
|
||||||
'locked': False
|
|
||||||
})
|
})
|
||||||
|
@@ -361,3 +361,11 @@ def import_conflunece_to_wiki(params):
|
|||||||
url = urljoin(SEAFEVENTS_SERVER_URL, '/import-confluence-to-wiki')
|
url = urljoin(SEAFEVENTS_SERVER_URL, '/import-confluence-to-wiki')
|
||||||
resp = requests.post(url, json=params, headers=headers, timeout=30)
|
resp = requests.post(url, json=params, headers=headers, timeout=30)
|
||||||
return json.loads(resp.content)['task_id']
|
return json.loads(resp.content)['task_id']
|
||||||
|
|
||||||
|
def import_wiki_page(params):
|
||||||
|
payload = {'exp': int(time.time()) + 300, }
|
||||||
|
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
|
||||||
|
headers = {"Authorization": "Token %s" % token}
|
||||||
|
url = urljoin(SEAFEVENTS_SERVER_URL, '/import-wiki-page')
|
||||||
|
resp = requests.post(url, json=params, headers=headers, timeout=30)
|
||||||
|
return json.loads(resp.content)['task_id']
|
||||||
|
Reference in New Issue
Block a user