mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-03 07:55:36 +00:00
@@ -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>
|
||||
);
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
}
|
||||
|
@@ -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>
|
||||
)}
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -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
|
||||
|
@@ -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">
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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:
|
||||
|
@@ -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())
|
||||
|
||||
|
@@ -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 }}",
|
||||
|
@@ -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()
|
||||
|
@@ -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,
|
||||
|
Reference in New Issue
Block a user