mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-12 21:30:39 +00:00
wiki page saved in doc uuid dir (#6110)
* wiki page saved in doc uuid dir * optimize del page and dir * optimize code * rebase
This commit is contained in:
@@ -83,14 +83,7 @@ class Wiki extends Component {
|
|||||||
getWikiConfig = () => {
|
getWikiConfig = () => {
|
||||||
wikiAPI.getWiki2Config(wikiId).then(res => {
|
wikiAPI.getWiki2Config(wikiId).then(res => {
|
||||||
const { wiki_config, repo_id } = res.data.wiki;
|
const { wiki_config, repo_id } = res.data.wiki;
|
||||||
try {
|
const config = new WikiConfig(wiki_config || {});
|
||||||
JSON.parse(wiki_config);
|
|
||||||
} catch (error) {
|
|
||||||
toaster.danger(gettext('Wiki config error'));
|
|
||||||
this.setState({ isConfigLoading: false });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const config = new WikiConfig(JSON.parse(wiki_config) || {});
|
|
||||||
this.setState({
|
this.setState({
|
||||||
config,
|
config,
|
||||||
isConfigLoading: false,
|
isConfigLoading: false,
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import deepCopy from 'deep-copy';
|
import deepCopy from 'deep-copy';
|
||||||
import { gettext, repoID, isWiki2 } from '../../utils/constants';
|
import { gettext, isWiki2, wikiId } from '../../utils/constants';
|
||||||
import toaster from '../../components/toast';
|
import toaster from '../../components/toast';
|
||||||
import Loading from '../../components/loading';
|
import Loading from '../../components/loading';
|
||||||
// import TreeView from '../../components/tree-view/tree-view';
|
// import TreeView from '../../components/tree-view/tree-view';
|
||||||
@@ -14,7 +14,7 @@ import ViewStructureFooter from './view-structure/view-structure-footer';
|
|||||||
import { generateUniqueId, isObjectNotEmpty } from './utils';
|
import { generateUniqueId, isObjectNotEmpty } from './utils';
|
||||||
import Folder from './models/folder';
|
import Folder from './models/folder';
|
||||||
import Page from './models/page';
|
import Page from './models/page';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import wikiAPI from '../../utils/wiki-api';
|
||||||
import { FOLDER } from './constant';
|
import { FOLDER } from './constant';
|
||||||
|
|
||||||
import './side-panel.css';
|
import './side-panel.css';
|
||||||
@@ -101,13 +101,10 @@ class SidePanel extends Component {
|
|||||||
const config = deepCopy(this.props.config);
|
const config = deepCopy(this.props.config);
|
||||||
const { pages, navigation } = config;
|
const { pages, navigation } = config;
|
||||||
const index = PageUtils.getPageIndexById(pageId, pages);
|
const index = PageUtils.getPageIndexById(pageId, pages);
|
||||||
const pageIndex = pages.findIndex(item => item.id === pageId);
|
|
||||||
let path = pages[pageIndex].path;
|
|
||||||
|
|
||||||
config.pages.splice(index, 1);
|
config.pages.splice(index, 1);
|
||||||
PageUtils.deletePage(navigation, pageId);
|
PageUtils.deletePage(navigation, pageId);
|
||||||
this.props.saveWikiConfig(config);
|
this.props.saveWikiConfig(config);
|
||||||
seafileAPI.deleteFile(repoID, path);
|
wikiAPI.deleteWiki2Page(wikiId, pageId);
|
||||||
if (config.pages.length > 0) {
|
if (config.pages.length > 0) {
|
||||||
this.props.setCurrentPage(config.pages[0].id);
|
this.props.setCurrentPage(config.pages[0].id);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Modal, ModalHeader, ModalBody, ModalFooter, Label, Input, Button } from 'reactstrap';
|
import { Modal, ModalHeader, ModalBody, ModalFooter, Label, Input, Button } from 'reactstrap';
|
||||||
import { gettext, repoID } from '../../../utils/constants';
|
import { gettext, wikiId } from '../../../utils/constants';
|
||||||
import { seafileAPI } from '../../../utils/seafile-api';
|
|
||||||
import { Utils } from '../../../utils/utils';
|
import { Utils } from '../../../utils/utils';
|
||||||
import toaster from '../../../components/toast';
|
import toaster from '../../../components/toast';
|
||||||
import Loading from '../../../components/loading';
|
import Loading from '../../../components/loading';
|
||||||
|
import wikiAPI from '../../../utils/wiki-api';
|
||||||
|
|
||||||
import '../css/add-new-page-dialog.css';
|
import '../css/add-new-page-dialog.css';
|
||||||
|
|
||||||
@@ -14,7 +14,6 @@ const propTypes = {
|
|||||||
onAddNewPage: PropTypes.func,
|
onAddNewPage: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
const NEW_WIKI_FILE_PATH = '/wiki-pages/';
|
|
||||||
|
|
||||||
class AddNewPageDialog extends React.Component {
|
class AddNewPageDialog extends React.Component {
|
||||||
|
|
||||||
@@ -22,35 +21,11 @@ class AddNewPageDialog extends React.Component {
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
pageName: '',
|
pageName: '',
|
||||||
isLoading: true,
|
isLoading: false,
|
||||||
errMessage: '',
|
errMessage: '',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
seafileAPI.getDirInfo(repoID, NEW_WIKI_FILE_PATH).then((res) => {
|
|
||||||
if (res.data.path === NEW_WIKI_FILE_PATH) {
|
|
||||||
this.setState({ isLoading: false });
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
if (error.response.data.error_msg === 'Folder /wiki-pages/ not found.') {
|
|
||||||
seafileAPI.createDir(repoID, NEW_WIKI_FILE_PATH).then((res) => {
|
|
||||||
if (res.data === 'success') {
|
|
||||||
this.setState({ isLoading: false });
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
let errMessage = Utils.getErrorMsg(error);
|
|
||||||
toaster.danger(errMessage);
|
|
||||||
this.setState({ isLoading: false });
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
let errMessage = Utils.getErrorMsg(error);
|
|
||||||
toaster.danger(errMessage);
|
|
||||||
this.setState({ isLoading: false });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChange = (event) => {
|
handleChange = (event) => {
|
||||||
let value = event.target.value;
|
let value = event.target.value;
|
||||||
if (value !== this.state.pageName) {
|
if (value !== this.state.pageName) {
|
||||||
@@ -89,12 +64,12 @@ class AddNewPageDialog extends React.Component {
|
|||||||
const pageName = this.state.pageName.trim();
|
const pageName = this.state.pageName.trim();
|
||||||
if (this.checkName(pageName)) {
|
if (this.checkName(pageName)) {
|
||||||
this.setState({ isLoading: true });
|
this.setState({ isLoading: true });
|
||||||
this.createFile(pageName, `${NEW_WIKI_FILE_PATH}${pageName}.sdoc`);
|
this.createPage(pageName);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
createFile = (pageName, filePath) => {
|
createPage = (pageName) => {
|
||||||
seafileAPI.createFile(repoID, filePath).then(res => {
|
wikiAPI.createWiki2Page(wikiId, pageName).then(res => {
|
||||||
const { obj_name, parent_dir, doc_uuid } = res.data;
|
const { obj_name, parent_dir, doc_uuid } = res.data;
|
||||||
this.props.onAddNewPage({
|
this.props.onAddNewPage({
|
||||||
name: pageName,
|
name: pageName,
|
||||||
|
@@ -41,7 +41,7 @@ class Wikis extends Component {
|
|||||||
return wiki['version'] = 'v1';
|
return wiki['version'] = 'v1';
|
||||||
});
|
});
|
||||||
wikiAPI.listWikis2().then(res => {
|
wikiAPI.listWikis2().then(res => {
|
||||||
let wikis2 = res.data.data;
|
let wikis2 = res.data.wikis;
|
||||||
wikis2.map(wiki => {
|
wikis2.map(wiki => {
|
||||||
return wiki['version'] = 'v2';
|
return wiki['version'] = 'v2';
|
||||||
});
|
});
|
||||||
|
@@ -108,9 +108,9 @@ class WikiAPI {
|
|||||||
// for wiki2
|
// for wiki2
|
||||||
listWiki2Dir(wikiId, dirPath, withParents) {
|
listWiki2Dir(wikiId, dirPath, withParents) {
|
||||||
const path = encodeURIComponent(dirPath);
|
const path = encodeURIComponent(dirPath);
|
||||||
let url = this.server + '/api/v2.1/wikis2/' + wikiId + '/dir/?p=' + path;
|
let url = this.server + '/api/v2.1/wiki2/' + wikiId + '/page-dir/?p=' + path;
|
||||||
if (withParents) {
|
if (withParents) {
|
||||||
url = this.server + '/api/v2.1/wikis2/' + wikiId + '/dir/?p=' + path + '&with_parents=' + withParents;
|
url = this.server + '/api/v2.1/wiki2/' + wikiId + '/page-dir/?p=' + path + '&with_parents=' + withParents;
|
||||||
}
|
}
|
||||||
return this.req.get(url);
|
return this.req.get(url);
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,7 @@ class WikiAPI {
|
|||||||
getWiki2FileContent(wikiId, filePath) {
|
getWiki2FileContent(wikiId, filePath) {
|
||||||
const path = encodeURIComponent(filePath);
|
const path = encodeURIComponent(filePath);
|
||||||
const time = new Date().getTime();
|
const time = new Date().getTime();
|
||||||
const url = this.server + '/api/v2.1/wikis2/' + wikiId + '/content/' + '?p=' + path + '&_=' + time;
|
const url = this.server + '/api/v2.1/wiki2/' + wikiId + '/content/' + '?p=' + path + '&_=' + time;
|
||||||
return this.req.get(url);
|
return this.req.get(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,12 +161,12 @@ class WikiAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deleteWiki2(wikiId) {
|
deleteWiki2(wikiId) {
|
||||||
const url = this.server + '/api/v2.1/wikis2/' + wikiId + '/';
|
const url = this.server + '/api/v2.1/wiki2/' + wikiId + '/';
|
||||||
return this.req.delete(url);
|
return this.req.delete(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateWiki2Config(wikiId, wikiConfig) {
|
updateWiki2Config(wikiId, wikiConfig) {
|
||||||
const url = this.server + '/api/v2.1/wiki2-config/' + wikiId + '/';
|
const url = this.server + '/api/v2.1/wiki2/' + wikiId + '/config/';
|
||||||
let params = {
|
let params = {
|
||||||
wiki_config: wikiConfig
|
wiki_config: wikiConfig
|
||||||
};
|
};
|
||||||
@@ -174,10 +174,28 @@ class WikiAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getWiki2Config(wikiId) {
|
getWiki2Config(wikiId) {
|
||||||
const url = this.server + '/api/v2.1/wiki2-config/' + wikiId + '/';
|
const url = this.server + '/api/v2.1/wiki2/' + wikiId + '/config/';
|
||||||
return this.req.get(url);
|
return this.req.get(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createWiki2Page(wikiId, pageName) {
|
||||||
|
const url = this.server + '/api/v2.1/wiki2/' + wikiId + '/pages/';
|
||||||
|
let form = new FormData();
|
||||||
|
form.append('page_name', pageName);
|
||||||
|
return this._sendPostRequest(url, form);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteWiki2Page(wikiId, pageId) {
|
||||||
|
// const path = encodeURIComponent(pagePath);
|
||||||
|
const url = this.server + '/api/v2.1/wiki2/' + wikiId + '/page/' + pageId + '/';
|
||||||
|
return this.req.delete(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteWiki2Folder(wikiId, folderId) {
|
||||||
|
const url = this.server + '/api/v2.1/wiki2/' + wikiId + '/folder/' + folderId + '/';
|
||||||
|
return this.req.delete(url);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let wikiAPI = new WikiAPI();
|
let wikiAPI = new WikiAPI();
|
||||||
|
@@ -6,11 +6,12 @@ import logging
|
|||||||
import requests
|
import requests
|
||||||
import posixpath
|
import posixpath
|
||||||
import time
|
import time
|
||||||
|
import uuid
|
||||||
import urllib.request, urllib.error, urllib.parse
|
import urllib.request, urllib.error, urllib.parse
|
||||||
|
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.authentication import SessionAuthentication
|
from rest_framework.authentication import SessionAuthentication
|
||||||
from rest_framework.permissions import IsAuthenticated, IsAuthenticated, IsAuthenticatedOrReadOnly
|
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from seaserv import seafile_api, edit_repo
|
from seaserv import seafile_api, edit_repo
|
||||||
@@ -21,9 +22,10 @@ from seahub.api2.authentication import TokenAuthentication
|
|||||||
from seahub.api2.throttling import UserRateThrottle
|
from seahub.api2.throttling import UserRateThrottle
|
||||||
from seahub.api2.utils import api_error, to_python_boolean
|
from seahub.api2.utils import api_error, to_python_boolean
|
||||||
from seahub.wiki2.models import Wiki2 as Wiki
|
from seahub.wiki2.models import Wiki2 as Wiki
|
||||||
from seahub.wiki2.utils import is_valid_wiki_name, can_edit_wiki, get_wiki_dirs_by_path
|
from seahub.wiki2.utils import is_valid_wiki_name, can_edit_wiki, get_wiki_dirs_by_path, \
|
||||||
|
get_wiki_config, WIKI_PAGES_DIR, WIKI_CONFIG_PATH, WIKI_CONFIG_FILE_NAME
|
||||||
from seahub.utils import is_org_context, get_user_repos, gen_inner_file_get_url, gen_file_upload_url, \
|
from seahub.utils import is_org_context, get_user_repos, gen_inner_file_get_url, gen_file_upload_url, \
|
||||||
normalize_dir_path, is_pro_version
|
normalize_dir_path, is_pro_version, check_filename_with_rename, is_valid_dirent_name
|
||||||
from seahub.views import check_folder_permission
|
from seahub.views import check_folder_permission
|
||||||
from seahub.views.file import send_file_access_msg
|
from seahub.views.file import send_file_access_msg
|
||||||
from seahub.base.templatetags.seahub_tags import email2nickname
|
from seahub.base.templatetags.seahub_tags import email2nickname
|
||||||
@@ -32,10 +34,12 @@ from seahub.utils.repo import parse_repo_perm
|
|||||||
from seahub.seadoc.utils import get_seadoc_file_uuid, gen_seadoc_access_token
|
from seahub.seadoc.utils import get_seadoc_file_uuid, gen_seadoc_access_token
|
||||||
from seahub.settings import SEADOC_SERVER_URL
|
from seahub.settings import SEADOC_SERVER_URL
|
||||||
from seahub.seadoc.sdoc_server_api import SdocServerAPI
|
from seahub.seadoc.sdoc_server_api import SdocServerAPI
|
||||||
|
from seahub.utils.timeutils import timestamp_to_isoformat_timestr
|
||||||
|
from seahub.tags.models import FileUUIDMap
|
||||||
|
from seahub.seadoc.models import SeadocHistoryName, SeadocDraft, SeadocCommentReply
|
||||||
|
from seahub.base.models import FileComment
|
||||||
|
from seahub.api2.views import HTTP_447_TOO_MANY_FILES_IN_LIBRARY
|
||||||
|
|
||||||
|
|
||||||
WIKI_CONFIG_PATH = '_Internal/Wiki'
|
|
||||||
WIKI_CONFIG_FILE_NAME = 'index.json'
|
|
||||||
HTTP_520_OPERATION_FAILED = 520
|
HTTP_520_OPERATION_FAILED = 520
|
||||||
|
|
||||||
|
|
||||||
@@ -91,10 +95,9 @@ class Wikis2View(APIView):
|
|||||||
wiki_list = []
|
wiki_list = []
|
||||||
for wiki in wikis:
|
for wiki in wikis:
|
||||||
wiki_info = wiki.to_dict()
|
wiki_info = wiki.to_dict()
|
||||||
wiki_info['can_edit'] = (username == wiki.username)
|
|
||||||
wiki_list.append(wiki_info)
|
wiki_list.append(wiki_info)
|
||||||
|
|
||||||
return Response({'data': wiki_list})
|
return Response({'wikis': wiki_list})
|
||||||
|
|
||||||
def post(self, request, format=None):
|
def post(self, request, format=None):
|
||||||
"""Add a new wiki.
|
"""Add a new wiki.
|
||||||
@@ -169,8 +172,12 @@ class Wiki2ConfigView(APIView):
|
|||||||
def put(self, request, wiki_id):
|
def put(self, request, wiki_id):
|
||||||
"""Edit a wiki config
|
"""Edit a wiki config
|
||||||
"""
|
"""
|
||||||
username = request.user.username
|
wiki_config = request.data.get('wiki_config')
|
||||||
|
if not wiki_config:
|
||||||
|
error_msg = 'wiki_config invalid.'
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
username = request.user.username
|
||||||
try:
|
try:
|
||||||
wiki = Wiki.objects.get(id=wiki_id)
|
wiki = Wiki.objects.get(id=wiki_id)
|
||||||
except Wiki.DoesNotExist:
|
except Wiki.DoesNotExist:
|
||||||
@@ -195,8 +202,6 @@ class Wiki2ConfigView(APIView):
|
|||||||
upload_link = gen_file_upload_url(token, 'upload-api')
|
upload_link = gen_file_upload_url(token, 'upload-api')
|
||||||
upload_link = upload_link + '?replace=1'
|
upload_link = upload_link + '?replace=1'
|
||||||
|
|
||||||
wiki_config = request.data.get('wiki_config', '{}')
|
|
||||||
|
|
||||||
files = {
|
files = {
|
||||||
'file': (WIKI_CONFIG_FILE_NAME, wiki_config)
|
'file': (WIKI_CONFIG_FILE_NAME, wiki_config)
|
||||||
}
|
}
|
||||||
@@ -223,7 +228,6 @@ class Wiki2ConfigView(APIView):
|
|||||||
error_msg = 'Permission denied.'
|
error_msg = 'Permission denied.'
|
||||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
|
||||||
path = posixpath.join(WIKI_CONFIG_PATH, WIKI_CONFIG_FILE_NAME)
|
|
||||||
try:
|
try:
|
||||||
repo = seafile_api.get_repo(wiki.repo_id)
|
repo = seafile_api.get_repo(wiki.repo_id)
|
||||||
if not repo:
|
if not repo:
|
||||||
@@ -233,29 +237,10 @@ class Wiki2ConfigView(APIView):
|
|||||||
error_msg = _("Internal Server Error")
|
error_msg = _("Internal Server Error")
|
||||||
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
|
||||||
try:
|
|
||||||
file_id = seafile_api.get_file_id_by_path(repo.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)
|
|
||||||
|
|
||||||
wiki = wiki.to_dict()
|
wiki = wiki.to_dict()
|
||||||
if not file_id:
|
wiki_config = get_wiki_config(repo.repo_id, request.user.username)
|
||||||
wiki['wiki_config'] = '{}'
|
|
||||||
return Response({'wiki': wiki})
|
|
||||||
|
|
||||||
token = seafile_api.get_fileserver_access_token(repo.repo_id, file_id, 'download', request.user.username, use_onetime=True)
|
wiki['wiki_config'] = wiki_config
|
||||||
|
|
||||||
if not token:
|
|
||||||
error_msg = 'Internal Server Error'
|
|
||||||
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
|
||||||
|
|
||||||
url = gen_inner_file_get_url(token, WIKI_CONFIG_FILE_NAME)
|
|
||||||
resp = requests.get(url)
|
|
||||||
content = resp.content
|
|
||||||
|
|
||||||
wiki['wiki_config'] = content
|
|
||||||
|
|
||||||
return Response({'wiki': wiki})
|
return Response({'wiki': wiki})
|
||||||
|
|
||||||
@@ -402,3 +387,155 @@ class Wiki2PageContentView(APIView):
|
|||||||
"seadoc_access_token": seadoc_access_token,
|
"seadoc_access_token": seadoc_access_token,
|
||||||
"assets_url": assets_url,
|
"assets_url": assets_url,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class Wiki2PagesView(APIView):
|
||||||
|
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||||
|
permission_classes = (IsAuthenticated, )
|
||||||
|
throttle_classes = (UserRateThrottle, )
|
||||||
|
|
||||||
|
def get_file_info(self, repo_id, file_path):
|
||||||
|
|
||||||
|
file_obj = seafile_api.get_dirent_by_path(repo_id, file_path)
|
||||||
|
if file_obj:
|
||||||
|
file_name = file_obj.obj_name
|
||||||
|
else:
|
||||||
|
file_name = os.path.basename(file_path.rstrip('/'))
|
||||||
|
|
||||||
|
file_info = {
|
||||||
|
'repo_id': repo_id,
|
||||||
|
'parent_dir': os.path.dirname(file_path),
|
||||||
|
'obj_name': file_name,
|
||||||
|
'mtime': timestamp_to_isoformat_timestr(file_obj.mtime) if file_obj else ''
|
||||||
|
}
|
||||||
|
|
||||||
|
return file_info
|
||||||
|
|
||||||
|
def post(self, request, wiki_id):
|
||||||
|
page_name = request.data.get('page_name', None)
|
||||||
|
|
||||||
|
if not page_name or '/' in page_name or '\\' in page_name:
|
||||||
|
error_msg = 'page_name invalid.'
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
try:
|
||||||
|
wiki = Wiki.objects.get(id=wiki_id)
|
||||||
|
except Wiki.DoesNotExist:
|
||||||
|
error_msg = "Wiki not found."
|
||||||
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
|
if not can_edit_wiki(wiki, request.user.username):
|
||||||
|
error_msg = 'Permission denied.'
|
||||||
|
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
|
||||||
|
repo_id = wiki.repo_id
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
sdoc_uuid = uuid.uuid4()
|
||||||
|
file_name = page_name + '.sdoc'
|
||||||
|
parent_dir = os.path.join(WIKI_PAGES_DIR, str(sdoc_uuid))
|
||||||
|
path = os.path.join(parent_dir, file_name)
|
||||||
|
|
||||||
|
seafile_api.mkdir_with_parents(repo_id, '/', parent_dir.strip('/'), request.user.username)
|
||||||
|
new_file_name = check_filename_with_rename(repo_id, parent_dir, file_name)
|
||||||
|
|
||||||
|
# create new empty file
|
||||||
|
if not is_valid_dirent_name(new_file_name):
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, 'name invalid.')
|
||||||
|
|
||||||
|
new_file_name = check_filename_with_rename(repo_id, parent_dir, new_file_name)
|
||||||
|
try:
|
||||||
|
seafile_api.post_empty_file(repo_id, parent_dir, new_file_name, request.user.username)
|
||||||
|
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)
|
||||||
|
|
||||||
|
new_file_path = posixpath.join(parent_dir, new_file_name)
|
||||||
|
file_info = self.get_file_info(repo_id, new_file_path)
|
||||||
|
file_info['doc_uuid'] = sdoc_uuid
|
||||||
|
filename = os.path.basename(path)
|
||||||
|
|
||||||
|
try:
|
||||||
|
FileUUIDMap.objects.create_fileuuidmap_by_uuid(sdoc_uuid, repo_id, parent_dir, filename, is_dir=False)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
error_msg = 'Internal Server Error'
|
||||||
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
|
||||||
|
return Response(file_info)
|
||||||
|
|
||||||
|
|
||||||
|
class Wiki2PageView(APIView):
|
||||||
|
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||||
|
permission_classes = (IsAuthenticated, )
|
||||||
|
throttle_classes = (UserRateThrottle, )
|
||||||
|
|
||||||
|
def delete(self, request, wiki_id, page_id):
|
||||||
|
try:
|
||||||
|
wiki = Wiki.objects.get(id=wiki_id)
|
||||||
|
except Wiki.DoesNotExist:
|
||||||
|
error_msg = "Wiki not found."
|
||||||
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
|
username = request.user.username
|
||||||
|
if not can_edit_wiki(wiki, username):
|
||||||
|
error_msg = 'Permission denied.'
|
||||||
|
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
|
||||||
|
repo_id = wiki.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)
|
||||||
|
|
||||||
|
wiki_config = get_wiki_config(repo_id, username)
|
||||||
|
pages = wiki_config.get('pages', [])
|
||||||
|
page_info = next(filter(lambda t: t['id'] == page_id, pages), {})
|
||||||
|
path = page_info.get('path')
|
||||||
|
|
||||||
|
# check file lock
|
||||||
|
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)
|
||||||
|
|
||||||
|
if is_locked and not locked_by_me:
|
||||||
|
error_msg = _("File is locked")
|
||||||
|
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
|
||||||
|
sdoc_dir_path = os.path.dirname(path)
|
||||||
|
parent_dir = os.path.dirname(sdoc_dir_path)
|
||||||
|
dir_name = os.path.basename(sdoc_dir_path)
|
||||||
|
|
||||||
|
# delete the folder where the sdoc is located
|
||||||
|
try:
|
||||||
|
seafile_api.del_file(repo_id, parent_dir, json.dumps([dir_name]), username)
|
||||||
|
except SearpcError as e:
|
||||||
|
logger.error(e)
|
||||||
|
error_msg = 'Internal Server Error'
|
||||||
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
|
||||||
|
try: # rm sdoc fileuuid
|
||||||
|
file_name = os.path.basename(path)
|
||||||
|
file_uuid = get_seadoc_file_uuid(repo, path)
|
||||||
|
FileComment.objects.filter(uuid=file_uuid).delete()
|
||||||
|
FileUUIDMap.objects.delete_fileuuidmap_by_path(repo_id, sdoc_dir_path, file_name, is_dir=False)
|
||||||
|
SeadocHistoryName.objects.filter(doc_uuid=file_uuid).delete()
|
||||||
|
SeadocDraft.objects.filter(doc_uuid=file_uuid).delete()
|
||||||
|
SeadocCommentReply.objects.filter(doc_uuid=file_uuid).delete()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
|
||||||
|
return Response({'success': True})
|
||||||
|
@@ -40,6 +40,11 @@ class FileUUIDMapManager(models.Manager):
|
|||||||
uuid.save(using=self._db)
|
uuid.save(using=self._db)
|
||||||
return uuid
|
return uuid
|
||||||
|
|
||||||
|
def create_fileuuidmap_by_uuid(self, file_uuid, repo_id, parent_path, filename, is_dir):
|
||||||
|
repo_id, parent_path = self.model.get_origin_repo_id_and_parent_path(repo_id, parent_path)
|
||||||
|
file_map = self.model(uuid=file_uuid, repo_id=repo_id, parent_path=parent_path, filename=filename, is_dir=is_dir)
|
||||||
|
file_map.save(using=self._db)
|
||||||
|
|
||||||
def get_fileuuidmap_by_path(self, repo_id, parent_path, filename, is_dir):
|
def get_fileuuidmap_by_path(self, repo_id, parent_path, filename, is_dir):
|
||||||
""" get filemap uuid by repoid、 parent_path 、 filename 、is_dir
|
""" get filemap uuid by repoid、 parent_path 、 filename 、is_dir
|
||||||
args:
|
args:
|
||||||
|
@@ -204,7 +204,8 @@ from seahub.ocm.settings import OCM_ENDPOINT
|
|||||||
from seahub.ai.apis import LibrarySdocIndexes, Search, LibrarySdocIndex, TaskStatus, \
|
from seahub.ai.apis import LibrarySdocIndexes, Search, LibrarySdocIndex, TaskStatus, \
|
||||||
LibraryIndexState, QuestionAnsweringSearchInLibrary, FileDownloadToken
|
LibraryIndexState, QuestionAnsweringSearchInLibrary, FileDownloadToken
|
||||||
from seahub.wiki2.views import wiki_view
|
from seahub.wiki2.views import wiki_view
|
||||||
from seahub.api2.endpoints.wiki2 import Wikis2View, Wiki2View, Wiki2ConfigView, Wiki2PagesDirView, Wiki2PageContentView
|
from seahub.api2.endpoints.wiki2 import Wikis2View, Wiki2View, Wiki2ConfigView, Wiki2PagesDirView, Wiki2PageContentView,\
|
||||||
|
Wiki2PagesView, Wiki2PageView
|
||||||
from seahub.api2.endpoints.subscription import SubscriptionView, SubscriptionPlansView, SubscriptionLogsView
|
from seahub.api2.endpoints.subscription import SubscriptionView, SubscriptionPlansView, SubscriptionLogsView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@@ -521,10 +522,12 @@ urlpatterns = [
|
|||||||
|
|
||||||
## user::wiki2
|
## user::wiki2
|
||||||
re_path(r'^api/v2.1/wikis2/$', Wikis2View.as_view(), name='api-v2.1-wikis2'),
|
re_path(r'^api/v2.1/wikis2/$', Wikis2View.as_view(), name='api-v2.1-wikis2'),
|
||||||
re_path(r'^api/v2.1/wikis2/(?P<wiki_id>\d+)/$', Wiki2View.as_view(), name='api-v2.1-wiki2'),
|
re_path(r'^api/v2.1/wiki2/(?P<wiki_id>\d+)/$', Wiki2View.as_view(), name='api-v2.1-wiki2'),
|
||||||
re_path(r'^api/v2.1/wikis2/(?P<wiki_id>\d+)/dir/$', Wiki2PagesDirView.as_view(), name='api-v2.1-wiki2-pages-dir'),
|
re_path(r'^api/v2.1/wiki2/(?P<wiki_id>\d+)/page-dir/$', Wiki2PagesDirView.as_view(), name='api-v2.1-wiki2-pages-dir'),
|
||||||
re_path(r'^api/v2.1/wiki2-config/(?P<wiki_id>\d+)/$', Wiki2ConfigView.as_view(), name='api-v2.1-wiki2-config'),
|
re_path(r'^api/v2.1/wiki2/(?P<wiki_id>\d+)/config/$', Wiki2ConfigView.as_view(), name='api-v2.1-wiki2-config'),
|
||||||
re_path(r'^api/v2.1/wikis2/(?P<wiki_id>\d+)/content/$', Wiki2PageContentView.as_view(), name='api-v2.1-wiki2-pages-content'),
|
re_path(r'^api/v2.1/wiki2/(?P<wiki_id>\d+)/content/$', Wiki2PageContentView.as_view(), name='api-v2.1-wiki2-pages-content'),
|
||||||
|
re_path(r'^api/v2.1/wiki2/(?P<wiki_id>\d+)/pages/$', Wiki2PagesView.as_view(), name='api-v2.1-wiki2-pages'),
|
||||||
|
re_path(r'^api/v2.1/wiki2/(?P<wiki_id>\d+)/page/(?P<page_id>[-0-9a-zA-Z]{4})/$', Wiki2PageView.as_view(), name='api-v2.1-wiki2-page'),
|
||||||
|
|
||||||
## user::drafts
|
## user::drafts
|
||||||
re_path(r'^api/v2.1/drafts/$', DraftsView.as_view(), name='api-v2.1-drafts'),
|
re_path(r'^api/v2.1/drafts/$', DraftsView.as_view(), name='api-v2.1-drafts'),
|
||||||
|
@@ -1,15 +1,25 @@
|
|||||||
# Copyright (c) 2012-2016 Seafile Ltd.
|
# Copyright (c) 2012-2016 Seafile Ltd.
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import re
|
import re
|
||||||
|
import os
|
||||||
import stat
|
import stat
|
||||||
import logging
|
import logging
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
import posixpath
|
||||||
|
|
||||||
from seaserv import seafile_api
|
from seaserv import seafile_api
|
||||||
from seahub.constants import PERMISSION_READ_WRITE
|
from seahub.constants import PERMISSION_READ_WRITE
|
||||||
|
from seahub.utils import gen_inner_file_get_url
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
WIKI_PAGES_DIR = '/wiki-pages'
|
||||||
|
WIKI_CONFIG_PATH = '_Internal/Wiki'
|
||||||
|
WIKI_CONFIG_FILE_NAME = 'index.json'
|
||||||
|
|
||||||
|
|
||||||
def is_valid_wiki_name(name):
|
def is_valid_wiki_name(name):
|
||||||
name = name.strip()
|
name = name.strip()
|
||||||
if len(name) > 255 or len(name) < 1:
|
if len(name) > 255 or len(name) < 1:
|
||||||
@@ -41,3 +51,13 @@ def get_wiki_dirs_by_path(repo_id, path, all_dirs):
|
|||||||
def can_edit_wiki(wiki, username):
|
def can_edit_wiki(wiki, username):
|
||||||
permission = seafile_api.check_permission_by_path(wiki.repo_id, '/', username)
|
permission = seafile_api.check_permission_by_path(wiki.repo_id, '/', username)
|
||||||
return permission == PERMISSION_READ_WRITE
|
return permission == PERMISSION_READ_WRITE
|
||||||
|
|
||||||
|
|
||||||
|
def get_wiki_config(repo_id, username):
|
||||||
|
config_path = posixpath.join(WIKI_CONFIG_PATH, WIKI_CONFIG_FILE_NAME)
|
||||||
|
file_id = seafile_api.get_file_id_by_path(repo_id, config_path)
|
||||||
|
token = seafile_api.get_fileserver_access_token(repo_id, file_id, 'download', username, use_onetime=True)
|
||||||
|
url = gen_inner_file_get_url(token, WIKI_CONFIG_FILE_NAME)
|
||||||
|
resp = requests.get(url)
|
||||||
|
wiki_config = json.loads(resp.content)
|
||||||
|
return wiki_config
|
||||||
|
Reference in New Issue
Block a user