diff --git a/frontend/src/components/dialog/share-dialog.js b/frontend/src/components/dialog/share-dialog.js index 72eb726b18..5936d8986b 100644 --- a/frontend/src/components/dialog/share-dialog.js +++ b/frontend/src/components/dialog/share-dialog.js @@ -1,11 +1,13 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import { Modal, ModalHeader, ModalBody, TabContent, TabPane, Nav, NavItem, NavLink } from 'reactstrap'; -import { gettext, canGenerateShareLink, canGenerateUploadLink } from '../../utils/constants'; +import { gettext, username, canGenerateShareLink, canGenerateUploadLink } from '../../utils/constants'; import ShareToUser from './share-to-user'; import ShareToGroup from './share-to-group'; import GenerateShareLink from './generate-share-link'; import GenerateUploadLink from './generate-upload-link'; +import { seafileAPI } from '../../utils/seafile-api'; +import Loading from '../loading'; import '../../css/share-link-dialog.css'; const propTypes = { @@ -24,10 +26,23 @@ class ShareDialog extends React.Component { constructor(props) { super(props); this.state = { - activeTab: this.getInitialActiveTab() + activeTab: this.getInitialActiveTab(), + isRepoJudgemented: false, + isRepoOwner: false, }; } + componentDidMount() { + let repoID = this.props.repoID; + seafileAPI.getRepoInfo(repoID).then(res => { + let isRepoOwner = res.data.owner_email === username; + this.setState({ + isRepoJudgemented: true, + isRepoOwner: isRepoOwner, + }); + }); + } + getInitialActiveTab = () => { const {repoEncrypted, userPerm, enableDirPrivateShare} = this.props; const enableShareLink = !repoEncrypted && canGenerateShareLink; @@ -49,8 +64,12 @@ class ShareDialog extends React.Component { } renderDirContent = () => { - let activeTab = this.state.activeTab; + if (!this.state.isRepoJudgemented) { + return ; + } + + let activeTab = this.state.activeTab; const {repoEncrypted, userPerm, enableDirPrivateShare} = this.props; const enableShareLink = !repoEncrypted && canGenerateShareLink; const enableUploadLink = !repoEncrypted && canGenerateUploadLink && userPerm == 'rw'; @@ -112,10 +131,10 @@ class ShareDialog extends React.Component { {enableDirPrivateShare && - + - + } diff --git a/frontend/src/components/dialog/share-to-group.js b/frontend/src/components/dialog/share-to-group.js index ade573abbe..1621d0ac7e 100644 --- a/frontend/src/components/dialog/share-to-group.js +++ b/frontend/src/components/dialog/share-to-group.js @@ -36,6 +36,7 @@ class GroupItem extends React.Component { render() { let item = this.props.item; + let currentPermission = item.is_admin ? 'admin' : item.permission; return ( {item.group_info.name} @@ -43,7 +44,7 @@ class GroupItem extends React.Component { @@ -87,7 +88,8 @@ const propTypes = { isGroupOwnedRepo: PropTypes.bool, itemPath: PropTypes.string.isRequired, itemType: PropTypes.string.isRequired, - repoID: PropTypes.string.isRequired + repoID: PropTypes.string.isRequired, + isRepoOwner: PropTypes.bool.isRequired, }; const NoOptionsMessage = (props) => { @@ -108,9 +110,10 @@ class ShareToGroup extends React.Component { }; this.options = []; this.permissions = [] - if (this.props.itemType === 'library') { - this.permissions = ['rw', 'r', 'admin', 'cloud-edit', 'preview']; - } else if (this.props.itemType === 'dir') { + let { itemType, isRepoOwner } = props; + if (itemType === 'library') { + this.permissions = isRepoOwner ? ['rw', 'r', 'admin', 'cloud-edit', 'preview'] : ['rw', 'r', 'cloud-edit', 'preview']; + } else if (itemType === 'dir') { this.permissions = ['rw', 'r', 'cloud-edit', 'preview']; } if (this.props.isGroupOwnedRepo || !isPro) { @@ -251,6 +254,7 @@ class ShareToGroup extends React.Component { if (groupID === sharedItemGroupID) { sharedItem.permission = permission; } + sharedItem.is_admin = permission === 'admin' ? true : false; return sharedItem; }); this.setState({sharedItems: sharedItems}); diff --git a/frontend/src/components/dialog/share-to-user.js b/frontend/src/components/dialog/share-to-user.js index e47c81aece..85b600152e 100644 --- a/frontend/src/components/dialog/share-to-user.js +++ b/frontend/src/components/dialog/share-to-user.js @@ -88,7 +88,8 @@ const propTypes = { isGroupOwnedRepo: PropTypes.bool, itemPath: PropTypes.string.isRequired, itemType: PropTypes.string.isRequired, - repoID: PropTypes.string.isRequired + repoID: PropTypes.string.isRequired, + isRepoOwner: PropTypes.bool.isRequired, }; class ShareToUser extends React.Component { @@ -103,8 +104,9 @@ class ShareToUser extends React.Component { }; this.options = []; this.permissions = []; - if (this.props.itemType === 'library') { - this.permissions = ['rw', 'r', 'admin', 'cloud-edit', 'preview']; + let { itemType, isRepoOwner } = props; + if (itemType === 'library') { + this.permissions = isRepoOwner ? ['rw', 'r', 'admin', 'cloud-edit', 'preview'] : ['rw', 'r', 'cloud-edit', 'preview']; } else if (this.props.itemType === 'dir') { this.permissions = ['rw', 'r', 'cloud-edit', 'preview']; } @@ -319,13 +321,13 @@ class ShareToUser extends React.Component { deleteShareItem={this.deleteShareItem} onChangeUserPermission={this.onChangeUserPermission} /> - { canInvitePeople && - - - {gettext('Invite People')} - - } + {canInvitePeople && + + + {gettext('Invite People')} + + } ); diff --git a/frontend/src/components/dirent-grid-view/dirent-grid-view.js b/frontend/src/components/dirent-grid-view/dirent-grid-view.js index a34b28fc29..f808cce064 100644 --- a/frontend/src/components/dirent-grid-view/dirent-grid-view.js +++ b/frontend/src/components/dirent-grid-view/dirent-grid-view.js @@ -392,6 +392,10 @@ class DirentGridView extends React.Component{ menuList: menuList, }; + if (menuList.length === 0) { + return; + } + showMenu(showMenuConfig); } @@ -408,11 +412,17 @@ class DirentGridView extends React.Component{ let contextmenuList = []; if (isContextmenu) { let { SHARE, DOWNLOAD, DELETE } = TextTranslation; - contextmenuList = this.props.showShareBtn ? [SHARE, DOWNLOAD, DELETE, 'Divider'] : [DOWNLOAD, DELETE, 'Divider']; + contextmenuList = this.props.showShareBtn ? [SHARE] : []; - if (dirent.type === 'file') { - contextmenuList = canGenerateShareLink ? [SHARE, DOWNLOAD, DELETE, 'Divider'] : [DOWNLOAD, DELETE, 'Divider']; + if (dirent.permission === 'rw' || dirent.permission === 'r') { + contextmenuList = [...contextmenuList, DOWNLOAD]; } + + if (dirent.permission === 'rw') { + contextmenuList = [...contextmenuList, DELETE]; + } + + contextmenuList = [...contextmenuList, 'Divider']; } let { RENAME, MOVE, COPY, PERMISSION, OPEN_VIA_CLIENT, LOCK, UNLOCK, COMMENT, HISTORY, ACCESS_LOG } = TextTranslation; diff --git a/frontend/src/components/dirent-list-view/dirent-list-item.js b/frontend/src/components/dirent-list-view/dirent-list-item.js index f8c10ddaa4..cde51c86bf 100644 --- a/frontend/src/components/dirent-list-view/dirent-list-item.js +++ b/frontend/src/components/dirent-list-view/dirent-list-item.js @@ -2,7 +2,7 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import MD5 from 'MD5'; import { UncontrolledTooltip } from 'reactstrap'; -import { gettext, siteRoot, mediaUrl, username, canGenerateShareLink } from '../../utils/constants'; +import { gettext, siteRoot, mediaUrl, username } from '../../utils/constants'; import { Utils } from '../../utils/utils'; import { seafileAPI } from '../../utils/seafile-api'; import URLDecorator from '../../utils/url-decorator'; @@ -411,7 +411,7 @@ class DirentListItem extends React.Component { dragStartItemData = JSON.parse(dragStartItemData); if (Array.isArray(dragStartItemData)) { //move items let direntPaths = dragStartItemData.map(draggedItem => { - return draggedItem.nodeRootPath + return draggedItem.nodeRootPath; }); let selectedPath = Utils.joinPath(this.props.path, this.props.dirent.name); @@ -462,7 +462,7 @@ class DirentListItem extends React.Component { if (currentRepoInfo.permission === 'cloud-edit' || currentRepoInfo.permission === 'preview') { return ''; } - + return ( {selectedDirentList.length > 1 ? @@ -470,17 +470,21 @@ class DirentListItem extends React.Component { {this.state.isOperationShow && !dirent.isSelected &&
    -
  • - -
  • - {showShareBtn && -
  • - -
  • - } -
  • - -
  • + {(dirent.permission === 'rw' || dirent.permission === 'r') && ( +
  • + +
  • + )} + {showShareBtn && ( +
  • + +
  • + )} + {dirent.permission === 'rw' && ( +
  • + +
  • + )}
    • -
    • - -
    • - {showShareBtn && -
    • - -
    • - } -
    • - -
    • + {(dirent.permission === 'rw' || dirent.permission === 'r') && ( +
    • + +
    • + )} + {showShareBtn && ( +
    • + +
    • + )} + {dirent.permission === 'rw' && ( +
    • + +
    • + )}
    • +
      ); diff --git a/frontend/src/components/wiki-markdown-viewer.js b/frontend/src/components/wiki-markdown-viewer.js index 1dfca1aa27..a6bf1b8948 100644 --- a/frontend/src/components/wiki-markdown-viewer.js +++ b/frontend/src/components/wiki-markdown-viewer.js @@ -127,21 +127,25 @@ class WikiMarkdownViewer extends React.Component { changeInlineNode = (item) => { if (item.object == 'inline') { - let url; + let url, imagePath; // change image url if (item.type == 'image' && isPublicWiki) { url = item.data.src; const re = new RegExp(serviceURL + '/lib/' + repoID +'/file.*raw=1'); // different repo - if (!re.test(url)) { + if (re.test(url)) { + // get image path + let index = url.indexOf('/file'); + let index2 = url.indexOf('?'); + imagePath = url.substring(index + 5, index2); + } else if (/^\.\.\/*/.test(url) || /^\.\/*/.test(url)) { + const path = this.props.path; + const originalPath = path.slice(0, path.lastIndexOf('/')) + '/' + url; + imagePath = Utils.pathNormalize(originalPath); + } else { return; } - // get image path - let index = url.indexOf('/file'); - let index2 = url.indexOf('?'); - const imagePath = url.substring(index + 5, index2); - // replace url item.data.src = serviceURL + '/view-image-via-public-wiki/?slug=' + slug + '&path=' + imagePath; } diff --git a/frontend/src/css/work-weixin-departments.css b/frontend/src/css/work-weixin-departments.css index cd0c4a2095..9771bcd857 100644 --- a/frontend/src/css/work-weixin-departments.css +++ b/frontend/src/css/work-weixin-departments.css @@ -1,4 +1,10 @@ +.cur-view-content { + position: relative; +} .dir-content-main { + position: absolute; + right: 0; + height: 100%; width: 75%; overflow-y: hidden; padding-right: 1rem; @@ -17,13 +23,16 @@ height: 140px; } .dir-content-nav { - width: 24%; + position: fixed; overflow: hidden; } .dir-content-nav:hover { overflow: auto; } .dir-content-resize { + position: absolute; + left: 25%; + height: 100%; width: 1%; border-left: 1px solid #eee; } diff --git a/frontend/src/pages/lib-content-view/lib-content-view.js b/frontend/src/pages/lib-content-view/lib-content-view.js index e8a5d8fa5f..a02647890e 100644 --- a/frontend/src/pages/lib-content-view/lib-content-view.js +++ b/frontend/src/pages/lib-content-view/lib-content-view.js @@ -550,11 +550,11 @@ class LibContentView extends React.Component { seafileAPI.listDir(repoID, path).then(res => { let newDirentList = res.data.dirent_list; let newAddedDirents = newDirentList.filter(item => { - return !nodeChildrenNames.includes(item.name) - }) + return !nodeChildrenNames.includes(item.name); + }); newAddedDirents.map(item => { this.addNodeToTree(item.name, path, item.type); - }) + }); }); } diff --git a/frontend/src/pages/wiki/main-panel.js b/frontend/src/pages/wiki/main-panel.js index ab9c2127c8..d53a83c9db 100644 --- a/frontend/src/pages/wiki/main-panel.js +++ b/frontend/src/pages/wiki/main-panel.js @@ -116,6 +116,7 @@ class MainPanel extends Component { latestContributor={this.props.latestContributor} onLinkClick={this.props.onLinkClick} isWiki={true} + path={this.props.path} /> )} {(!this.props.isDataLoading && !this.props.isViewFile) && ( diff --git a/frontend/src/repo-snapshot.js b/frontend/src/repo-snapshot.js index b0750bfa55..39ad180dc6 100644 --- a/frontend/src/repo-snapshot.js +++ b/frontend/src/repo-snapshot.js @@ -1,7 +1,6 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { navigate } from '@reach/router'; -import moment from 'moment'; import { Utils } from './utils/utils'; import { gettext, loginUrl, siteRoot, mediaUrl, logoPath, logoWidth, logoHeight, siteTitle } from './utils/constants'; import { seafileAPI } from './utils/seafile-api'; @@ -233,26 +232,26 @@ class Content extends React.Component { } return ( - - - - {this.theadData.map((item, index) => { - return ; - })} - - - - {folderItems.map((item, index) => { - return ; - }) - } - -
      {item.text}
      + + + + {this.theadData.map((item, index) => { + return ; + })} + + + + {folderItems.map((item, index) => { + return ; + }) + } + +
      {item.text}
      ); } } diff --git a/frontend/src/utils/utils.js b/frontend/src/utils/utils.js index 9a80b81266..e1bc531b7c 100644 --- a/frontend/src/utils/utils.js +++ b/frontend/src/utils/utils.js @@ -231,8 +231,8 @@ export const Utils = { isIEBrower: function() { // is ie <= ie11 not include Edge var userAgent = navigator.userAgent; - var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1; - var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1; + var isIE = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1; + var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1; return isIE || isIE11; }, @@ -880,6 +880,21 @@ export const Utils = { return password; }, + pathNormalize: function(originalPath) { + let oldPath = originalPath.split('/'); + let newPath = []; + for (let i = 0; i < oldPath.length; i++) { + if (oldPath[i] === '.' || oldPath[i] === '') { + continue; + } else if (oldPath[i] === '..') { + newPath.pop(); + } else { + newPath.push(oldPath[i]); + } + } + return newPath.join('/'); + }, + getEventData: function(event, data) { if (event.target.dataset) { return event.target.dataset[data]; diff --git a/seahub/api2/views.py b/seahub/api2/views.py index 891038df71..9c5ea0a18c 100644 --- a/seahub/api2/views.py +++ b/seahub/api2/views.py @@ -641,6 +641,7 @@ def repo_download_info(request, repo_id, gen_sync_token=True): 'random_key': random_key, 'repo_version': repo_version, 'head_commit_id': repo.head_cmmt_id, + 'permission': seafile_api.check_permission_by_path(repo_id, '/', email) } if is_pro_version() and ENABLE_STORAGE_CLASSES: