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

share wiki (#6413)

* share wiki

update leave and return

update get group info

* format optimize

* Update wikis.js

* Update wiki2.py

* fix empty group_wikis

* update

* remove-useless-code

* add-owner-nickname

* Update wiki2.py

* Update wiki2.py

* Update wiki2.py

---------

Co-authored-by: 孙永强 <11704063+s-yongqiang@user.noreply.gitee.com>
Co-authored-by: r350178982 <32759763+r350178982@users.noreply.github.com>
This commit is contained in:
awu0403
2024-07-25 17:28:55 +08:00
committed by GitHub
parent aa477190f2
commit 9d227661b3
14 changed files with 597 additions and 122 deletions

View File

@@ -113,6 +113,7 @@ const propTypes = {
itemPath: PropTypes.string.isRequired, itemPath: PropTypes.string.isRequired,
itemType: PropTypes.string.isRequired, itemType: PropTypes.string.isRequired,
repoID: PropTypes.string.isRequired, repoID: PropTypes.string.isRequired,
repoType: PropTypes.string.isRequired,
isRepoOwner: PropTypes.bool.isRequired, isRepoOwner: PropTypes.bool.isRequired,
onAddCustomPermissionToggle: PropTypes.func, onAddCustomPermissionToggle: PropTypes.func,
}; };
@@ -126,7 +127,8 @@ class ShareToGroup extends React.Component {
selectedOption: null, selectedOption: null,
errorMsg: [], errorMsg: [],
permission: 'rw', permission: 'rw',
sharedItems: [] sharedItems: [],
isWiki: this.props.repoType === 'wiki'
}; };
this.permissions = []; this.permissions = [];
let { itemType, isRepoOwner } = props; let { itemType, isRepoOwner } = props;
@@ -141,6 +143,9 @@ class ShareToGroup extends React.Component {
if (this.props.isGroupOwnedRepo) { if (this.props.isGroupOwnedRepo) {
this.permissions = ['rw', 'r', 'cloud-edit', 'preview']; this.permissions = ['rw', 'r', 'cloud-edit', 'preview'];
} }
if (this.state.isWiki) {
this.permissions = ['rw', 'r'];
}
} }
handleSelectChange = (option) => { handleSelectChange = (option) => {
@@ -344,6 +349,7 @@ class ShareToGroup extends React.Component {
permissions={this.permissions} permissions={this.permissions}
onPermissionChanged={this.setPermission} onPermissionChanged={this.setPermission}
enableAddCustomPermission={isPro} enableAddCustomPermission={isPro}
isWiki={this.state.isWiki}
onAddCustomPermissionToggle={this.props.onAddCustomPermissionToggle} onAddCustomPermissionToggle={this.props.onAddCustomPermissionToggle}
/> />
</td> </td>

View File

@@ -154,6 +154,7 @@ const propTypes = {
itemType: PropTypes.string.isRequired, itemType: PropTypes.string.isRequired,
repoID: PropTypes.string.isRequired, repoID: PropTypes.string.isRequired,
isRepoOwner: PropTypes.bool.isRequired, isRepoOwner: PropTypes.bool.isRequired,
repoType: PropTypes.string.isRequired,
onAddCustomPermissionToggle: PropTypes.func, onAddCustomPermissionToggle: PropTypes.func,
}; };
@@ -165,7 +166,8 @@ class ShareToUser extends React.Component {
selectedOption: null, selectedOption: null,
errorMsg: [], errorMsg: [],
permission: 'rw', permission: 'rw',
sharedItems: [] sharedItems: [],
isWiki: this.props.repoType === 'wiki'
}; };
this.options = []; this.options = [];
this.permissions = []; this.permissions = [];
@@ -181,6 +183,9 @@ class ShareToUser extends React.Component {
if (this.props.isGroupOwnedRepo) { if (this.props.isGroupOwnedRepo) {
this.permissions = ['rw', 'r', 'cloud-edit', 'preview']; this.permissions = ['rw', 'r', 'cloud-edit', 'preview'];
} }
if (this.state.isWiki) {
this.permissions = ['rw', 'r'];
}
} }
handleSelectChange = (option) => { handleSelectChange = (option) => {
@@ -370,6 +375,7 @@ class ShareToUser extends React.Component {
permissions={this.permissions} permissions={this.permissions}
onPermissionChanged={this.setPermission} onPermissionChanged={this.setPermission}
enableAddCustomPermission={isPro} enableAddCustomPermission={isPro}
isWiki={this.state.isWiki}
onAddCustomPermissionToggle={this.props.onAddCustomPermissionToggle} onAddCustomPermissionToggle={this.props.onAddCustomPermissionToggle}
/> />
</td> </td>

View File

@@ -0,0 +1,174 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { Modal, ModalHeader, ModalBody, TabContent, TabPane, Nav, NavItem, NavLink } from 'reactstrap';
import { gettext, username, additionalShareDialogNote, canShareRepo } from '../../utils/constants';
import ShareToUser from './share-to-user';
import ShareToGroup from './share-to-group';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
import Loading from '../loading';
import toaster from '../toast';
import '../../css/share-link-dialog.css';
const propTypes = {
isGroupOwnedRepo: PropTypes.bool,
itemType: PropTypes.string.isRequired, // there will be three choose: ['library', 'dir', 'file']
itemName: PropTypes.string.isRequired,
itemPath: PropTypes.string.isRequired,
toggleDialog: PropTypes.func.isRequired,
repoID: PropTypes.string.isRequired,
repoEncrypted: PropTypes.bool,
enableDirPrivateShare: PropTypes.bool,
};
class ShareWikiDialog extends React.Component {
constructor(props) {
super(props);
this.state = {
activeTab: 'shareToUser',
isRepoJudgemented: false,
isRepoOwner: false,
isGroupOwnedRepo: false,
};
}
componentDidMount() {
let repoID = this.props.repoID;
seafileAPI.getRepoInfo(repoID).then(res => {
const isGroupOwnedRepo = res.data.owner_email.indexOf('@seafile_group') > -1;
let isRepoOwner = res.data.owner_email === username;
this.setState({
isRepoJudgemented: true,
isRepoOwner: isRepoOwner,
repoType: res.data.repo_type,
isGroupOwnedRepo: isGroupOwnedRepo,
});
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
}
toggle = (tab) => {
if (this.state.activeTab !== tab) {
this.setState({ activeTab: tab });
}
};
onAddCustomPermissionToggle = () => {
this.toggle('customSharePermission');
};
renderDirContent = () => {
if (!this.state.isRepoJudgemented) {
return <Loading />;
}
let activeTab = this.state.activeTab;
let { repoEncrypted, enableDirPrivateShare, itemType } = this.props;
if (repoEncrypted) {
enableDirPrivateShare = itemType == 'library';
}
return (
<Fragment>
<div className="share-dialog-side">
<Nav pills>
{enableDirPrivateShare &&
<Fragment>
{ canShareRepo && (
<NavItem role="tab" aria-selected={activeTab === 'shareToUser'} aria-controls="share-to-user-panel">
<NavLink className={activeTab === 'shareToUser' ? 'active' : ''} onClick={this.toggle.bind(this, 'shareToUser')} tabIndex="0" onKeyDown={this.onTabKeyDown}>
{gettext('Share to user')}
</NavLink>
</NavItem>
)}
{ canShareRepo && (
<NavItem role="tab" aria-selected={activeTab === 'shareToGroup'} aria-controls="share-to-group-panel">
<NavLink className={activeTab === 'shareToGroup' ? 'active' : ''} onClick={this.toggle.bind(this, 'shareToGroup')} tabIndex="0" onKeyDown={this.onTabKeyDown}>
{gettext('Share to group')}
</NavLink>
</NavItem>
)}
</Fragment>
}
</Nav>
</div>
<div className="share-dialog-main">
<TabContent activeTab={this.state.activeTab}>
{enableDirPrivateShare &&
<Fragment>
{(activeTab === 'shareToUser' && canShareRepo) &&
<TabPane tabId="shareToUser" role="tabpanel" id="share-to-user-panel">
<ShareToUser
itemType={this.props.itemType}
isGroupOwnedRepo={this.state.isGroupOwnedRepo}
itemPath={this.props.itemPath}
repoID={this.props.repoID}
isRepoOwner={this.state.isRepoOwner}
repoType={this.state.repoType}
onAddCustomPermissionToggle={this.onAddCustomPermissionToggle}
/>
</TabPane>
}
{(activeTab === 'shareToGroup' && canShareRepo) &&
<TabPane tabId="shareToGroup" role="tabpanel" id="share-to-group-panel">
<ShareToGroup
itemType={this.props.itemType}
isGroupOwnedRepo={this.state.isGroupOwnedRepo}
itemPath={this.props.itemPath}
repoID={this.props.repoID}
isRepoOwner={this.state.isRepoOwner}
repoType={this.state.repoType}
onAddCustomPermissionToggle={this.onAddCustomPermissionToggle}
/>
</TabPane>
}
</Fragment>
}
</TabContent>
</div>
</Fragment>
);
};
onTabKeyDown = (e) => {
if (e.key == 'Enter' || e.key == 'Space') {
e.target.click();
}
};
renderExternalShareMessage = () => {
if (additionalShareDialogNote && (typeof additionalShareDialogNote) === 'object') {
return (
<div className="external-share-message mt-2">
<h6>{additionalShareDialogNote.title}</h6>
<p style={{ fontSize: '14px', color: '#666' }} className="text-wrap m-0">{additionalShareDialogNote.content}</p>
</div>
);
}
return null;
};
render() {
const { itemType, itemName } = this.props;
return (
<div>
<Modal isOpen={true} style={{ maxWidth: '760px' }} className="share-dialog" toggle={this.props.toggleDialog}>
<ModalHeader toggle={this.props.toggleDialog} tag="div">
<h5 className="text-truncate">{gettext('Share')} <span className="op-target" title={itemName}>{itemName}</span></h5>
{this.renderExternalShareMessage()}
</ModalHeader>
<ModalBody className="share-dialog-content" role="tablist">
{(itemType === 'library') && this.renderDirContent()}
</ModalBody>
</Modal>
</div>
);
}
}
ShareWikiDialog.propTypes = propTypes;
export default ShareWikiDialog;

View File

@@ -9,6 +9,7 @@ const propTypes = {
isTextMode: PropTypes.bool.isRequired, // there will be two mode. first: text and select. second: just select isTextMode: PropTypes.bool.isRequired, // there will be two mode. first: text and select. second: just select
isEditing: PropTypes.bool, isEditing: PropTypes.bool,
isEditIconShow: PropTypes.bool.isRequired, isEditIconShow: PropTypes.bool.isRequired,
isWiki: PropTypes.bool,
autoFocus: PropTypes.bool, autoFocus: PropTypes.bool,
options: PropTypes.array.isRequired, options: PropTypes.array.isRequired,
currentOption: PropTypes.string.isRequired, currentOption: PropTypes.string.isRequired,
@@ -56,7 +57,7 @@ class SelectEditor extends React.Component {
} }
const { enableAddCustomPermission } = this.props; const { enableAddCustomPermission } = this.props;
if (enableAddCustomPermission) { if (enableAddCustomPermission && !this.props.isWiki) {
const option = { const option = {
value: gettext('Add custom permission'), value: gettext('Add custom permission'),
isDisabled: true, isDisabled: true,

View File

@@ -11,6 +11,7 @@ const propTypes = {
repoID: PropTypes.string, repoID: PropTypes.string,
isTextMode: PropTypes.bool.isRequired, isTextMode: PropTypes.bool.isRequired,
isEditing: PropTypes.bool, isEditing: PropTypes.bool,
isWiki: PropTypes.bool,
autoFocus: PropTypes.bool, autoFocus: PropTypes.bool,
isEditIconShow: PropTypes.bool.isRequired, isEditIconShow: PropTypes.bool.isRequired,
permissions: PropTypes.array.isRequired, permissions: PropTypes.array.isRequired,
@@ -136,6 +137,7 @@ class SharePermissionEditor extends React.Component {
translateOption={this.translatePermission} translateOption={this.translatePermission}
translateExplanation={this.translateExplanation} translateExplanation={this.translateExplanation}
enableAddCustomPermission={this.props.enableAddCustomPermission} enableAddCustomPermission={this.props.enableAddCustomPermission}
isWiki={this.props.isWiki}
onAddCustomPermissionToggle={this.props.onAddCustomPermissionToggle} onAddCustomPermissionToggle={this.props.onAddCustomPermissionToggle}
/> />
); );

View File

@@ -7,7 +7,9 @@ import { SIDE_PANEL_FOLDED_WIDTH } from '../../constants';
const propTypes = { const propTypes = {
wikis: PropTypes.array.isRequired, wikis: PropTypes.array.isRequired,
group: PropTypes.object,
deleteWiki: PropTypes.func.isRequired, deleteWiki: PropTypes.func.isRequired,
unshareGroupWiki: PropTypes.func.isRequired,
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired,
isDepartment: PropTypes.bool.isRequired, isDepartment: PropTypes.bool.isRequired,
isShowAvatar: PropTypes.bool.isRequired, isShowAvatar: PropTypes.bool.isRequired,
@@ -48,23 +50,39 @@ class WikiCardGroup extends Component {
}; };
render() { render() {
const { wikis, title, isDepartment, toggelAddWikiDialog } = this.props; const { wikis, title, isDepartment, toggelAddWikiDialog, group } = this.props;
const containerWidth = this.getContainerWidth(); const containerWidth = this.getContainerWidth();
const numberOfWiki = Math.floor(containerWidth / 180); const numberOfWiki = Math.floor(containerWidth / 180);
const grids = (Math.floor((containerWidth - (numberOfWiki + 1) * 16) / numberOfWiki) + 'px ').repeat(numberOfWiki); const grids = (Math.floor((containerWidth - (numberOfWiki + 1) * 16) / numberOfWiki) + 'px ').repeat(numberOfWiki);
let isGroup = false;
let depIcon = false;
if (group) {
isGroup = true;
depIcon = group.owner === 'system admin';
}
return ( return (
<div className='wiki-card-group mb-4'> <div className='wiki-card-group mb-4'>
<h4 className="sf-heading"> <h4 className="sf-heading">
<span className={`sf3-font nav-icon sf3-font-${isDepartment ? 'department' : 'mine'}`} aria-hidden="true"></span> <span className={`sf3-font nav-icon sf3-font-${(isDepartment && depIcon) ? 'department' : isDepartment ? 'group' : 'mine'}`} aria-hidden="true"></span>
{title} {title}
</h4> </h4>
<div className='wiki-card-group-items' style={{ gridTemplateColumns: isMobile ? '48% 48%' : grids }} ref={this.groupItemsRef}> <div className='wiki-card-group-items' style={{ gridTemplateColumns: isMobile ? '48% 48%' : grids }} ref={this.groupItemsRef}>
{wikis.map((wiki, index) => { {wikis.map((wiki, index) => {
return ( return (isGroup ?
<WikiCardItem <WikiCardItem
key={index + wiki.id + wiki.name}
group={group}
wiki={wiki}
deleteWiki={this.props.deleteWiki}
unshareGroupWiki={this.props.unshareGroupWiki}
isDepartment={isDepartment}
isShowAvatar={this.props.isShowAvatar}
renameWiki={this.props.renameWiki}
/> : <WikiCardItem
key={index + wiki.id + wiki.name} key={index + wiki.id + wiki.name}
wiki={wiki} wiki={wiki}
deleteWiki={this.props.deleteWiki} deleteWiki={this.props.deleteWiki}
unshareGroupWiki={this.props.unshareGroupWiki}
isDepartment={isDepartment} isDepartment={isDepartment}
isShowAvatar={this.props.isShowAvatar} isShowAvatar={this.props.isShowAvatar}
renameWiki={this.props.renameWiki} renameWiki={this.props.renameWiki}

View File

@@ -2,14 +2,17 @@ import React, { Component } from 'react';
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap'; import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import moment from 'moment'; import moment from 'moment';
import { siteRoot, gettext } from '../../utils/constants'; import { siteRoot, gettext, username } from '../../utils/constants';
import ModalPortal from '../modal-portal'; import ModalPortal from '../modal-portal';
import DeleteWikiDialog from '../dialog/delete-wiki-dialog'; import DeleteWikiDialog from '../dialog/delete-wiki-dialog';
import RenameWikiDialog from '../dialog/rename-wiki-dialog'; import RenameWikiDialog from '../dialog/rename-wiki-dialog';
import ShareWikiDialog from '../dialog/share-wiki-dialog';
const propTypes = { const propTypes = {
wiki: PropTypes.object.isRequired, wiki: PropTypes.object.isRequired,
group: PropTypes.object,
deleteWiki: PropTypes.func.isRequired, deleteWiki: PropTypes.func.isRequired,
unshareGroupWiki: PropTypes.func.isRequired,
renameWiki: PropTypes.func.isRequired, renameWiki: PropTypes.func.isRequired,
isDepartment: PropTypes.bool.isRequired, isDepartment: PropTypes.bool.isRequired,
isShowAvatar: PropTypes.bool.isRequired, isShowAvatar: PropTypes.bool.isRequired,
@@ -22,6 +25,7 @@ class WikiCardItem extends Component {
isShowDeleteDialog: false, isShowDeleteDialog: false,
isShowRenameDialog: false, isShowRenameDialog: false,
isItemMenuShow: false, isItemMenuShow: false,
isShowShareDialog: false,
}; };
} }
@@ -31,6 +35,12 @@ class WikiCardItem extends Component {
}); });
}; };
onShareToggle = (e) => {
this.setState({
isShowShareDialog: !this.state.isShowShareDialog,
});
};
onDeleteToggle = (e) => { onDeleteToggle = (e) => {
e.preventDefault(); e.preventDefault();
this.setState({ this.setState({
@@ -52,6 +62,14 @@ class WikiCardItem extends Component {
}); });
}; };
onItemUnshare = () => {
let wiki = this.props.wiki;
this.props.unshareGroupWiki(wiki, this.props.group.group_id);
this.setState({
isShowDeleteDialog: !this.state.isShowDeleteDialog,
});
};
renameWiki = (newName) => { renameWiki = (newName) => {
if (this.props.wiki.name !== newName) { if (this.props.wiki.name !== newName) {
this.props.renameWiki(this.props.wiki, newName); this.props.renameWiki(this.props.wiki, newName);
@@ -94,10 +112,49 @@ class WikiCardItem extends Component {
render() { render() {
const { wiki, isDepartment, isShowAvatar } = this.props; const { wiki, isDepartment, isShowAvatar } = this.props;
let isAdmin = false;
if (wiki.admins) {
isAdmin = wiki.admins.includes(username);
}
let isGroupOwner = false;
if (this.props.group) {
isGroupOwner = wiki.owner.split('@')[0] === this.props.group.group_id.toString();
}
let isWikiOwner = username === wiki.owner;
let isOldVersion = wiki.version !== 'v2'; let isOldVersion = wiki.version !== 'v2';
let publishedUrl = `${siteRoot}published/${encodeURIComponent(wiki.slug)}/`; let publishedUrl = `${siteRoot}published/${encodeURIComponent(wiki.slug)}/`;
let editUrl = `${siteRoot}wikis/${wiki.id}/`; let editUrl = `${siteRoot}wikis/${wiki.id}/`;
let wikiName = isOldVersion ? `${wiki.name} (old version)` : wiki.name; let wikiName = isOldVersion ? `${wiki.name} (old version)` : wiki.name;
let showRename = false;
let showShare = false;
let showDelete = false;
let showLeaveShare = false;
let showDropdownMenu = false;
if (isDepartment) {
if (isAdmin) {
if (isGroupOwner) {
showDelete = true;
showShare = true;
showRename = true;
} else {
showLeaveShare = true;
}
}
} else {
if (isAdmin || isWikiOwner) {
showShare = true;
showDelete = true;
showRename = true;
} else {
showLeaveShare = true;
}
}
if (isOldVersion || showRename || showShare || showDelete || showLeaveShare) {
showDropdownMenu = true;
}
return ( return (
<> <>
<div <div
@@ -106,6 +163,7 @@ class WikiCardItem extends Component {
> >
<div className="wiki-card-item-top"> <div className="wiki-card-item-top">
<span className="sf3-font-wiki sf3-font" aria-hidden="true"></span> <span className="sf3-font-wiki sf3-font" aria-hidden="true"></span>
{showDropdownMenu &&
<Dropdown isOpen={this.state.isItemMenuShow} toggle={this.toggleDropDownMenu} onClick={this.onClickDropdown}> <Dropdown isOpen={this.state.isItemMenuShow} toggle={this.toggleDropDownMenu} onClick={this.onClickDropdown}>
<DropdownToggle <DropdownToggle
tag="i" tag="i"
@@ -120,14 +178,23 @@ class WikiCardItem extends Component {
style={{ 'minWidth': '0' }} style={{ 'minWidth': '0' }}
/> />
<DropdownMenu right={true} className="dtable-dropdown-menu"> <DropdownMenu right={true} className="dtable-dropdown-menu">
<DropdownItem onClick={this.onRenameToggle}>{gettext('Rename')}</DropdownItem> {showRename &&
{isOldVersion ? <DropdownItem onClick={this.onRenameToggle}>{gettext('Rename')}</DropdownItem>}
{showShare &&
<DropdownItem onClick={this.onShareToggle}>{gettext('Share')}</DropdownItem>
}
{isOldVersion &&
<DropdownItem onClick={this.onDeleteToggle}>{gettext('Unpublish')}</DropdownItem> <DropdownItem onClick={this.onDeleteToggle}>{gettext('Unpublish')}</DropdownItem>
: }
{showDelete &&
<DropdownItem onClick={this.onDeleteToggle}>{gettext('Delete')}</DropdownItem> <DropdownItem onClick={this.onDeleteToggle}>{gettext('Delete')}</DropdownItem>
} }
{showLeaveShare &&
<DropdownItem onClick={this.onDeleteToggle}>{gettext('Leave')}</DropdownItem>
}
</DropdownMenu> </DropdownMenu>
</Dropdown> </Dropdown>
}
</div> </div>
<div className="wiki-item-name text-truncate" title={wikiName} aria-label={wikiName}>{wikiName}</div> <div className="wiki-item-name text-truncate" title={wikiName} aria-label={wikiName}>{wikiName}</div>
<div className="wiki-item-owner"> <div className="wiki-item-owner">
@@ -137,22 +204,41 @@ class WikiCardItem extends Component {
</div> </div>
{this.state.isShowDeleteDialog && {this.state.isShowDeleteDialog &&
<ModalPortal> <ModalPortal>
{isOldVersion ? {isOldVersion &&
<DeleteWikiDialog <DeleteWikiDialog
toggleCancel={this.onDeleteCancel} toggleCancel={this.onDeleteCancel}
handleSubmit={this.deleteWiki} handleSubmit={this.deleteWiki}
title={gettext('Unpublish Wiki')} title={gettext('Unpublish Wiki')}
content={<p>{gettext('Are you sure you want to unpublish Wiki')}{' '}<b>{wiki.name}</b> ?</p>} content={<p>{gettext('Are you sure you want to unpublish Wiki')}{' '}<b>{wiki.name}</b> ?</p>}
footer={gettext('Unpublish')} footer={gettext('Unpublish')}
/> />}
: {(isDepartment && isGroupOwner) ?
<DeleteWikiDialog <DeleteWikiDialog
toggleCancel={this.onDeleteCancel} toggleCancel={this.onDeleteCancel}
handleSubmit={this.deleteWiki} handleSubmit={this.deleteWiki}
title={gettext('Delete Wiki')} title={gettext('Delete Wiki')}
content={<p>{gettext('Are you sure you want to delete Wiki')}{' '}<b>{wiki.name}</b> ?</p>} content={<p>{gettext('Are you sure you want to delete Wiki')}{' '}<b>{wiki.name}</b> ?</p>}
footer={gettext('Delete')} footer={gettext('Delete')}
/> : isDepartment ? <DeleteWikiDialog
toggleCancel={this.onDeleteCancel}
handleSubmit={this.onItemUnshare}
title={gettext('Leave Share Wiki')}
content={<p>{gettext('Are you sure you want to leave share Wiki')}{' '}<b>{wiki.name}</b> ?</p>}
footer={gettext('Leave')}
/> : (isWikiOwner ? <DeleteWikiDialog
toggleCancel={this.onDeleteCancel}
handleSubmit={this.deleteWiki}
title={gettext('Delete Wiki')}
content={<p>{gettext('Are you sure you want to delete Wiki')}{' '}<b>{wiki.name}</b> ?</p>}
footer={gettext('Delete')}
/> : <DeleteWikiDialog
toggleCancel={this.onDeleteCancel}
handleSubmit={this.deleteWiki}
title={gettext('Leave Share Wiki')}
content={<p>{gettext('Are you sure you want to leave share Wiki')}{' '}<b>{wiki.name}</b> ?</p>}
footer={gettext('Leave')}
/> />
)
} }
</ModalPortal> </ModalPortal>
} }
@@ -165,6 +251,19 @@ class WikiCardItem extends Component {
/> />
</ModalPortal> </ModalPortal>
} }
{this.state.isShowShareDialog &&
<ModalPortal>
<ShareWikiDialog
itemType={'library'}
itemName={wiki.name}
itemPath={'/'}
repoID={wiki.repo_id}
repoEncrypted={ false }
enableDirPrivateShare={true}
toggleDialog={this.onShareToggle}
/>
</ModalPortal>
}
</> </>
); );
} }

View File

@@ -12,6 +12,8 @@ const propTypes = {
data: PropTypes.object.isRequired, data: PropTypes.object.isRequired,
deleteWiki: PropTypes.func.isRequired, deleteWiki: PropTypes.func.isRequired,
renameWiki: PropTypes.func.isRequired, renameWiki: PropTypes.func.isRequired,
leaveSharedWiki: PropTypes.func.isRequired,
unshareGroupWiki: PropTypes.func.isRequired,
toggelAddWikiDialog: PropTypes.func, toggelAddWikiDialog: PropTypes.func,
sidePanelRate: PropTypes.number, sidePanelRate: PropTypes.number,
isSidePanelFolded: PropTypes.bool, isSidePanelFolded: PropTypes.bool,
@@ -30,7 +32,7 @@ class WikiCardView extends Component {
if (!canPublishRepo || !isPro) return; if (!canPublishRepo || !isPro) return;
let departmentMap = {}; let departmentMap = {};
wikiAPI.listWikiDepartments().then(res => { wikiAPI.listWikiDepartments().then(res => {
res.data.forEach(item => departmentMap[item.email] = true); res.data.forEach(item => departmentMap[item.id] = true);
this.setState({ departmentMap }); this.setState({ departmentMap });
}).catch(error => { }).catch(error => {
let errMessage = Utils.getErrorMsg(error); let errMessage = Utils.getErrorMsg(error);
@@ -41,12 +43,15 @@ class WikiCardView extends Component {
classifyWikis = (wikis) => { classifyWikis = (wikis) => {
let v1Wikis = []; let v1Wikis = [];
let myWikis = []; let myWikis = [];
let sharedWikis = [];
let department2WikisMap = {}; let department2WikisMap = {};
for (let i = 0; i < wikis.length; i++) { for (let i = 0; i < wikis.length; i++) {
if (wikis[i].version === 'v1') { if (wikis[i].version === 'v1') {
v1Wikis.push(wikis[i]); v1Wikis.push(wikis[i]);
} else if (wikis[i].owner === username) { } else if (wikis[i].owner === username) {
myWikis.push(wikis[i]); myWikis.push(wikis[i]);
} else if (wikis[i].type === 'shared') {
sharedWikis.push(wikis[i]);
} else { } else {
if (!department2WikisMap[wikis[i].owner]) { if (!department2WikisMap[wikis[i].owner]) {
department2WikisMap[wikis[i].owner] = []; department2WikisMap[wikis[i].owner] = [];
@@ -54,11 +59,12 @@ class WikiCardView extends Component {
department2WikisMap[wikis[i].owner].push(wikis[i]); department2WikisMap[wikis[i].owner].push(wikis[i]);
} }
} }
return { department2WikisMap, myWikis, v1Wikis }; return { department2WikisMap, myWikis, v1Wikis, sharedWikis };
}; };
render() { render() {
let { loading, errorMsg, wikis } = this.props.data; let { loading, errorMsg, wikis, groupWikis } = this.props.data;
const { toggelAddWikiDialog, sidePanelRate, isSidePanelFolded } = this.props; const { toggelAddWikiDialog, sidePanelRate, isSidePanelFolded } = this.props;
if (loading) { if (loading) {
@@ -67,13 +73,14 @@ class WikiCardView extends Component {
if (errorMsg) { if (errorMsg) {
return <p className="error text-center">{errorMsg}</p>; return <p className="error text-center">{errorMsg}</p>;
} }
const { v1Wikis, myWikis, department2WikisMap } = this.classifyWikis(wikis); const { v1Wikis, myWikis, sharedWikis } = this.classifyWikis(wikis);
let wikiCardGroups = []; let wikiCardGroups = [];
wikiCardGroups.push( wikiCardGroups.push(
<WikiCardGroup <WikiCardGroup
key='my-Wikis' key='my-Wikis'
deleteWiki={this.props.deleteWiki} deleteWiki={this.props.deleteWiki}
renameWiki={this.props.renameWiki} renameWiki={this.props.renameWiki}
unshareGroupWiki={this.props.unshareGroupWiki}
sidePanelRate={sidePanelRate} sidePanelRate={sidePanelRate}
isSidePanelFolded={isSidePanelFolded} isSidePanelFolded={isSidePanelFolded}
wikis={myWikis} wikis={myWikis}
@@ -83,19 +90,37 @@ class WikiCardView extends Component {
toggelAddWikiDialog={canPublishRepo ? toggelAddWikiDialog.bind(this, null) : null} toggelAddWikiDialog={canPublishRepo ? toggelAddWikiDialog.bind(this, null) : null}
/> />
); );
for (let deptEmail in department2WikisMap) {
wikiCardGroups.push( wikiCardGroups.push(
<WikiCardGroup <WikiCardGroup
key={'department-Wikis-' + deptEmail} key='shared-Wikis'
deleteWiki={this.props.leaveSharedWiki}
renameWiki={this.props.renameWiki}
unshareGroupWiki={this.props.unshareGroupWiki}
wikis={sharedWikis}
title={gettext('Shared with me')}
isDepartment={false}
isShowAvatar={false}
sidePanelRate={sidePanelRate}
isSidePanelFolded={isSidePanelFolded}
toggelAddWikiDialog={null}
/>
);
for (let deptID in groupWikis) {
groupWikis[deptID].wiki_info.length !== 0 &&
wikiCardGroups.push(
<WikiCardGroup
key={'group-Wikis-' + deptID}
deleteWiki={this.props.deleteWiki} deleteWiki={this.props.deleteWiki}
unshareGroupWiki={this.props.unshareGroupWiki}
renameWiki={this.props.renameWiki} renameWiki={this.props.renameWiki}
sidePanelRate={sidePanelRate} sidePanelRate={sidePanelRate}
isSidePanelFolded={isSidePanelFolded} isSidePanelFolded={isSidePanelFolded}
wikis={department2WikisMap[deptEmail]} group={groupWikis[deptID]}
title={department2WikisMap[deptEmail][0].owner_nickname} wikis={groupWikis[deptID].wiki_info}
title={groupWikis[deptID].group_name}
isDepartment={true} isDepartment={true}
isShowAvatar={false} isShowAvatar={false}
toggelAddWikiDialog={(canPublishRepo && this.state.departmentMap[deptEmail]) ? toggelAddWikiDialog.bind(this, deptEmail) : null} toggelAddWikiDialog={(canPublishRepo && this.state.departmentMap[groupWikis[deptID]['group_id']]) ? toggelAddWikiDialog.bind(this, deptID) : null}
/> />
); );
} }
@@ -104,6 +129,7 @@ class WikiCardView extends Component {
key='old-Wikis' key='old-Wikis'
deleteWiki={this.props.deleteWiki} deleteWiki={this.props.deleteWiki}
renameWiki={this.props.renameWiki} renameWiki={this.props.renameWiki}
unshareGroupWiki={this.props.unshareGroupWiki}
isSidePanelFolded={isSidePanelFolded} isSidePanelFolded={isSidePanelFolded}
sidePanelRate={sidePanelRate} sidePanelRate={sidePanelRate}
wikis={v1Wikis} wikis={v1Wikis}

View File

@@ -9,6 +9,8 @@ import EmptyTip from '../../components/empty-tip';
import AddWikiDialog from '../../components/dialog/add-wiki-dialog'; import AddWikiDialog from '../../components/dialog/add-wiki-dialog';
import wikiAPI from '../../utils/wiki-api'; import wikiAPI from '../../utils/wiki-api';
import WikiCardView from '../../components/wiki-card-view/wiki-card-view'; import WikiCardView from '../../components/wiki-card-view/wiki-card-view';
import { seafileAPI } from '../../utils/seafile-api';
const propTypes = { const propTypes = {
sidePanelRate: PropTypes.number, sidePanelRate: PropTypes.number,
@@ -23,6 +25,7 @@ class Wikis extends Component {
errorMsg: '', errorMsg: '',
currentDeptEmail: '', currentDeptEmail: '',
wikis: [], wikis: [],
groupWikis: [],
isShowAddWikiMenu: false, isShowAddWikiMenu: false,
isShowAddDialog: false, isShowAddDialog: false,
isDropdownMenuShown: false, isDropdownMenuShown: false,
@@ -35,6 +38,7 @@ class Wikis extends Component {
getWikis = () => { getWikis = () => {
let wikis = []; let wikis = [];
let groupWikis = [];
wikiAPI.listWikis().then(res => { wikiAPI.listWikis().then(res => {
wikis = wikis.concat(res.data.data); wikis = wikis.concat(res.data.data);
wikis.map(wiki => { wikis.map(wiki => {
@@ -42,12 +46,20 @@ class Wikis extends Component {
}); });
wikiAPI.listWikis2().then(res => { wikiAPI.listWikis2().then(res => {
let wikis2 = res.data.wikis; let wikis2 = res.data.wikis;
groupWikis = res.data.group_wikis;
groupWikis.forEach(group => {
group.wiki_info.forEach(wiki => {
wiki.version = 'v2';
wiki.admins = group.group_admins;
});
});
wikis2.map(wiki => { wikis2.map(wiki => {
return wiki['version'] = 'v2'; return wiki['version'] = 'v2';
}); });
this.setState({ this.setState({
loading: false, loading: false,
wikis: wikis.concat(wikis2) wikis: wikis.concat(wikis2),
groupWikis: groupWikis
}); });
}).catch((error) => { }).catch((error) => {
this.setState({ this.setState({
@@ -89,12 +101,24 @@ class Wikis extends Component {
addWiki = (wikiName, currentDeptID) => { addWiki = (wikiName, currentDeptID) => {
wikiAPI.addWiki2(wikiName, currentDeptID).then((res) => { wikiAPI.addWiki2(wikiName, currentDeptID).then((res) => {
let wikis = this.state.wikis.slice(0); let wikis = this.state.wikis.slice(0);
let groupWikis = this.state.groupWikis;
let new_wiki = res.data; let new_wiki = res.data;
new_wiki['version'] = 'v2'; new_wiki['version'] = 'v2';
if (currentDeptID) {
groupWikis.filter(group => {
if (group.group_id === currentDeptID) {
group.wiki_info.push(new_wiki);
}
return group;
});
} else {
wikis.push(new_wiki); wikis.push(new_wiki);
}
this.setState({ this.setState({
wikis, wikis,
currentDeptEmail: '', currentDeptEmail: '',
groupWikis,
currentDeptID: '',
}); });
}).catch((error) => { }).catch((error) => {
if (error.response) { if (error.response) {
@@ -110,7 +134,14 @@ class Wikis extends Component {
let wikis = this.state.wikis.filter(item => { let wikis = this.state.wikis.filter(item => {
return item.id !== wiki.id; return item.id !== wiki.id;
}); });
this.setState({ wikis: wikis }); let groupWikis = this.state.groupWikis.filter(group => {
group.wiki_info = group.wiki_info.filter(item => item.name !== wiki.name);
return group;
});
this.setState({
wikis: wikis,
groupWikis: groupWikis,
});
}).catch((error) => { }).catch((error) => {
if (error.response) { if (error.response) {
let errorMsg = error.response.data.error_msg; let errorMsg = error.response.data.error_msg;
@@ -122,7 +153,14 @@ class Wikis extends Component {
let wikis = this.state.wikis.filter(item => { let wikis = this.state.wikis.filter(item => {
return item.id !== wiki.id; return item.id !== wiki.id;
}); });
this.setState({ wikis: wikis }); let groupWikis = this.state.groupWikis.filter(group => {
group.wiki_info = group.wiki_info.filter(item => item.name !== wiki.name);
return group;
});
this.setState({
wikis: wikis,
groupWikis: groupWikis,
});
}).catch((error) => { }).catch((error) => {
if (error.response) { if (error.response) {
let errorMsg = error.response.data.error_msg; let errorMsg = error.response.data.error_msg;
@@ -132,6 +170,57 @@ class Wikis extends Component {
} }
}; };
leaveSharedWiki = (wiki) => {
if (!wiki.owner.includes('@seafile_group')) {
let options = {
'share_type': 'personal',
'from': wiki.owner
};
seafileAPI.leaveShareRepo(wiki.repo_id, options).then(res => {
let wikis = this.state.wikis.filter(item => {
return item.name !== wiki.name;
});
this.setState({
wikis: wikis,
});
}).catch((error) => {
let errorMsg = Utils.getErrorMsg(error, true);
toaster.danger(errorMsg);
});
} else {
seafileAPI.leaveShareGroupOwnedRepo(wiki.repo_id).then(res => {
let wikis = this.state.wikis.filter(item => {
return item.name !== wiki.name;
});
this.setState({
wikis: wikis,
});
}).catch((error) => {
let errorMsg = Utils.getErrorMsg(error, true);
toaster.danger(errorMsg);
});
}
};
unshareGroupWiki = (wiki, groupId) => {
seafileAPI.unshareRepoToGroup(wiki.repo_id, groupId).then(() => {
let groupWikis = this.state.groupWikis.map(group => {
if (group.group_id === groupId) {
return {
...group,
wiki_info: group.wiki_info.filter(item => item.name !== wiki.name)
};
}
return group;
});
this.setState({ groupWikis: groupWikis });
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
};
renameWiki = (wiki, newName) => { renameWiki = (wiki, newName) => {
if (wiki.version === 'v1') { if (wiki.version === 'v1') {
wikiAPI.renameWiki(wiki.id, newName).then(() => { wikiAPI.renameWiki(wiki.id, newName).then(() => {
@@ -150,13 +239,7 @@ class Wikis extends Component {
}); });
} else { } else {
wikiAPI.renameWiki2(wiki.id, newName).then(() => { wikiAPI.renameWiki2(wiki.id, newName).then(() => {
let wikis = this.state.wikis.map(item => { this.getWikis();
if (item.id === wiki.id && item.version === 'v2') {
item.name = newName;
}
return item;
});
this.setState({ wikis: wikis });
}).catch((error) => { }).catch((error) => {
if (error.response) { if (error.response) {
let errorMsg = error.response.data.error_msg; let errorMsg = error.response.data.error_msg;
@@ -208,11 +291,13 @@ class Wikis extends Component {
} }
</div> </div>
</div> </div>
{(this.state.loading || this.state.wikis.length !== 0) && {(this.state.loading || this.state.wikis.length !== 0 || this.state.groupWikis.length !== 0) &&
<div className="cur-view-content pb-4"> <div className="cur-view-content pb-4">
<WikiCardView <WikiCardView
data={this.state} data={this.state}
deleteWiki={this.deleteWiki} deleteWiki={this.deleteWiki}
leaveSharedWiki={this.leaveSharedWiki}
unshareGroupWiki={this.unshareGroupWiki}
renameWiki={this.renameWiki} renameWiki={this.renameWiki}
toggelAddWikiDialog={this.toggelAddWikiDialog} toggelAddWikiDialog={this.toggelAddWikiDialog}
sidePanelRate={this.props.sidePanelRate} sidePanelRate={this.props.sidePanelRate}
@@ -220,7 +305,7 @@ class Wikis extends Component {
/> />
</div> </div>
} }
{(!this.state.loading && this.state.wikis.length === 0) && {(!this.state.loading && this.state.wikis.length === 0 && this.state.groupWikis.length === 0) &&
<div className="cur-view-content"> <div className="cur-view-content">
<EmptyTip> <EmptyTip>
<h2>{gettext('No Wikis')}</h2> <h2>{gettext('No Wikis')}</h2>

View File

@@ -373,7 +373,7 @@ class RepoView(APIView):
result = { result = {
"repo_id": repo.id, "repo_id": repo.id,
"repo_name": repo.name, "repo_name": repo.name,
"repo_type": repo.repo_type,
"owner_email": repo_owner, "owner_email": repo_owner,
"owner_name": email2nickname(repo_owner), "owner_name": email2nickname(repo_owner),
"owner_contact_email": email2contact_email(repo_owner), "owner_contact_email": email2contact_email(repo_owner),

View File

@@ -42,6 +42,7 @@ from seahub.settings import SEADOC_SERVER_URL, ENABLE_STORAGE_CLASSES, STORAGE_C
ENCRYPTED_LIBRARY_VERSION ENCRYPTED_LIBRARY_VERSION
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, datetime_to_isoformat_timestr from seahub.utils.timeutils import timestamp_to_isoformat_timestr, datetime_to_isoformat_timestr
from seahub.utils.ccnet_db import CcnetDB
from seahub.tags.models import FileUUIDMap from seahub.tags.models import FileUUIDMap
from seahub.seadoc.models import SeadocHistoryName, SeadocDraft, SeadocCommentReply from seahub.seadoc.models import SeadocHistoryName, SeadocDraft, SeadocCommentReply
from seahub.base.models import FileComment from seahub.base.models import FileComment
@@ -49,12 +50,38 @@ from seahub.api2.views import HTTP_447_TOO_MANY_FILES_IN_LIBRARY
from seahub.group.utils import group_id_to_name, is_group_admin from seahub.group.utils import group_id_to_name, is_group_admin
from seahub.utils.rpc import SeafileAPI from seahub.utils.rpc import SeafileAPI
from seahub.constants import PERMISSION_READ_WRITE from seahub.constants import PERMISSION_READ_WRITE
from seaserv import ccnet_api
HTTP_520_OPERATION_FAILED = 520 HTTP_520_OPERATION_FAILED = 520
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def _merge_wiki_in_groups(group_wikis):
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:
wiki = Wiki(gw)
wiki_info = wiki.to_dict()
owner = gw.owner
if ('@seafile_group') in owner:
group_id = int(owner.split('@')[0])
owner_nickname = group_id_to_name(group_id)
else:
owner_nickname = email2nickname(owner)
repo_info = {
"type": "group",
"permission": gw.permission,
"owner_nickname": owner_nickname
}
wiki_info.update(repo_info)
group_id = gw.group_id
group_id_wikis_map[group_id].append(wiki_info)
return group_id_wikis_map
class Wikis2View(APIView): class Wikis2View(APIView):
authentication_classes = (TokenAuthentication, SessionAuthentication) authentication_classes = (TokenAuthentication, SessionAuthentication)
@@ -64,63 +91,82 @@ class Wikis2View(APIView):
def get(self, request, format=None): def get(self, request, format=None):
"""List all wikis. """List all wikis.
""" """
# parse request params
filter_by = {
'mine': False,
'shared': False,
'group': False,
'org': False,
}
rtype = request.GET.get('type', "")
if not rtype:
# set all to True, no filter applied
filter_by = filter_by.fromkeys(iter(filter_by.keys()), True)
for f in rtype.split(','):
f = f.strip()
filter_by[f] = True
username = request.user.username username = request.user.username
org_id = request.user.org.org_id if is_org_context(request) else None org_id = request.user.org.org_id if is_org_context(request) else None
(owned, shared, groups, public) = get_user_repos(username, org_id) (owned, shared, groups, public) = get_user_repos(username, org_id)
wikis = [] # list user groups
username = request.user.username if is_org_context(request):
if filter_by['mine']: org_id = request.user.org.org_id
user_groups = ccnet_api.get_org_groups_by_user(org_id, username, return_ancestors=True)
else:
user_groups = ccnet_api.get_groups(username, return_ancestors=True)
owned_wikis = [r for r in owned if is_wiki_repo(r)] owned_wikis = [r for r in owned if is_wiki_repo(r)]
wiki_list = []
for r in owned_wikis: for r in owned_wikis:
r.owner = username r.owner = username
r.permission = 'rw' r.permission = 'rw'
wikis.append(r) wiki = Wiki(r)
wiki_info = wiki.to_dict()
repo_info = {
"type": "mine",
"permission": 'rw',
"owner_nickname": email2nickname(username)
}
wiki_info.update(repo_info)
wiki_list.append(wiki_info)
if filter_by['shared']:
shared_wikis = [r for r in shared if is_wiki_repo(r)] shared_wikis = [r for r in shared if is_wiki_repo(r)]
for r in shared_wikis: for r in shared_wikis:
r.owner = r.user owner = r.user
wikis.append(r) r.owner = owner
wiki = Wiki(r)
if ('@seafile_group') in r.owner:
group_id = int(owner.split('@')[0])
owner_nickname = group_id_to_name(group_id)
else:
owner_nickname = email2nickname(owner)
wiki_info = wiki.to_dict()
repo_info = {
"type": "shared",
"permission": r.permission,
"owner_nickname": owner_nickname
}
wiki_info.update(repo_info)
wiki_list.append(wiki_info)
if filter_by['group']:
group_wikis = [r for r in groups if is_wiki_repo(r)] group_wikis = [r for r in groups if is_wiki_repo(r)]
group_id_in_wikis = list(set([r.group_id for r in group_wikis]))
try:
group_ids_admins_map = {}
if group_id_in_wikis:
ccnet_db = CcnetDB()
group_ids_admins_map = ccnet_db.get_group_ids_admins_map(group_id_in_wikis)
except Exception as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
user_wiki_groups = [ug for ug in user_groups if ug.id in group_id_in_wikis]
for r in group_wikis: for r in group_wikis:
r.owner = r.user r.owner = r.user
wikis.append(r)
wikis = list(set(wikis)) group_wiki_list = []
wiki_list = [] group_id_wikis_map = _merge_wiki_in_groups(group_wikis)
for w in wikis: for group_obj in user_wiki_groups:
wiki = Wiki(w) group_wiki = {
wiki_info = wiki.to_dict() 'group_name': group_obj.group_name,
if is_group_wiki(wiki): 'group_id': group_obj.id,
group_id = int(wiki.owner.split('@')[0]) 'group_admins': group_ids_admins_map.get(group_obj.id) or [],
wiki_info['owner_nickname'] = group_id_to_name(group_id) "owner": group_obj.creator_name,
else: 'wiki_info': group_id_wikis_map[group_obj.id]
wiki_info['owner_nickname'] = email2nickname(wiki.owner) }
wiki_list.append(wiki_info) group_wiki_list.append(group_wiki)
wiki_list = sorted(wiki_list, key=lambda x: x.get('updated_at'), reverse=True) wiki_list = sorted(wiki_list, key=lambda x: x.get('updated_at'), reverse=True)
return Response({'wikis': wiki_list}) return Response({'wikis': wiki_list, 'group_wikis': group_wiki_list})
def post(self, request, format=None): def post(self, request, format=None):
"""Add a new wiki. """Add a new wiki.

View File

@@ -162,3 +162,24 @@ class CcnetDB:
users.append(users_obj) users.append(users_obj)
return users, total_count return users, total_count
def get_group_ids_admins_map(self, group_ids):
group_admins = {}
group_ids_str = ','.join(str(id) for id in group_ids)
sql = f"""
SELECT user_name, group_id
FROM
`{self.db_name}`.`GroupUser`
WHERE
group_id IN ({group_ids_str}) AND is_staff = 1
"""
with connection.cursor() as cursor:
cursor.execute(sql)
result = cursor.fetchall()
for user, group_id in result:
if group_id in group_admins:
group_admins[group_id].append(user)
else:
group_admins[group_id] = [user]
return group_admins

View File

@@ -81,13 +81,8 @@ def check_wiki_admin_permission(wiki, username):
def check_wiki_permission(wiki, username): def check_wiki_permission(wiki, username):
if is_group_wiki(wiki): permission = seafile_api.check_permission_by_path(wiki.repo_id, '/', username)
group_id = int(wiki.owner.split('@')[0]) return permission
return is_group_member(group_id, username)
else:
if username == wiki.owner:
return True
return False
def get_page_ids_in_folder(navigation, folder_id): def get_page_ids_in_folder(navigation, folder_id):

View File

@@ -2,26 +2,20 @@
import os import os
import logging import logging
import posixpath import posixpath
import time
from datetime import datetime from datetime import datetime
from seaserv import seafile_api from seaserv import seafile_api
from django.urls import reverse from django.http import Http404
from django.http import HttpResponseRedirect, Http404 from django.shortcuts import render
from django.shortcuts import render, get_object_or_404, redirect
from seahub.share.models import FileShare
from seahub.wiki2.models import Wiki2 as Wiki from seahub.wiki2.models import Wiki2 as Wiki
from seahub.views import check_folder_permission from seahub.utils import get_file_type_and_ext, render_permission_error
from seahub.utils import get_file_type_and_ext, render_permission_error, is_pro_version from seahub.utils.file_types import SEADOC
from seahub.utils.file_types import IMAGE, SEADOC
from seahub.seadoc.utils import get_seadoc_file_uuid, gen_seadoc_access_token
from seahub.auth.decorators import login_required from seahub.auth.decorators import login_required
from seahub.wiki2.utils import can_edit_wiki, check_wiki_permission, get_wiki_config from seahub.wiki2.utils import check_wiki_permission, get_wiki_config
from seahub.utils.file_op import check_file_lock, ONLINE_OFFICE_LOCK_OWNER, if_locked_by_online_office from seahub.utils.repo import get_repo_owner
from seahub.utils.repo import parse_repo_perm, get_repo_owner
from seahub.settings import SEADOC_SERVER_URL from seahub.settings import SEADOC_SERVER_URL
# Get an instance of a logger # Get an instance of a logger
@@ -56,6 +50,7 @@ def wiki_view(request, wiki_id):
# perm check # perm check
req_user = request.user.username req_user = request.user.username
permission = check_wiki_permission(wiki, req_user)
if not check_wiki_permission(wiki, req_user): if not check_wiki_permission(wiki, req_user):
return render_permission_error(request, 'Permission denied.') return render_permission_error(request, 'Permission denied.')
@@ -79,5 +74,6 @@ def wiki_view(request, wiki_id):
"repo_name": repo.name if repo else '', "repo_name": repo.name if repo else '',
"modifier": latest_contributor, "modifier": latest_contributor,
"modify_time": last_modified, "modify_time": last_modified,
"seadoc_server_url": SEADOC_SERVER_URL "seadoc_server_url": SEADOC_SERVER_URL,
"permission": permission
}) })