1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-03 07:55:36 +00:00

refactor wiki (#3289)

* refactor wiki

* refactor code
This commit is contained in:
ilearnit
2019-04-17 10:34:43 +08:00
committed by Daniel Pan
parent ff6ffb0f4c
commit b83197e2b0
15 changed files with 96 additions and 127 deletions

View File

@@ -17,13 +17,13 @@ class WikiDeleteDialog extends React.Component {
render() {
return (
<Modal isOpen={true}>
<ModalHeader toggle={this.toggle}>{gettext('Delete Wiki')}</ModalHeader>
<ModalHeader toggle={this.toggle}>{gettext('Unpublish Library')}</ModalHeader>
<ModalBody>
<p>{gettext('Are you sure you want to delete this wiki?')}</p>
<p>{gettext('Are you sure you want to unpublish this library?')}</p>
</ModalBody>
<ModalFooter>
<Button color="secondary" onClick={this.toggle}>{gettext('Cancel')}</Button>
<Button color="danger" onClick={this.props.handleSubmit}>{gettext('Delete')}</Button>
<Button color="danger" onClick={this.props.handleSubmit}>{gettext('Unpublish')}</Button>
</ModalFooter>
</Modal>
);

View File

@@ -18,8 +18,6 @@ class WikiSelectDialog extends React.Component {
super(props);
this.state = {
repos: [],
isExist: true,
name: '',
repoID: '',
};
}
@@ -43,8 +41,8 @@ class WikiSelectDialog extends React.Component {
}
handleSubmit = () => {
let { isExist, name, repoID } = this.state;
this.props.addWiki(isExist, name, repoID);
let { repoID } = this.state;
this.props.addWiki(repoID);
this.props.toggleCancel();
}
@@ -55,7 +53,7 @@ class WikiSelectDialog extends React.Component {
render() {
return (
<Modal isOpen={true}>
<ModalHeader toggle={this.toggle}>{gettext('Choose a library as Wiki')}</ModalHeader>
<ModalHeader toggle={this.toggle}>{gettext('Publish a library')}</ModalHeader>
<ModalBody className="dialog-list-container">
<table>
<thead>

View File

@@ -202,7 +202,7 @@ class MainSideNav extends React.Component {
<li className="nav-item">
<Link className={`nav-link ellipsis ${this.getActiveClass('wikis')}`} to={siteRoot + 'wikis/'} title={gettext('Wikis')} onClick={() => this.tabItemClick('wikis')}>
<span className="sf2-icon-wiki-view" aria-hidden="true"></span>
<span className="nav-text">{gettext('Wikis')}</span>
<span className="nav-text">{gettext('Published Libraries')}</span>
</Link>
</li>
}

View File

@@ -153,15 +153,6 @@ class WikiListItem extends Component {
</td>
<td><a href={userProfileURL} target='_blank'>{wiki.owner_nickname}</a></td>
<td>{moment(wiki.updated_at).fromNow()}</td>
<td>
<WikiPermissionEditor
isTextMode={true}
isEditIconShow={this.state.showOpIcon}
currentPermission={this.state.permission}
permissions={this.permissions}
onPermissionChanged={this.changePerm}
/>
</td>
<td className="text-center cursor-pointer">
{this.state.isShowMenuControl && (
<Dropdown isOpen={this.state.isShowWikiMenu} toggle={this.onMenuToggle}>
@@ -174,8 +165,7 @@ class WikiListItem extends Component {
onClick={this.clickMenuToggle}
/>
<DropdownMenu>
<DropdownItem onClick={this.onRenameToggle}>{gettext('Rename')}</DropdownItem>
<DropdownItem onClick={this.onDeleteToggle}>{gettext('Delete')}</DropdownItem>
<DropdownItem onClick={this.onDeleteToggle}>{gettext('Unpublish')}</DropdownItem>
</DropdownMenu>
</Dropdown>
)}

View File

@@ -38,10 +38,9 @@ class WikiListView extends Component {
<table>
<thead>
<tr>
<th width="35%">{gettext('Name')}</th>
<th width="20%">{gettext('Owner')}</th>
<th width="20%">{gettext('Last Update')}</th>
<th width="15%">{gettext('Permission')}</th>
<th width="40%">{gettext('Name')}</th>
<th width="25%">{gettext('Owner')}</th>
<th width="25%">{gettext('Last Update')}</th>
<th width="10%">{/* operation */}</th>
</tr>
</thead>

View File

@@ -79,7 +79,7 @@ class MainPanel extends Component {
<div className="cur-view-toolbar">
<span className="sf2-icon-menu hidden-md-up d-md-none side-nav-toggle" title="Side Nav Menu" onClick={this.onMenuClick}></span>
{this.props.permission === 'rw' && (
<button className="btn btn-secondary operation-item" title="Edit File" onClick={this.onEditClick}>{gettext('Edit Page')}</button>
<button className="btn btn-secondary operation-item" title="Edit" onClick={this.onEditClick}>{gettext('Edit')}</button>
)}
</div>
<CommonToolbar
@@ -93,12 +93,6 @@ class MainPanel extends Component {
<div className="main-panel-center">
<div className="cur-view-path">
<div className="path-containter">
{username &&
<Fragment>
<a href={siteRoot + 'wikis/'} className="normal">{gettext('Wikis')}</a>
<span className="path-split">/</span>
</Fragment>
}
<a href={siteRoot + 'wikis/' + slug} className="normal">{slug}</a>
{this.renderNavPath()}
</div>

View File

@@ -46,7 +46,7 @@ class SidePanel extends Component {
renderTreeView = () => {
return (
<Fragment>
<h3 className="wiki-pages-heading">{gettext('Pages')}</h3>
<h3 className="wiki-pages-heading">{gettext('Contents')}</h3>
<div className="wiki-pages-container">
{this.props.treeData && (
<TreeView

View File

@@ -1,5 +1,5 @@
import React, { Component, Fragment } from 'react';
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
import { Button } from 'reactstrap';
import { seafileAPI } from '../../utils/seafile-api';
import { gettext, loginUrl } from '../../utils/constants';
import toaster from '../../components/toast';
@@ -73,8 +73,8 @@ class Wikis extends Component {
this.setState({isShowCreateDialog: !this.state.isShowCreateDialog});
}
addWiki = (isExist, name, repoID) => {
seafileAPI.addWiki(isExist, name, repoID).then((res) => {
addWiki = (repoID) => {
seafileAPI.addWiki(repoID).then((res) => {
this.state.wikis.push(res.data);
this.setState({wikis: this.state.wikis});
}).catch((error) => {
@@ -123,15 +123,9 @@ class Wikis extends Component {
<div className="cur-view-toolbar">
<span className="sf2-icon-menu side-nav-toggle hidden-md-up d-md-none" title="Side Nav Menu" onClick={this.props.onShowSidePanel}></span>
<div className="operation">
<Dropdown tag="div" isOpen={this.state.isShowAddWikiMenu} toggle={this.onMenuToggle}>
<DropdownToggle className="btn btn-secondary operation-item">
<i className="fa fa-plus-square text-secondary mr-1"></i>{gettext('Add Wiki')}
</DropdownToggle>
<DropdownMenu>
<DropdownItem onClick={this.onCreateToggle}>{gettext('New Wiki')}</DropdownItem>
<DropdownItem onClick={this.onSelectToggle}>{gettext('Choose a library as Wiki')}</DropdownItem>
</DropdownMenu>
</Dropdown>
<Button className="btn btn-secondary operation-item" onClick={this.onSelectToggle}>
<i className="fa fa-plus-square text-secondary mr-1"></i>{gettext('Publish a Library')}
</Button>
</div>
</div>
<CommonToolbar onSearchedClick={this.props.onSearchedClick} />
@@ -140,7 +134,7 @@ class Wikis extends Component {
<div className="cur-view-container" id="wikis">
<div className="cur-view-path">
<div className="path-container">
<h3 className="sf-heading">{gettext('Wikis')}</h3>
<h3 className="sf-heading">{gettext('Published Libraries')}</h3>
</div>
</div>
<div className="cur-view-content">

View File

@@ -56,6 +56,8 @@ export const permission = window.wiki ? window.wiki.config.permission === 'True'
export const isDir = window.wiki ? window.wiki.config.isDir : '';
export const serviceUrl = window.wiki ? window.wiki.config.serviceUrl : '';
export const isPublicWiki = window.wiki ? window.wiki.config.isPublicWiki === 'True': '';
export const sharedToken = window.wiki ? window.wiki.config.sharedToken : '';
export const sharedType = window.wiki ? window.wiki.config.sharedType : '';
// file history
export const PER_PAGE = 25;

View File

@@ -1,7 +1,7 @@
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import moment from 'moment';
import { slug, repoID, siteRoot, initialPath, isDir } from './utils/constants';
import { slug, repoID, siteRoot, initialPath, isDir, sharedToken } from './utils/constants';
import { Utils } from './utils/utils';
import { seafileAPI } from './utils/seafile-api';
import Dirent from './models/dirent';
@@ -270,7 +270,7 @@ class Wiki extends Component {
if (Utils.isMarkdownFile(path)) {
this.showFile(path);
} else {
let url = siteRoot + 'lib/' + item.repo_id + '/file' + Utils.encodePath(path);
let url = siteRoot + 'd/' + sharedToken + '/files/?p=' + Utils.encodePath(path);
let newWindow = window.open('about:blank');
newWindow.location.href = url;
}
@@ -285,7 +285,6 @@ class Wiki extends Component {
let tree = this.state.treeData.clone();
let node = tree.getNodeByPath(nodePath);
tree.expandNode(node);
this.setState({treeData: tree, currentNode: node});
this.showDir(node.path);
}
@@ -300,7 +299,7 @@ class Wiki extends Component {
this.showFile(direntPath);
} else {
const w=window.open('about:blank');
const url = siteRoot + 'lib/' + repoID + '/file' + Utils.encodePath(direntPath);
const url = siteRoot + 'd/' + sharedToken + '/files/?p=' + Utils.encodePath(direntPath);
w.location.href = url;
}
}
@@ -351,7 +350,7 @@ class Wiki extends Component {
}
} else {
const w = window.open('about:blank');
const url = siteRoot + 'lib/' + repoID + '/file' + Utils.encodePath(node.path);
const url = siteRoot + 'd/' + sharedToken + '/files/?p=' + Utils.encodePath(node.path);
w.location.href = url;
}
}

View File

@@ -38,6 +38,7 @@ from seahub.settings import SHARE_LINK_EXPIRE_DAYS_MAX, \
SHARE_LINK_EXPIRE_DAYS_MIN, SHARE_LINK_LOGIN_REQUIRED, \
ENABLE_SHARE_LINK_AUDIT, ENABLE_VIDEO_THUMBNAIL, \
THUMBNAIL_ROOT
from seahub.wiki.models import Wiki
logger = logging.getLogger(__name__)
@@ -366,11 +367,23 @@ class ShareLink(APIView):
except FileShare.DoesNotExist:
return Response({'success': True})
has_published_library = False
if fs.path == '/':
try:
Wiki.objects.get(repo_id=fs.repo_id)
has_published_library = True
except Wiki.DoesNotExist:
pass
username = request.user.username
if not fs.is_owner(username):
error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
if has_published_library:
error_msg = 'This is an associated published library.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
try:
fs.delete()
except Exception as e:

View File

@@ -9,7 +9,6 @@ from rest_framework.response import Response
from rest_framework.views import APIView
from seaserv import seafile_api, edit_repo
from pysearpc import SearpcError
from django.core.urlresolvers import reverse
from django.db import IntegrityError
from django.db.models import Count
from django.http import HttpResponse
@@ -24,6 +23,7 @@ from seahub.utils import is_org_context, get_user_repos
from seahub.utils.repo import is_group_repo_staff, is_repo_owner
from seahub.views import check_folder_permission
from seahub.share.utils import is_repo_admin
from seahub.share.models import FileShare
logger = logging.getLogger(__name__)
@@ -79,49 +79,12 @@ class WikisView(APIView):
def post(self, request, format=None):
"""Add a new wiki.
"""
use_exist_repo = request.POST.get('use_exist_repo', '')
if not use_exist_repo:
msg = 'Use exist repo is invalid'
return api_error(status.HTTP_400_BAD_REQUEST, msg)
name = request.POST.get('name', '')
if not name:
msg = 'Name is invalid'
return api_error(status.HTTP_400_BAD_REQUEST, msg)
if not is_valid_wiki_name(name):
msg = _('Name can only contain letters, numbers, blank, hyphen or underscore.')
return api_error(status.HTTP_400_BAD_REQUEST, msg)
username = request.user.username
org_id = -1
if is_org_context(request):
org_id = request.user.org.org_id
if use_exist_repo == 'false':
try:
wiki = Wiki.objects.add(name, username, org_id=org_id)
except DuplicateWikiNameError:
msg = _('%s is taken by others, please try another name.') % name
return api_error(status.HTTP_400_BAD_REQUEST, msg)
except IntegrityError:
msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, msg)
# create home page
page_name = "home.md"
try:
seafile_api.post_empty_file(wiki.repo_id, '/',
page_name, request.user.username)
except SearpcError as e:
logger.error(e)
msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, msg)
return Response(wiki.to_dict())
if use_exist_repo == 'true':
repo_id = request.POST.get('repo_id', '')
if not repo_id:
msg = 'Repo id is invalid.'
@@ -147,7 +110,7 @@ class WikisView(APIView):
try:
wiki = Wiki.objects.add(wiki_name=repo.repo_name, username=username,
repo_id=repo.repo_id, org_id=org_id)
repo_id=repo.repo_id, org_id=org_id, permission='public')
except DuplicateWikiNameError:
msg = _('%s is taken by others, please try another name.') % repo.repo_name
return api_error(status.HTTP_400_BAD_REQUEST, msg)
@@ -165,6 +128,10 @@ class WikisView(APIView):
msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, msg)
fs = FileShare.objects.get_dir_link_by_path(username, repo_id, '/')
if not fs:
fs = FileShare.objects.create_dir_link(username, repo_id, '/',
permission='view_download', org_id=org_id)
return Response(wiki.to_dict())

View File

@@ -10,6 +10,8 @@
config: {
slug: "{{ wiki.slug }}",
repoId: "{{ wiki.repo_id }}",
sharedToken: "{{ shared_token }}",
sharedType: "{{ shared_type }}",
initial_path: "{{ file_path|escapejs }}",
permission: "{{ user_can_write }}",
isPublicWiki: "{{ is_public_wiki }}",

View File

@@ -160,3 +160,9 @@ def remove_personal_wiki(sender, **kwargs):
repo_id = kwargs['repo_id']
PersonalWiki.objects.filter(username=repo_owner, repo_id=repo_id).delete()
@receiver(repo_deleted)
def remove_wiki(sender, **kwargs):
repo_id = kwargs['repo_id']
Wiki.objects.filter(repo_id=repo_id).delete()

View File

@@ -12,6 +12,7 @@ from django.utils.translation import ugettext as _
from seahub.auth.decorators import login_required
from seahub.base.decorators import user_mods_check
from seahub.share.models import FileShare
from seahub.wiki.models import Wiki
from seahub.views import check_folder_permission
from seahub.utils import get_service_url, get_file_type_and_ext, render_permission_error
@@ -88,9 +89,13 @@ def slug(request, slug, file_path="home.md"):
if wiki.permission == 'public':
is_public_wiki = True
fs = FileShare.objects.get(repo_id=wiki.repo_id, path='/')
return render(request, "wiki/wiki.html", {
"wiki": wiki,
"page_name": file_path,
"shared_token": fs.token,
"shared_type": fs.s_type,
"user_can_write": user_can_write,
"file_path": file_path,
"repo_id": wiki.repo_id,