From cc625f7815daa32ddb932e23d1e7f205f88deb75 Mon Sep 17 00:00:00 2001 From: JoinTyang <41655440+JoinTyang@users.noreply.github.com> Date: Tue, 5 Nov 2024 18:03:53 +0800 Subject: [PATCH] migrate old wiki to new wiki (#6987) * migrate old wiki to new wiki * change style --------- Co-authored-by: Michael An <2331806369@qq.com> --- .../src/components/common/select/index.js | 4 +- .../common/select/no-group-message.js | 3 +- .../common/select/seahub-select-style.js | 8 +- .../src/components/dialog/add-wiki-dialog.js | 4 +- .../components/dialog/convert-wiki-dialog.js | 114 ++++++++++++++ frontend/src/components/modal-portal.js | 2 +- frontend/src/components/user-select.js | 7 +- .../wiki-card-view/wiki-card-group.js | 7 +- .../wiki-card-view/wiki-card-item.js | 29 ++++ .../wiki-card-view/wiki-card-view.js | 2 + frontend/src/pages/wikis/wikis.js | 12 ++ frontend/src/utils/wiki-api.js | 10 ++ seahub/api2/endpoints/wiki2.py | 147 +++++++++++++++++- seahub/urls.py | 10 +- seahub/wiki2/utils.py | 15 +- 15 files changed, 351 insertions(+), 23 deletions(-) create mode 100644 frontend/src/components/dialog/convert-wiki-dialog.js diff --git a/frontend/src/components/common/select/index.js b/frontend/src/components/common/select/index.js index 17d8a9bfe1..6764f95dcd 100644 --- a/frontend/src/components/common/select/index.js +++ b/frontend/src/components/common/select/index.js @@ -1,5 +1,5 @@ import SeahubSelect from './seahub-select'; import { NoGroupMessage } from './no-group-message'; -import { MenuSelectStyle, UserSelectStyle } from './seahub-select-style'; +import { MenuSelectStyle, UserSelectStyle, NoOptionsStyle } from './seahub-select-style'; -export { SeahubSelect, NoGroupMessage, MenuSelectStyle, UserSelectStyle }; +export { SeahubSelect, NoGroupMessage, MenuSelectStyle, UserSelectStyle, NoOptionsStyle }; diff --git a/frontend/src/components/common/select/no-group-message.js b/frontend/src/components/common/select/no-group-message.js index 362f72a5e3..7f97e853fd 100644 --- a/frontend/src/components/common/select/no-group-message.js +++ b/frontend/src/components/common/select/no-group-message.js @@ -1,10 +1,11 @@ import React from 'react'; import PropTypes from 'prop-types'; import { gettext } from '../../../utils/constants'; +import { NoOptionsStyle } from './seahub-select-style'; const NoGroupMessage = (props) => { return ( -
{gettext('Group not found')}
+
{gettext('Group not found')}
); }; diff --git a/frontend/src/components/common/select/seahub-select-style.js b/frontend/src/components/common/select/seahub-select-style.js index df4130841e..b2aa726170 100644 --- a/frontend/src/components/common/select/seahub-select-style.js +++ b/frontend/src/components/common/select/seahub-select-style.js @@ -87,4 +87,10 @@ const UserSelectStyle = { }, }; -export { MenuSelectStyle, UserSelectStyle }; +const NoOptionsStyle = { + margin: '6px 10px', + textAlign: 'center', + color: 'hsl(0, 0%, 50%)', +}; + +export { MenuSelectStyle, UserSelectStyle, NoOptionsStyle }; diff --git a/frontend/src/components/dialog/add-wiki-dialog.js b/frontend/src/components/dialog/add-wiki-dialog.js index e37039a3e6..c8b1321023 100644 --- a/frontend/src/components/dialog/add-wiki-dialog.js +++ b/frontend/src/components/dialog/add-wiki-dialog.js @@ -5,7 +5,7 @@ import { gettext, isPro } from '../../utils/constants'; import wikiAPI from '../../utils/wiki-api'; import { Utils } from '../../utils/utils'; import toaster from '../toast'; -import { SeahubSelect } from '../common/select'; +import { SeahubSelect, NoOptionsStyle } from '../common/select'; const propTypes = { toggleCancel: PropTypes.func.isRequired, @@ -97,7 +97,7 @@ class AddWikiDialog extends React.Component { maxMenuHeight={200} value={this.state.selectedOption} components={{ NoOptionsMessage: ( -
{gettext('No department')}
+
{gettext('No department')}
) }} noOptionsMessage={() => {return gettext('No options available');}} /> diff --git a/frontend/src/components/dialog/convert-wiki-dialog.js b/frontend/src/components/dialog/convert-wiki-dialog.js new file mode 100644 index 0000000000..1efd83263f --- /dev/null +++ b/frontend/src/components/dialog/convert-wiki-dialog.js @@ -0,0 +1,114 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Input, Label } from 'reactstrap'; +import { gettext, isPro } from '../../utils/constants'; +import wikiAPI from '../../utils/wiki-api'; +import { Utils } from '../../utils/utils'; +import toaster from '../toast'; +import { SeahubSelect, NoOptionsStyle } from '../common/select'; + +const propTypes = { + toggleCancel: PropTypes.func.isRequired, + convertWiki: PropTypes.func.isRequired, + wiki: PropTypes.object.isRequired, +}; + +class ConvertWikiDialog extends React.Component { + + constructor(props) { + super(props); + this.state = { + name: '', + isSubmitBtnActive: false, + selectedOption: null, + options: [], + }; + } + + componentDidMount() { + if (!isPro) return; + wikiAPI.listWikiDepartments().then(res => { + const departments = res.data.sort((a, b) => { + return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1; + }); + let options = []; + for (let i = 0 ; i < departments.length; i++) { + let obj = {}; + obj.value = departments[i].name; + obj.id = departments[i].id; + obj.email = departments[i].email; + obj.label = departments[i].name; + options.push(obj); + } + this.setState({ options }); + }).catch(error => { + let errMessage = Utils.getErrorMsg(error); + toaster.danger(errMessage); + }); + } + + inputNewName = (e) => { + this.setState({ + name: e.target.value, + }); + }; + + handleKeyDown = (e) => { + if (e.key === 'Enter') { + this.handleSubmit(e); + } + }; + + handleSubmit = (e) => { + const wikiName = this.state.name.trim(); + const departmentID = this.state.selectedOption ? this.state.selectedOption.id : null; + if (!wikiName) return; + this.props.convertWiki(this.props.wiki, wikiName, departmentID); + this.props.toggleCancel(e); + }; + + toggle = () => { + this.props.toggleCancel(); + }; + + handleSelectChange = (option) => { + this.setState({ selectedOption: option }); + }; + + render() { + return ( + + {gettext('Convert Wiki')} + + + + {isPro && + <> + + {gettext('No department')} + ) }} + noOptionsMessage={() => {return gettext('No options available');}} + /> + + } + + + + + + + ); + } +} + +ConvertWikiDialog.propTypes = propTypes; + +export default ConvertWikiDialog; diff --git a/frontend/src/components/modal-portal.js b/frontend/src/components/modal-portal.js index 284fbbc57c..a37c3f076e 100644 --- a/frontend/src/components/modal-portal.js +++ b/frontend/src/components/modal-portal.js @@ -3,7 +3,7 @@ import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; const propTypes = { - children: PropTypes.object.isRequired, + children: PropTypes.any.isRequired, }; const modalRoot = document.getElementById('modal-wrapper'); diff --git a/frontend/src/components/user-select.js b/frontend/src/components/user-select.js index 4e5f165de6..eceefb4bc9 100644 --- a/frontend/src/components/user-select.js +++ b/frontend/src/components/user-select.js @@ -5,7 +5,7 @@ import { seafileAPI } from '../utils/seafile-api'; import { gettext, enableShowContactEmailWhenSearchUser, enableShowLoginIDWhenSearchUser } from '../utils/constants'; import { Utils } from '../utils/utils'; import toaster from './toast'; -import { UserSelectStyle } from './common/select'; +import { UserSelectStyle, NoOptionsStyle } from './common/select'; import '../css/user-select.css'; @@ -86,7 +86,6 @@ class UserSelect extends React.Component { render() { const searchValue = this.state.searchValue; - const style = { margin: '6px 10px', textAlign: 'center', color: 'hsl(0,0%,50%)' }; return ( { return ( -
{searchValue ? gettext('User not found') : gettext('Enter characters to start searching')}
+
+ {searchValue ? gettext('User not found') : gettext('Enter characters to start searching')} +
); } }} diff --git a/frontend/src/components/wiki-card-view/wiki-card-group.js b/frontend/src/components/wiki-card-view/wiki-card-group.js index 923648bdae..fa886966df 100644 --- a/frontend/src/components/wiki-card-view/wiki-card-group.js +++ b/frontend/src/components/wiki-card-view/wiki-card-group.js @@ -14,6 +14,7 @@ const propTypes = { isDepartment: PropTypes.bool.isRequired, isShowAvatar: PropTypes.bool.isRequired, renameWiki: PropTypes.func.isRequired, + convertWiki: PropTypes.func, toggelAddWikiDialog: PropTypes.func, sidePanelRate: PropTypes.number, isSidePanelFolded: PropTypes.bool, @@ -78,7 +79,10 @@ class WikiCardGroup extends Component { isDepartment={isDepartment} isShowAvatar={this.props.isShowAvatar} renameWiki={this.props.renameWiki} - /> : + : + ); })} diff --git a/frontend/src/components/wiki-card-view/wiki-card-item.js b/frontend/src/components/wiki-card-view/wiki-card-item.js index dda8560436..1284a071ab 100644 --- a/frontend/src/components/wiki-card-view/wiki-card-item.js +++ b/frontend/src/components/wiki-card-view/wiki-card-item.js @@ -11,6 +11,7 @@ import ShareWikiDialog from '../dialog/share-wiki-dialog'; import PublishWikiDialog from '../dialog/publish-wiki-dialog'; import wikiAPI from '../../utils/wiki-api'; import toaster from '../toast'; +import ConvertWikiDialog from '../dialog/convert-wiki-dialog'; dayjs.extend(relativeTime); @@ -20,6 +21,7 @@ const propTypes = { deleteWiki: PropTypes.func.isRequired, unshareGroupWiki: PropTypes.func.isRequired, renameWiki: PropTypes.func.isRequired, + convertWiki: PropTypes.func, isDepartment: PropTypes.bool.isRequired, isShowAvatar: PropTypes.bool.isRequired, }; @@ -33,6 +35,7 @@ class WikiCardItem extends Component { isItemMenuShow: false, isShowShareDialog: false, isShowPublishDialog: false, + isShowConvertDialog: false, customUrl: '', }; } @@ -56,6 +59,13 @@ class WikiCardItem extends Component { }); }; + onConvertToggle = (e) => { + e && e.preventDefault(); + this.setState({ + isShowConvertDialog: !this.state.isShowConvertDialog, + }); + }; + onPublishToggle = (e) => { this.getPublishWikiLink(); }; @@ -176,6 +186,7 @@ class WikiCardItem extends Component { let showLeaveShare = false; let showDropdownMenu = false; let showPublish = false; + let showWikiConvert = false; if (isDepartment) { if (isAdmin) { @@ -184,6 +195,9 @@ class WikiCardItem extends Component { showShare = true; showRename = true; showPublish = true; + if (isOldVersion) { + showWikiConvert = true; + } } else { showLeaveShare = true; } @@ -194,6 +208,9 @@ class WikiCardItem extends Component { showDelete = true; showRename = true; showPublish = true; + if (isOldVersion) { + showWikiConvert = true; + } } else { showLeaveShare = true; } @@ -239,6 +256,9 @@ class WikiCardItem extends Component { {showDelete && {gettext('Delete')} } + {showWikiConvert && + {gettext('Convert to new Wiki')} + } {showLeaveShare && {gettext('Leave')} } @@ -327,6 +347,15 @@ class WikiCardItem extends Component { /> } + {this.state.isShowConvertDialog && + + + + } ); } diff --git a/frontend/src/components/wiki-card-view/wiki-card-view.js b/frontend/src/components/wiki-card-view/wiki-card-view.js index 3139c58076..c18f919383 100644 --- a/frontend/src/components/wiki-card-view/wiki-card-view.js +++ b/frontend/src/components/wiki-card-view/wiki-card-view.js @@ -14,6 +14,7 @@ const propTypes = { renameWiki: PropTypes.func.isRequired, leaveSharedWiki: PropTypes.func.isRequired, unshareGroupWiki: PropTypes.func.isRequired, + convertWiki: PropTypes.func.isRequired, toggelAddWikiDialog: PropTypes.func, sidePanelRate: PropTypes.number, isSidePanelFolded: PropTypes.bool, @@ -132,6 +133,7 @@ class WikiCardView extends Component { deleteWiki={this.props.deleteWiki} renameWiki={this.props.renameWiki} unshareGroupWiki={this.props.unshareGroupWiki} + convertWiki={this.props.convertWiki} isSidePanelFolded={isSidePanelFolded} sidePanelRate={sidePanelRate} wikis={v1Wikis} diff --git a/frontend/src/pages/wikis/wikis.js b/frontend/src/pages/wikis/wikis.js index 9c8f07d241..1823323606 100644 --- a/frontend/src/pages/wikis/wikis.js +++ b/frontend/src/pages/wikis/wikis.js @@ -249,6 +249,17 @@ class Wikis extends Component { } }; + convertWiki = (wiki, wikiName, departmentID) => { + wikiAPI.convertWiki(wiki.id, wikiName, departmentID).then((res) => { + this.getWikis(); + }).catch((error) => { + if (error.response) { + let errorMsg = error.response.data.error_msg; + toaster.danger(errorMsg); + } + }); + }; + toggleDropdownMenu = (e) => { e.stopPropagation(); this.setState({ @@ -299,6 +310,7 @@ class Wikis extends Component { leaveSharedWiki={this.leaveSharedWiki} unshareGroupWiki={this.unshareGroupWiki} renameWiki={this.renameWiki} + convertWiki={this.convertWiki} toggelAddWikiDialog={this.toggelAddWikiDialog} sidePanelRate={this.props.sidePanelRate} isSidePanelFolded={this.props.isSidePanelFolded} diff --git a/frontend/src/utils/wiki-api.js b/frontend/src/utils/wiki-api.js index c93e02d521..34b6eefbfb 100644 --- a/frontend/src/utils/wiki-api.js +++ b/frontend/src/utils/wiki-api.js @@ -280,6 +280,16 @@ class WikiAPI { return this.req.delete(url); } + convertWiki(oldWikiId, wikiName, owner) { + const url = this.server + '/api/v2.1/convert-wiki/'; + let form = new FormData(); + form.append('old_wiki_id', oldWikiId); + form.append('name', wikiName); + if (owner) { + form.append('owner', owner); + } + return this._sendPostRequest(url, form); + } } let wikiAPI = new WikiAPI(); diff --git a/seahub/api2/endpoints/wiki2.py b/seahub/api2/endpoints/wiki2.py index 7cff66e773..cbee2dac25 100644 --- a/seahub/api2/endpoints/wiki2.py +++ b/seahub/api2/endpoints/wiki2.py @@ -25,11 +25,12 @@ from seahub.api2.utils import api_error, is_wiki_repo from seahub.api2.endpoints.utils import wiki_search from seahub.utils.db_api import SeafileDB from seahub.wiki2.models import Wiki2 as Wiki +from seahub.wiki.models import Wiki as OldWiki from seahub.wiki2.models import WikiPageTrash, Wiki2Publish from seahub.wiki2.utils import is_valid_wiki_name, get_wiki_config, WIKI_PAGES_DIR, is_group_wiki, \ 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, \ - delete_page, move_nav, revert_nav, get_sub_ids_by_page_id, get_parent_id_stack + delete_page, move_nav, revert_nav, get_sub_ids_by_page_id, get_parent_id_stack, add_convert_wiki_task from seahub.utils import is_org_context, get_user_repos, is_pro_version, is_valid_dirent_name, \ get_no_duplicate_obj_name @@ -37,7 +38,7 @@ from seahub.utils import is_org_context, get_user_repos, is_pro_version, is_vali from seahub.views import check_folder_permission from seahub.base.templatetags.seahub_tags import email2nickname from seahub.utils.file_op import check_file_lock -from seahub.utils.repo import get_repo_owner, is_valid_repo_id_format +from seahub.utils.repo import get_repo_owner, is_valid_repo_id_format, is_group_repo_staff, is_repo_owner from seahub.seadoc.utils import get_seadoc_file_uuid, gen_seadoc_access_token, copy_sdoc_images_with_sdoc_uuid from seahub.settings import ENABLE_STORAGE_CLASSES, STORAGE_CLASS_MAPPING_POLICY, \ ENCRYPTED_LIBRARY_VERSION @@ -51,6 +52,7 @@ from seahub.group.utils import group_id_to_name, is_group_admin from seahub.utils.rpc import SeafileAPI from seahub.constants import PERMISSION_READ_WRITE from seaserv import ccnet_api +from seahub.share.utils import is_repo_admin HTTP_520_OPERATION_FAILED = 520 @@ -59,7 +61,7 @@ logger = logging.getLogger(__name__) def _merge_wiki_in_groups(group_wikis, publish_wiki_ids): - + group_ids = [gw.group_id for gw in group_wikis] group_id_wikis_map = {key: [] for key in group_ids} for gw in group_wikis: @@ -81,7 +83,7 @@ def _merge_wiki_in_groups(group_wikis, publish_wiki_ids): group_id = gw.group_id group_id_wikis_map[group_id].append(wiki_info) return group_id_wikis_map - + @@ -96,7 +98,7 @@ class Wikis2View(APIView): username = request.user.username org_id = request.user.org.org_id if is_org_context(request) else None (owned, shared, groups, public) = get_user_repos(username, org_id) - + # list user groups if is_org_context(request): org_id = request.user.org.org_id @@ -623,7 +625,7 @@ class Wiki2PagesView(APIView): if move_position not in valid_move_positions: error_msg = 'Invalid move_position value: ' + move_position return api_error(status.HTTP_400_BAD_REQUEST, error_msg) - + if (target_page_id not in id_set) or (moved_page_id not in id_set): error_msg = 'Page not found' logger.error(error_msg) @@ -1311,3 +1313,136 @@ class WikiSearch(APIView): return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal Server Error') return Response(resp_json, resp.status_code) + + +class WikiConvertView(APIView): + authentication_classes = (TokenAuthentication, SessionAuthentication) + permission_classes = (IsAuthenticated,) + throttle_classes = (UserRateThrottle,) + + def post(self, request): + old_wiki_id = request.data.get('old_wiki_id', None) + if not old_wiki_id: + error_msg = 'old_wiki_id invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + try: + wiki = OldWiki.objects.get(id=old_wiki_id) + except OldWiki.DoesNotExist: + error_msg = 'Old Wiki not found.' + return api_error(status.HTTP_404_NOT_FOUND, error_msg) + + username = request.user.username + old_repo_id = wiki.repo_id + + # check old wiki permission + is_owner = is_repo_owner(request, old_repo_id, username) + if not is_owner: + repo_admin = is_repo_admin(username, old_repo_id) + if not repo_admin: + is_group_repo_admin = is_group_repo_staff(request, old_repo_id, username) + + if not is_group_repo_admin: + error_msg = _('Permission denied.') + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + + if wiki.username != username: + error_msg = 'Permission denied.' + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + + if not request.user.permissions.can_add_repo(): + return api_error(status.HTTP_403_FORBIDDEN, 'You do not have permission to create library.') + + wiki_name = request.data.get("name", None) + if not wiki_name: + return api_error(status.HTTP_400_BAD_REQUEST, 'wiki name is required.') + + if not is_valid_wiki_name(wiki_name): + msg = _('Name can only contain letters, numbers, blank, hyphen or underscore.') + return api_error(status.HTTP_400_BAD_REQUEST, msg) + + old_repo_id = wiki.repo_id + repo = seafile_api.get_repo(old_repo_id) + if not repo: + error_msg = 'Library %s not found.' % old_repo_id + return api_error(status.HTTP_404_NOT_FOUND, error_msg) + + wiki_owner = request.data.get('owner', 'me') + is_group_owner = False + group_id = '' + if wiki_owner == 'me': + wiki_owner = request.user.username + else: + try: + group_id = int(wiki_owner) + wiki_owner = "%s@seafile_group" % group_id + except: + return api_error(status.HTTP_400_BAD_REQUEST, 'wiki_owner invalid') + is_group_owner = True + + org_id = -1 + if is_org_context(request): + org_id = request.user.org.org_id + + permission = PERMISSION_READ_WRITE + if is_group_owner: + group_id = int(group_id) + # only group admin can create wiki + if not is_group_admin(group_id, request.user.username): + error_msg = 'Permission denied.' + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + + group_quota = seafile_api.get_group_quota(group_id) + group_quota = int(group_quota) + if group_quota <= 0 and group_quota != -2: + error_msg = 'No group quota.' + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + + # create group owned repo + group_id = int(group_id) + password = None + if is_pro_version() and ENABLE_STORAGE_CLASSES: + + if STORAGE_CLASS_MAPPING_POLICY in ('USER_SELECT', 'ROLE_BASED'): + storage_id = None + repo_id = seafile_api.add_group_owned_repo(group_id, + wiki_name, + permission, + password, + enc_version=ENCRYPTED_LIBRARY_VERSION, + storage_id=storage_id) + else: + # STORAGE_CLASS_MAPPING_POLICY == 'REPO_ID_MAPPING' + repo_id = SeafileAPI.add_group_owned_repo( + group_id, wiki_name, password, permission, org_id=org_id) + else: + repo_id = SeafileAPI.add_group_owned_repo( + group_id, wiki_name, password, permission, org_id=org_id) + else: + if org_id and org_id > 0: + repo_id = seafile_api.create_org_repo(wiki_name, '', wiki_owner, org_id) + else: + repo_id = seafile_api.create_repo(wiki_name, '', wiki_owner) + + try: + seafile_db_api = SeafileDB() + seafile_db_api.set_repo_type(repo_id, 'wiki') + except Exception as e: + logger.error(e) + msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, msg) + + params = { + 'old_repo_id': old_repo_id, + 'new_repo_id': repo_id, + 'username': request.user.username, + } + + try: + task_id = add_convert_wiki_task(params=params) + except Exception as e: + logger.error(e) + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Internal Server Error') + + return Response({"task_id": task_id}) + diff --git a/seahub/urls.py b/seahub/urls.py index 041e3615ce..6024273f4a 100644 --- a/seahub/urls.py +++ b/seahub/urls.py @@ -210,7 +210,7 @@ from seahub.ocm.settings import OCM_ENDPOINT from seahub.wiki2.views import wiki_view, wiki_publish_view from seahub.api2.endpoints.wiki2 import Wikis2View, Wiki2View, Wiki2ConfigView, Wiki2PagesView, Wiki2PageView, \ Wiki2DuplicatePageView, WikiPageTrashView, Wiki2PublishView, Wiki2PublishConfigView, Wiki2PublishPageView, \ - WikiSearch + WikiSearch, WikiConvertView from seahub.api2.endpoints.subscription import SubscriptionView, SubscriptionPlansView, SubscriptionLogsView from seahub.api2.endpoints.metadata_manage import MetadataRecords, MetadataManage, MetadataColumns, MetadataRecordInfo, \ MetadataViews, MetadataViewsMoveView, MetadataViewsDetailView, MetadataViewsDuplicateView, FacesRecords, \ @@ -558,7 +558,7 @@ urlpatterns = [ re_path(r'^api/v2.1/wiki2/(?P[-0-9a-f]{36})/trash/', WikiPageTrashView.as_view(), name='api-v2.1-wiki2-trash'), re_path(r'^api/v2.1/wiki2/(?P[-0-9a-f]{36})/publish/$', Wiki2PublishView.as_view(), name='api-v2.1-wiki2-publish'), re_path(r'^api/v2.1/wiki2/search/$', WikiSearch.as_view(), name='api-v2.1-wiki2-search'), - + re_path(r'^api/v2.1/convert-wiki/$', WikiConvertView.as_view(), name='api-v2.1-wiki-convert'), ## user::drafts re_path(r'^api/v2.1/drafts/$', DraftsView.as_view(), name='api-v2.1-drafts'), re_path(r'^api/v2.1/drafts/(?P\d+)/$', DraftView.as_view(), name='api-v2.1-draft'), @@ -801,7 +801,7 @@ urlpatterns = [ re_path(r'^api/v2.1/internal/user-list/$', InternalUserListView.as_view(), name="api-v2.1-internal-user-list"), re_path(r'^api/v2.1/internal/check-share-link-access/$', InternalCheckShareLinkAccess.as_view(), name="api-v2.1-internal-share-link-info"), re_path(r'^api/v2.1/internal/repos/(?P[-0-9a-f]{36})/check-access/$', InternalCheckFileOperationAccess.as_view(), name="api-v2.1-internal-check-file-op-access"), - + ### system admin ### re_path(r'^sys/seafadmin/delete/(?P[-0-9a-f]{36})/$', sys_repo_delete, name='sys_repo_delete'), path('sys/useradmin/export-excel/', sys_useradmin_export_excel, name='sys_useradmin_export_excel'), @@ -956,8 +956,8 @@ if getattr(settings, 'ENABLE_KRB5_LOGIN', False): urlpatterns += [ re_path(r'^krb5-login/', shib_login, name="krb5_login"), ] - - + + if getattr(settings, 'ENABLE_LOGIN_SIMPLE_CHECK', False): urlpatterns += [ re_path(r'^sso-auto-login/', login_simple_check), diff --git a/seahub/wiki2/utils.py b/seahub/wiki2/utils.py index ac3dc3ab4b..c39314567b 100644 --- a/seahub/wiki2/utils.py +++ b/seahub/wiki2/utils.py @@ -8,12 +8,16 @@ import json import requests import posixpath import random +import jwt +import time +from urllib.parse import urljoin from seaserv import seafile_api from seahub.constants import PERMISSION_READ_WRITE from seahub.utils import gen_inner_file_get_url, gen_file_upload_url from seahub.group.utils import is_group_admin, is_group_member from seahub.wiki2.models import WikiPageTrash +from seahub.settings import SECRET_KEY, SEAFEVENTS_SERVER_URL logger = logging.getLogger(__name__) @@ -271,7 +275,7 @@ def move_nav(navigation, target_id, moved_nav, move_position): def revert_nav(navigation, parent_page_id, subpages): - + # connect the subpages to the parent_page # if not parent_page_id marked as flag, connect the subpages to the root def recurse(navigation, parent_page_id, subpages): @@ -318,3 +322,12 @@ def get_parent_id_stack(navigation, page_id): return_parent_page_id(navigation, page_id, id_list) return id_list + + +def add_convert_wiki_task(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, '/add-convert-wiki-task') + resp = requests.get(url, params=params, headers=headers) + return json.loads(resp.content)['task_id']