diff --git a/frontend/src/components/dialog/repo-share-admin-dialog.js b/frontend/src/components/dialog/repo-share-admin-dialog.js index 205a2544672..484c313c1fd 100644 --- a/frontend/src/components/dialog/repo-share-admin-dialog.js +++ b/frontend/src/components/dialog/repo-share-admin-dialog.js @@ -1,15 +1,11 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; -import toaster from '../toast'; -import { Utils } from '../../utils/utils'; -import { seafileAPI } from '../../utils/seafile-api'; import { Modal, ModalHeader, ModalBody, TabContent, TabPane, Nav, NavItem, NavLink } from 'reactstrap'; -import { gettext, username, canGenerateShareLink, canGenerateUploadLink } from '../../utils/constants'; +import { gettext, canGenerateShareLink, canGenerateUploadLink } from '../../utils/constants'; import RepoShareAdminShareLinks from './repo-share-admin/share-links'; import RepoShareAdminUploadLinks from './repo-share-admin/upload-links'; import RepoShareAdminUserShares from './repo-share-admin/user-shares'; import RepoShareAdminGroupShares from './repo-share-admin/group-shares'; -import RepoShareAdminInternalLinks from './repo-share-admin/internal-links'; const propTypes = { repo: PropTypes.object.isRequired, @@ -20,14 +16,13 @@ class RepoShareAdminDialog extends React.Component { constructor(props) { super(props); + this.enableShareLink = !this.props.repo.encrypted && canGenerateShareLink; + this.enableUploadLink = !this.props.repo.encrypted && canGenerateUploadLink; this.state = { - activeTab: this.getInitialActiveTab(), + activeTab: this.getInitialActiveTab() }; } - enableShareLink = !this.props.repo.encrypted && canGenerateShareLink; - enableUploadLink = !this.props.repo.encrypted && canGenerateUploadLink; - getInitialActiveTab = () => { if (this.enableShareLink) { return 'shareLink'; @@ -51,9 +46,8 @@ class RepoShareAdminDialog extends React.Component { } render() { - - let activeTab = this.state.activeTab; - let repoName = this.props.repo.repo_name; + const { activeTab } = this.state; + const { repoName } = this.props.repo; return (
@@ -89,11 +83,6 @@ class RepoShareAdminDialog extends React.Component { {gettext('Group Shares')} - - - {gettext('Internal Links')} - -
@@ -126,13 +115,6 @@ class RepoShareAdminDialog extends React.Component { /> } - {activeTab === 'internalLink' && - - - - }
diff --git a/frontend/src/components/dialog/repo-share-admin/group-shares.js b/frontend/src/components/dialog/repo-share-admin/group-shares.js index feb56a9b995..8589e49101a 100644 --- a/frontend/src/components/dialog/repo-share-admin/group-shares.js +++ b/frontend/src/components/dialog/repo-share-admin/group-shares.js @@ -1,10 +1,9 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; - +import { Link } from '@gatsbyjs/reach-router'; import { Utils } from '../../../utils/utils'; import { seafileAPI } from '../../../utils/seafile-api'; -import { gettext, siteRoot, isPro } from '../../../utils/constants'; - +import { gettext, siteRoot, isPro, username } from '../../../utils/constants'; import Loading from '../../../components/loading'; import toaster from '../../../components/toast'; import EmptyTip from '../../../components/empty-tip'; @@ -12,7 +11,8 @@ import SharePermissionEditor from '../../../components/select-editor/share-permi const itemPropTypes = { item: PropTypes.object.isRequired, - deleteItem: PropTypes.func.isRequired + deleteItem: PropTypes.func.isRequired, + isRepoOwner: PropTypes.bool.isRequired }; class Item extends Component { @@ -25,10 +25,10 @@ class Item extends Component { isShowPermEditor: false, }; this.permissions = ['rw', 'r']; - if (isPro && this.props.item.path === '/') { - this.permissions.push('admin'); - } if (isPro) { + if (this.props.item.path === '/' && this.props.isRepoOwner) { + this.permissions.push('admin'); + } this.permissions.push('cloud-edit', 'preview'); } } @@ -74,10 +74,10 @@ class Item extends Component { return ( - {Utils.getFolderName(item.path)} + {Utils.getFolderName(item.path)} {item.share_to_name} - + {!this.state.isShowPermEditor && (
{item.permission_name || Utils.sharePerms(this.state.permission)} @@ -103,7 +103,7 @@ class Item extends Component { onPermissionChanged={this.changePerm} /> )} - + + > + ); @@ -155,7 +156,7 @@ class RepoShareAdminGroupShares extends Component { seafileAPI.deleteShareToGroupItem(item.repo_id, item.path, 'group', item.share_to).then(res => { let items = this.state.items.filter(shareItem => { return shareItem.path + shareItem.share_to !== item.path + item.share_to; - }) + }); this.setState({items: items}); let message = gettext('Successfully deleted 1 item'); toaster.success(message); @@ -167,44 +168,41 @@ class RepoShareAdminGroupShares extends Component { render() { const { loading, errorMsg, items } = this.state; + const { repo } = this.props; + const isRepoOwner = repo.owner_email === username; return ( -
-
-
- {loading && } - {!loading && errorMsg &&

{errorMsg}

} - {!loading && !errorMsg && !items.length && - -

{gettext('No share links')}

-
- } - {!loading && !errorMsg && items.length > 0 && - - - - - - - - - - - {items.map((item, index) => { - return ( - - ); - })} - -
{gettext('Name')}{gettext('Group')}{gettext('Permission')}
- } -
-
-
+ {loading && } + {!loading && errorMsg &&

{errorMsg}

} + {!loading && !errorMsg && !items.length && + +

{gettext('No group shares')}

+
+ } + {!loading && !errorMsg && items.length > 0 && + + + + + + + + + + + {items.map((item, index) => { + return ( + + ); + })} + +
{gettext('Name')}{gettext('Group')}{gettext('Permission')}
+ }
); } diff --git a/frontend/src/components/dialog/repo-share-admin/internal-links.js b/frontend/src/components/dialog/repo-share-admin/internal-links.js deleted file mode 100644 index e6aca9eb9d7..00000000000 --- a/frontend/src/components/dialog/repo-share-admin/internal-links.js +++ /dev/null @@ -1,171 +0,0 @@ -import React, { Component, Fragment } from 'react'; -import PropTypes from 'prop-types'; - -import { Utils } from '../../../utils/utils'; -import { seafileAPI } from '../../../utils/seafile-api'; -import { gettext, siteRoot } from '../../../utils/constants'; - -import Loading from '../../../components/loading'; -import toaster from '../../../components/toast'; -import EmptyTip from '../../../components/empty-tip'; - -const itemPropTypes = { - item: PropTypes.object.isRequired, - repoID: PropTypes.string.isRequired, - repoName: PropTypes.string.isRequired, - deleteItem: PropTypes.func.isRequired -}; - -class Item extends Component { - - constructor(props) { - super(props); - this.state = { - isOperationShow: false - }; - } - - onMouseEnter = () => { - this.setState({isOperationShow: true}); - }; - - onMouseLeave = () => { - this.setState({isOperationShow: false}); - }; - - onDeleteLink = (e) => { - e.preventDefault(); - this.props.deleteItem(this.props.item); - }; - - render() { - - const { item, repoID, repoName } = this.props; - - let objUrl; - let path = item.parent_dir + item.dirent_name; - - if (item.is_dir) { - objUrl = `${siteRoot}library/${repoID}/${encodeURIComponent(repoName)}${Utils.encodePath(path)}`; - } else { - objUrl = `${siteRoot}lib/${repoID}/file${Utils.encodePath(path)}`; - } - - return ( - - - {item.dirent_name} - - - {item.smart_link} - - - - - - ); - } -} - -Item.propTypes = itemPropTypes; - -const propTypes = { - repo: PropTypes.object.isRequired, -}; - -class RepoShareAdminShareLinks extends Component { - - constructor(props) { - super(props); - this.state = { - loading: true, - errorMsg: '', - items: [], - }; - } - - componentDidMount() { - seafileAPI.listRepoInternalLinks(this.props.repo.repo_id).then((res) => { - this.setState({ - loading: false, - items: res.data.smart_link_list, - }); - }).catch((error) => { - this.setState({ - loading: false, - errorMsg: Utils.getErrorMsg(error, true) // true: show login tip if 403 - }); - }); - } - - deleteItem = (item) => { - seafileAPI.deleteRepoInternalLink(this.props.repo.repo_id, item.token).then(() => { - let items = this.state.items.filter(linkItem => { - return linkItem.token !== item.token; - }); - this.setState({items: items}); - let message = gettext('Successfully deleted 1 item'); - toaster.success(message); - }).catch((error) => { - let errMessage = Utils.getErrorMsg(error); - toaster.danger(errMessage); - }); - } - - render() { - const { loading, errorMsg, items } = this.state; - return ( - -
-
-
- {loading && } - {!loading && errorMsg &&

{errorMsg}

} - {!loading && !errorMsg && !items.length && - -

{gettext('No internal links')}

-
- } - {!loading && !errorMsg && items.length > 0 && - - - - - - - - - - {items.map((item, index) => { - return ( - - ); - })} - -
{gettext('Name')}{gettext('Link')}
- } -
-
-
-
- ); - } -} - -RepoShareAdminShareLinks.propTypes = propTypes; - -export default RepoShareAdminShareLinks; diff --git a/frontend/src/components/dialog/repo-share-admin/share-links.js b/frontend/src/components/dialog/repo-share-admin/share-links.js index 9368b05fd77..a42ecdbc457 100644 --- a/frontend/src/components/dialog/repo-share-admin/share-links.js +++ b/frontend/src/components/dialog/repo-share-admin/share-links.js @@ -1,10 +1,9 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; - +import { Link } from '@gatsbyjs/reach-router'; import { Utils } from '../../../utils/utils'; import { seafileAPI } from '../../../utils/seafile-api'; import { gettext, siteRoot } from '../../../utils/constants'; - import Loading from '../../../components/loading'; import toaster from '../../../components/toast'; import EmptyTip from '../../../components/empty-tip'; @@ -37,7 +36,6 @@ class Item extends Component { }; render() { - let objUrl; let item = this.props.item; let path = item.path === '/' ? '/' : item.path.slice(0, item.path.length - 1); @@ -52,10 +50,11 @@ class Item extends Component { {item.creator_name} - {item.obj_name} + {item.is_dir ? {item.obj_name} : + {item.obj_name}} - {item.link} + {item.link} + > + ); @@ -86,7 +86,7 @@ class RepoShareAdminShareLinks extends Component { this.state = { loading: true, errorMsg: '', - items: [], + items: [] }; } @@ -122,42 +122,36 @@ class RepoShareAdminShareLinks extends Component { const { loading, errorMsg, items } = this.state; return ( -
-
-
- {loading && } - {!loading && errorMsg &&

{errorMsg}

} - {!loading && !errorMsg && !items.length && - -

{gettext('No share links')}

-
- } - {!loading && !errorMsg && items.length > 0 && - - - - - - - - - - - {items.map((item, index) => { - return ( - - ); - })} - -
{gettext('Creator')}{gettext('Name')}{gettext('Link')}
- } -
-
-
+ {loading && } + {!loading && errorMsg &&

{errorMsg}

} + {!loading && !errorMsg && !items.length && + +

{gettext('No share links')}

+
+ } + {!loading && !errorMsg && items.length > 0 && + + + + + + + + + + + {items.map((item, index) => { + return ( + + ); + })} + +
{gettext('Creator')}{gettext('Name')}{gettext('Link')}
+ }
); } diff --git a/frontend/src/components/dialog/repo-share-admin/upload-links.js b/frontend/src/components/dialog/repo-share-admin/upload-links.js index 719f13d61df..d1670ecd5d1 100644 --- a/frontend/src/components/dialog/repo-share-admin/upload-links.js +++ b/frontend/src/components/dialog/repo-share-admin/upload-links.js @@ -1,10 +1,9 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; - +import { Link } from '@gatsbyjs/reach-router'; import { Utils } from '../../../utils/utils'; import { seafileAPI } from '../../../utils/seafile-api'; import { gettext, siteRoot } from '../../../utils/constants'; - import Loading from '../../../components/loading'; import toaster from '../../../components/toast'; import EmptyTip from '../../../components/empty-tip'; @@ -37,7 +36,6 @@ class Item extends Component { }; render() { - let item = this.props.item; let path = item.path === '/' ? '/' : item.path.slice(0, item.path.length - 1); let objUrl = `${siteRoot}library/${item.repo_id}/${encodeURIComponent(item.repo_name)}${Utils.encodePath(path)}`; @@ -46,10 +44,10 @@ class Item extends Component { {item.creator_name} - {item.obj_name} + {item.obj_name} - {item.link} + {item.link} + > + ); @@ -116,42 +115,36 @@ class RepoShareAdminUploadLinks extends Component { const { loading, errorMsg, items } = this.state; return ( -
-
-
- {loading && } - {!loading && errorMsg &&

{errorMsg}

} - {!loading && !errorMsg && !items.length && - -

{gettext('No upload links')}

-
- } - {!loading && !errorMsg && items.length > 0 && - - - - - - - - - - - {items.map((item, index) => { - return ( - - ); - })} - -
{gettext('Creator')}{gettext('Name')}{gettext('Link')}
- } -
-
-
+ {loading && } + {!loading && errorMsg &&

{errorMsg}

} + {!loading && !errorMsg && !items.length && + +

{gettext('No upload links')}

+
+ } + {!loading && !errorMsg && items.length > 0 && + + + + + + + + + + + {items.map((item, index) => { + return ( + + ); + })} + +
{gettext('Creator')}{gettext('Name')}{gettext('Link')}
+ }
); } diff --git a/frontend/src/components/dialog/repo-share-admin/user-shares.js b/frontend/src/components/dialog/repo-share-admin/user-shares.js index 18fd0b132f1..fb1998cc53f 100644 --- a/frontend/src/components/dialog/repo-share-admin/user-shares.js +++ b/frontend/src/components/dialog/repo-share-admin/user-shares.js @@ -1,10 +1,9 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; - +import { Link } from '@gatsbyjs/reach-router'; import { Utils } from '../../../utils/utils'; import { seafileAPI } from '../../../utils/seafile-api'; -import { gettext, siteRoot, isPro } from '../../../utils/constants'; - +import { gettext, siteRoot, isPro, username } from '../../../utils/constants'; import Loading from '../../../components/loading'; import toaster from '../../../components/toast'; import EmptyTip from '../../../components/empty-tip'; @@ -12,7 +11,8 @@ import SharePermissionEditor from '../../../components/select-editor/share-permi const itemPropTypes = { item: PropTypes.object.isRequired, - deleteItem: PropTypes.func.isRequired + deleteItem: PropTypes.func.isRequired, + isRepoOwner: PropTypes.bool.isRequired }; class Item extends Component { @@ -25,10 +25,10 @@ class Item extends Component { isShowPermEditor: false, }; this.permissions = ['rw', 'r']; - if (isPro && this.props.item.path === '/') { - this.permissions.push('admin'); - } if (isPro) { + if (this.props.item.path === '/' && this.props.isRepoOwner) { + this.permissions.push('admin'); + } this.permissions.push('cloud-edit', 'preview'); } } @@ -74,10 +74,10 @@ class Item extends Component { return ( - {Utils.getFolderName(item.path)} + {Utils.getFolderName(item.path)} {item.share_to_name} - + {!this.state.isShowPermEditor && (
{item.permission_name || Utils.sharePerms(this.state.permission)} @@ -103,7 +103,7 @@ class Item extends Component { onPermissionChanged={this.changePerm} /> )} - + + > + ); @@ -155,7 +156,7 @@ class RepoShareAdminUserShares extends Component { seafileAPI.deleteShareToUserItem(item.repo_id, item.path, 'user', item.share_to).then(res => { let items = this.state.items.filter(shareItem => { return shareItem.path + shareItem.share_to !== item.path + item.share_to; - }) + }); this.setState({items: items}); let message = gettext('Successfully deleted 1 item'); toaster.success(message); @@ -167,44 +168,41 @@ class RepoShareAdminUserShares extends Component { render() { const { loading, errorMsg, items } = this.state; + const { repo } = this.props; + const isRepoOwner = repo.owner_email === username; return ( -
-
-
- {loading && } - {!loading && errorMsg &&

{errorMsg}

} - {!loading && !errorMsg && !items.length && - -

{gettext('No share links')}

-
- } - {!loading && !errorMsg && items.length > 0 && - - - - - - - - - - - {items.map((item, index) => { - return ( - - ); - })} - -
{gettext('Name')}{gettext('User')}{gettext('Permission')}
- } -
-
-
+ {loading && } + {!loading && errorMsg &&

{errorMsg}

} + {!loading && !errorMsg && !items.length && + +

{gettext('No user shares')}

+
+ } + {!loading && !errorMsg && items.length > 0 && + + + + + + + + + + + {items.map((item, index) => { + return ( + + ); + })} + +
{gettext('Name')}{gettext('User')}{gettext('Permission')}
+ }
); } diff --git a/frontend/src/components/dialog/repo-share-upload-links-dialog.js b/frontend/src/components/dialog/repo-share-upload-links-dialog.js deleted file mode 100644 index 88f49355cf8..00000000000 --- a/frontend/src/components/dialog/repo-share-upload-links-dialog.js +++ /dev/null @@ -1,220 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { Modal, ModalHeader, ModalBody, NavLink } from 'reactstrap'; -import { seafileAPI } from '../../utils/seafile-api'; -import { siteRoot, gettext } from '../../utils/constants'; -import { Utils } from '../../utils/utils'; -import toaster from '../toast'; -import Loading from '../loading'; -import EmptyTip from '../empty-tip'; - -const repoShareUploadLinkItemPropTypes = { - item: PropTypes.object.isRequired, - activeTab: PropTypes.string.isRequired, - deleteItem: PropTypes.func.isRequired -}; - -class RepoShareUploadLinkItem extends React.Component { - - constructor(props) { - super(props); - this.state = { - isOperationShow: false - }; - } - - onMouseEnter = () => { - this.setState({isOperationShow: true}); - }; - - onMouseLeave = () => { - this.setState({isOperationShow: false}); - }; - - onDeleteLink = (e) => { - e.preventDefault(); - this.props.deleteItem(this.props.item.token); - }; - - render() { - - let objUrl; - let item = this.props.item; - let path = item.path === '/' ? '/' : item.path.slice(0, item.path.length - 1); - - if (this.props.activeTab === 'shareLinks') { - if (item.is_dir) { - objUrl = `${siteRoot}library/${item.repo_id}/${encodeURIComponent(item.repo_name)}${Utils.encodePath(path)}`; - } else { - objUrl = `${siteRoot}lib/${item.repo_id}/file${Utils.encodePath(item.path)}`; - } - } - - if (this.props.activeTab === 'uploadLinks') { - objUrl = `${siteRoot}library/${item.repo_id}/${encodeURIComponent(item.repo_name)}${Utils.encodePath(path)}`; - } - - return ( - - {item.creator_name} - - {item.obj_name} - - - {item.link} - - - - - - ); - } -} - -RepoShareUploadLinkItem.propTypes = repoShareUploadLinkItemPropTypes; - -const RepoShareUploadLinksDialogPropTypes = { - repo: PropTypes.object.isRequired, - toggleDialog: PropTypes.func.isRequired -}; - -class RepoShareUploadLinksDialog extends React.Component { - - constructor(props) { - super(props); - this.state = { - loading: true, - activeTab: 'shareLinks', - repoShareUploadLinkList: [], - errorMsg: '' - }; - } - - componentDidMount() { - this.getItems('share-link'); - } - - getItems = (itemType) => { - const repoID = this.props.repo.repo_id; - const request = itemType == 'share-link' ? - seafileAPI.listRepoShareLinks(repoID) : - seafileAPI.listRepoUploadLinks(repoID); - request.then((res) => { - this.setState({ - loading: false, - repoShareUploadLinkList: res.data, - }); - }).catch(error => { - this.setState({ - isLoading: false, - errorMsg: Utils.getErrorMsg(error, true) - }); - }); - } - - deleteItem = (token) => { - const repoID = this.props.repo.repo_id; - const request = this.state.activeTab == 'shareLinks' ? - seafileAPI.deleteRepoShareLink(repoID, token) : - seafileAPI.deleteRepoUploadLink(repoID, token); - request.then((res) => { - const repoShareUploadLinkList = this.state.repoShareUploadLinkList.filter(item => { - return item.token !== token; - }); - this.setState({ - repoShareUploadLinkList: repoShareUploadLinkList - }); - }).catch(error => { - toaster.danger(Utils.getErrorMsg(error)); - }); - }; - - toggle = (tab) => { - if (this.state.activeTab !== tab) { - this.setState({activeTab: tab}); - } - if (tab == 'shareLinks') { - this.getItems('share-link'); - } - if (tab == 'uploadLinks') { - this.getItems('upload-link'); - } - }; - - render() { - - const { loading, errorMsg, activeTab, repoShareUploadLinkList } = this.state; - - const itemName = '' + Utils.HTMLescape(this.props.repo.repo_name) + ''; - const title = gettext('{placeholder} Share/Upload Links').replace('{placeholder}', itemName); - - return ( - - - - - -
-
-
-
    -
  • - {gettext('Share Links')} -
  • -
  • - {gettext('Upload Links')} -
  • -
-
-
- {loading && } - {!loading && errorMsg &&

{errorMsg}

} - {!loading && !errorMsg && !repoShareUploadLinkList.length && - -

{activeTab == 'shareLinks' ? gettext('No share links') : gettext('No upload links')}

-
- } - {!loading && !errorMsg && repoShareUploadLinkList.length > 0 && - - - - - - - - - - - {this.state.repoShareUploadLinkList.map((item, index) => { - return ( - - ); - })} - -
{gettext('Creator')}{gettext('Name')}{gettext('Link')}
- } -
-
-
-
-
- ); - } -} - -RepoShareUploadLinksDialog.propTypes = RepoShareUploadLinksDialogPropTypes; - -export default RepoShareUploadLinksDialog; diff --git a/frontend/src/css/share-link-dialog.css b/frontend/src/css/share-link-dialog.css index 29442376892..a049b3d9b45 100644 --- a/frontend/src/css/share-link-dialog.css +++ b/frontend/src/css/share-link-dialog.css @@ -11,7 +11,7 @@ } .share-dialog-content .share-dialog-side { - display: flex; + /*display: flex;*/ flex-basis: 22%; padding: 1rem; border-bottom: 1px solid #eee; diff --git a/seahub/api2/endpoints/smart_link.py b/seahub/api2/endpoints/smart_link.py index 50c395be4b0..7c2c6389b20 100644 --- a/seahub/api2/endpoints/smart_link.py +++ b/seahub/api2/endpoints/smart_link.py @@ -18,7 +18,7 @@ from seahub.tags.models import FileUUIDMap from seahub.utils import get_service_url, normalize_dir_path, \ normalize_file_path -from seahub.utils.repo import is_valid_repo_id_format, is_repo_admin +from seahub.utils.repo import is_valid_repo_id_format from seahub.views import check_folder_permission from seahub.api2.utils import to_python_boolean @@ -103,9 +103,7 @@ def get(self, request): try: uuid_map = FileUUIDMap.objects.get_or_create_fileuuidmap(repo_id, - parent_dir, - dirent_name, - is_dir) + parent_dir, dirent_name, is_dir) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' @@ -155,83 +153,3 @@ def get(self, request, token): result['is_dir'] = is_dir return Response(result) - - -class RepoSmartLinks(APIView): - - authentication_classes = (TokenAuthentication, SessionAuthentication) - permission_classes = (IsAuthenticated,) - throttle_classes = (UserRateThrottle,) - - def get(self, request, repo_id): - """ Get all smart links of a repo. - - Permission checking: - 1. repo owner or admin; - """ - - # 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) - - # permission check - username = request.user.username - if not is_repo_admin(username, repo_id): - error_msg = 'Permission denied.' - return api_error(status.HTTP_403_FORBIDDEN, error_msg) - - result = {} - result['smart_link_list'] = [] - - smart_links = FileUUIDMap.objects.filter(repo_id=repo_id) - for link in smart_links: - - link_info = {} - link_info['token'] = link.uuid - link_info['is_dir'] = link.is_dir - link_info['parent_dir'] = normalize_dir_path(link.parent_path) - link_info['dirent_name'] = link.filename - link_info['smart_link'] = gen_smart_link(link.uuid) - - result['smart_link_list'].append(link_info) - - return Response(result) - - -class RepoSmartLink(APIView): - - authentication_classes = (TokenAuthentication, SessionAuthentication) - permission_classes = (IsAuthenticated,) - throttle_classes = (UserRateThrottle,) - - def delete(self, request, repo_id, token): - """ Delete smart link of a repo. - - Permission checking: - 1. repo owner or admin; - """ - - # 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) - - # permission check - username = request.user.username - if not is_repo_admin(username, repo_id): - error_msg = 'Permission denied.' - return api_error(status.HTTP_403_FORBIDDEN, error_msg) - - smart_links = FileUUIDMap.objects.filter(repo_id=repo_id).filter(uuid=token) - - try: - smart_links.delete() - 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({'success': True}) diff --git a/seahub/urls.py b/seahub/urls.py index f987dbc58a2..ac843fc1d74 100644 --- a/seahub/urls.py +++ b/seahub/urls.py @@ -22,8 +22,7 @@ from seahub.api2.endpoints.search_file import SearchFile -from seahub.api2.endpoints.smart_link import SmartLink, SmartLinkToken, \ - RepoSmartLinks, RepoSmartLink +from seahub.api2.endpoints.smart_link import SmartLink, SmartLinkToken from seahub.api2.endpoints.groups import Groups, Group from seahub.api2.endpoints.all_groups import AllGroups from seahub.api2.endpoints.departments import Departments @@ -312,8 +311,6 @@ ## user::smart-link re_path(r'^api/v2.1/smart-link/$', SmartLink.as_view(), name="api-v2.1-smart-link"), re_path(r'^api/v2.1/smart-links/(?P[-0-9a-f]{36})/$', SmartLinkToken.as_view(), name="api-v2.1-smart-links-token"), - re_path(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/smart-links/$', RepoSmartLinks.as_view(), name='api-v2.1-repo-smart-links'), - re_path(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/smart-links/(?P[-0-9a-f]{36})/$', RepoSmartLink.as_view(), name='api-v2.1-repo-smart-link'), # search file by name re_path(r'^api/v2.1/search-file/$', SearchFile.as_view(), name='api-v2.1-search-file'),