diff --git a/frontend/config/webpack.config.dev.js b/frontend/config/webpack.config.dev.js index 0c426d09b8..71a6d27c11 100644 --- a/frontend/config/webpack.config.dev.js +++ b/frontend/config/webpack.config.dev.js @@ -64,11 +64,6 @@ module.exports = { require.resolve('react-dev-utils/webpackHotDevClient'), paths.appSrc + "/wiki.js", ], - repoview: [ - require.resolve('./polyfills'), - require.resolve('react-dev-utils/webpackHotDevClient'), - paths.appSrc + "/repo-wiki-mode.js", - ], fileHistory: [ require.resolve('./polyfills'), require.resolve('react-dev-utils/webpackHotDevClient'), diff --git a/frontend/config/webpack.config.prod.js b/frontend/config/webpack.config.prod.js index eb220a7562..116ca73066 100644 --- a/frontend/config/webpack.config.prod.js +++ b/frontend/config/webpack.config.prod.js @@ -61,7 +61,6 @@ module.exports = { markdownEditor: [require.resolve('./polyfills'), paths.appIndexJs], TCAccept: [require.resolve('./polyfills'), paths.appSrc + "/tc-accept.js"], wiki: [require.resolve('./polyfills'), paths.appSrc + "/wiki.js"], - repoview: [require.resolve('./polyfills'), paths.appSrc + "/repo-wiki-mode.js"], fileHistory: [require.resolve('./polyfills'), paths.appSrc + "/file-history.js"], fileHistoryOld: [require.resolve('./polyfills'), paths.appSrc + "/file-history-old.js"], app: [require.resolve('./polyfills'), paths.appSrc + "/app.js"], 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 6720ba3d14..0c70345407 100644 --- a/frontend/src/components/dirent-list-view/dirent-list-item.js +++ b/frontend/src/components/dirent-list-view/dirent-list-item.js @@ -494,13 +494,10 @@ class DirentListItem extends React.Component { } renderItemOperation = () => { - let { dirent, selectedDirentList } = this.props; + let { dirent, currentRepoInfo, selectedDirentList } = this.props; - // no need to check whether show shareBtn or not. - // according to specification below, shareBtn aways show. - // check for "generate uploadlink" or other tabs should put inside the shareDialog. // https://dev.seafile.com/seahub/lib/d6f300e7-bb2b-4722-b83e-cf45e370bfbc/file/seaf-server%20%E5%8A%9F%E8%83%BD%E8%AE%BE%E8%AE%A1/%E6%9D%83%E9%99%90%E7%9B%B8%E5%85%B3/%E8%B5%84%E6%96%99%E5%BA%93%E6%9D%83%E9%99%90%E8%A7%84%E8%8C%83.md - // let showShareBtn = Utils.isHasPermissionToShare(currentRepoInfo, dirent.permission, dirent); + let showShareBtn = Utils.isHasPermissionToShare(currentRepoInfo, dirent.permission, dirent); return ( @@ -514,9 +511,11 @@ class DirentListItem extends React.Component { )} -
  • - -
  • + {showShareBtn && ( +
  • + +
  • + )} {dirent.permission === 'rw' && (
  • @@ -546,7 +545,7 @@ class DirentListItem extends React.Component {
  • )} - {( + {showShareBtn && (
  • diff --git a/frontend/src/components/file-uploader/file-uploader.js b/frontend/src/components/file-uploader/file-uploader.js index 247ae84626..7aebac3d70 100644 --- a/frontend/src/components/file-uploader/file-uploader.js +++ b/frontend/src/components/file-uploader/file-uploader.js @@ -2,7 +2,7 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import Resumablejs from '@seafile/resumablejs'; import MD5 from 'MD5'; -import { enableResumableFileUpload, resumableUploadFileBlockSize } from '../../utils/constants'; +import { enableResumableFileUpload, resumableUploadFileBlockSize, maxUploadFileSize } from '../../utils/constants'; import { seafileAPI } from '../../utils/seafile-api'; import { Utils } from '../../utils/utils'; import { gettext } from '../../utils/constants'; @@ -18,13 +18,11 @@ const propTypes = { chunkSize: PropTypes.number, withCredentials: PropTypes.bool, maxFiles: PropTypes.number, - maxFileSize: PropTypes.number, testMethod: PropTypes.string, testChunks: PropTypes.number, simultaneousUploads: PropTypes.number, fileParameterName: PropTypes.string, maxFilesErrorCallback: PropTypes.func, - maxFileSizeErrorCallback: PropTypes.func, minFileSizeErrorCallback: PropTypes.func, fileTypeErrorCallback: PropTypes.func, dragAndDrop: PropTypes.bool.isRequired, @@ -39,6 +37,7 @@ class FileUploader extends React.Component { this.state = { retryFileList: [], uploadFileList: [], + forbidUploadFileList: [], totalProgress: 0, isUploadProgressDialogShow: false, isUploadRemindDialogShow: false, @@ -64,7 +63,7 @@ class FileUploader extends React.Component { query: this.setQuery || {}, fileType: this.props.filetypes, maxFiles: this.props.maxFiles, - maxFileSize: this.props.maxFileSize, + maxFileSize: maxUploadFileSize * 1000 * 1000 || undefined, testMethod: this.props.testMethod || 'post', testChunks: this.props.testChunks || false, headers: this.setHeaders || {}, @@ -105,7 +104,7 @@ class FileUploader extends React.Component { } bindCallbackHandler = () => { - let {maxFilesErrorCallback, minFileSizeErrorCallback, maxFileSizeErrorCallback, fileTypeErrorCallback } = this.props; + let {maxFilesErrorCallback, minFileSizeErrorCallback, fileTypeErrorCallback } = this.props; if (maxFilesErrorCallback) { this.resumable.opts.maxFilesErrorCallback = this.props.maxFilesErrorCallback; @@ -115,8 +114,8 @@ class FileUploader extends React.Component { this.resumable.opts.minFileSizeErrorCallback = this.props.minFileSizeErrorCallback; } - if (maxFileSizeErrorCallback) { - this.resumable.opts.maxFileSizeErrorCallback = this.props.maxFileSizeErrorCallback; + if (this.maxFileSizeErrorCallback) { + this.resumable.opts.maxFileSizeErrorCallback = this.maxFileSizeErrorCallback; } if (fileTypeErrorCallback) { @@ -142,6 +141,12 @@ class FileUploader extends React.Component { this.resumable.on('dragstart', this.onDragStart.bind(this)); } + maxFileSizeErrorCallback = (file) => { + let { forbidUploadFileList } = this.state; + forbidUploadFileList.push(file); + this.setState({forbidUploadFileList: forbidUploadFileList}); + } + onChunkingComplete = (resumableFile) => { let allFilesUploaded = this.state.allFilesUploaded; @@ -229,7 +234,13 @@ class FileUploader extends React.Component { } filesAddedComplete = (resumable, files) => { - // single file uploading can check repetition, because custom dialog conn't prevent program execution; + let { forbidUploadFileList } = this.state; + if (forbidUploadFileList.length > 0 && files.length === 0) { + this.setState({ + isUploadProgressDialogShow: true, + totalProgress: 100 + }); + } } setUploadFileList = () => { @@ -377,7 +388,16 @@ class FileUploader extends React.Component { if (!message) { error = gettext('Network error'); } else { - error = message; + // eg: '{"error": "Internal error" \n }' + let errorMessage = message.replace(/\n/g, ''); + errorMessage = JSON.parse(errorMessage); + error = errorMessage.error; + if (error === 'File locked by others.') { + error = gettext('File Locked by others.'); + } + if (error === 'Internal error.') { + error = gettext('Internal error.'); + } } let uploadFileList = this.state.uploadFileList.map(item => { @@ -481,7 +501,7 @@ class FileUploader extends React.Component { this.resumable.files = []; // reset upload link loaded this.isUploadLinkLoaded = false; - this.setState({isUploadProgressDialogShow: false, uploadFileList: []}); + this.setState({isUploadProgressDialogShow: false, uploadFileList: [], forbidUploadFileList: []}); Utils.registerGlobalVariable('uploader', 'isUploadProgressDialogShow', false); } @@ -667,6 +687,7 @@ class FileUploader extends React.Component { + +
    {file.name}
    + + + {msg} + + ); + } +} + +ForbidUploadListItem.propTypes = propTypes; + +export default ForbidUploadListItem; diff --git a/frontend/src/components/file-uploader/upload-progress-dialog.js b/frontend/src/components/file-uploader/upload-progress-dialog.js index 2cbfecbf68..7a94726e62 100644 --- a/frontend/src/components/file-uploader/upload-progress-dialog.js +++ b/frontend/src/components/file-uploader/upload-progress-dialog.js @@ -1,14 +1,16 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import { gettext } from '../../utils/constants'; -import UploadListItem from './upload-list-item'; import { Utils } from '../../utils/utils'; +import UploadListItem from './upload-list-item'; +import ForbidUploadListItem from './forbid-upload-list-item'; const propTypes = { uploadBitrate: PropTypes.number.isRequired, totalProgress: PropTypes.number.isRequired, retryFileList: PropTypes.array.isRequired, uploadFileList: PropTypes.array.isRequired, + forbidUploadFileList: PropTypes.array.isRequired, onCloseUploadDialog: PropTypes.func.isRequired, onCancelAllUploading: PropTypes.func.isRequired, onUploadCancel: PropTypes.func.isRequired, @@ -94,6 +96,11 @@ class UploadProgressDialog extends React.Component { } + { + this.props.forbidUploadFileList.map((file, index) => { + return (); + }) + } { this.props.uploadFileList.map((resumableFile, index) => { return ( 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 f708bc0834..3b460d4354 100644 --- a/frontend/src/pages/lib-content-view/lib-content-view.js +++ b/frontend/src/pages/lib-content-view/lib-content-view.js @@ -1264,7 +1264,11 @@ class LibContentView extends React.Component { let direntList = this.state.direntList.filter(item => { return item.name !== name; }); - this.setState({ direntList: direntList }); + + // Recalculate the state of the selection + this.recaculateSelectedStateAfterDirentDeleted(name, direntList); + + this.setState({direntList: direntList}); this.updateReadmeMarkdown(direntList); } else if (Utils.isAncestorPath(direntPath, this.state.path)) { // the deleted item is ancester of the current item @@ -1283,6 +1287,10 @@ class LibContentView extends React.Component { let direntList = this.state.direntList.filter(item => { return item.name !== name; }); + + // Recalculate the state of the selection + this.recaculateSelectedStateAfterDirentDeleted(name, direntList); + this.setState({direntList: direntList}); this.updateReadmeMarkdown(direntList); } @@ -1531,6 +1539,20 @@ class LibContentView extends React.Component { }); } + recaculateSelectedStateAfterDirentDeleted = (name, newDirentList) => { + let selectedDirentList = this.state.selectedDirentList.slice(0); + if (selectedDirentList.length > 0) { + selectedDirentList = selectedDirentList.filter(item => { + return item.name !== name; + }); + } + this.setState({ + selectedDirentList: selectedDirentList, + isDirentSelected: selectedDirentList.length > 0, + isAllDirentSelected: selectedDirentList.length === newDirentList.length, + }); + } + onLibDecryptDialog = () => { this.setState({libNeedDecrypt: false}); this.loadDirData(this.state.path); diff --git a/frontend/src/pages/repo-wiki-mode/main-panel.js b/frontend/src/pages/repo-wiki-mode/main-panel.js deleted file mode 100644 index 3929b27005..0000000000 --- a/frontend/src/pages/repo-wiki-mode/main-panel.js +++ /dev/null @@ -1,315 +0,0 @@ -import React, { Component, Fragment } from 'react'; -import PropTypes from 'prop-types'; -import cookie from 'react-cookies'; -import { gettext, repoID, siteRoot, permission } from '../../utils/constants'; -import { seafileAPI } from '../../utils/seafile-api'; -import { Utils } from '../../utils/utils'; -import RepoInfo from '../../models/repo-info'; -import CommonToolbar from '../../components/toolbar/common-toolbar'; -import ViewModeToolbar from '../../components/toolbar/view-mode-toolbar'; -import DirOperationToolBar from '../../components/toolbar/dir-operation-toolbar'; -import MultipleDirOperationToolbar from '../../components/toolbar/multiple-dir-operation-toolbar'; -import CurDirPath from '../../components/cur-dir-path'; -import WikiMarkdownViewer from '../../components/wiki-markdown-viewer'; -import DirentListView from '../../components/dirent-list-view/dirent-list-view'; -import DirentDetail from '../../components/dirent-detail/dirent-details'; -import FileUploader from '../../components/file-uploader/file-uploader'; -import RepoInfoBar from '../../components/repo-info-bar'; - -const propTypes = { - content: PropTypes.string, - lastModified: PropTypes.string, - latestContributor: PropTypes.string, - permission: PropTypes.string, - hash: PropTypes.string, - path: PropTypes.string.isRequired, - repoName: PropTypes.string.isRequired, - repoEncrypted: PropTypes.bool.isRequired, - showShareBtn: PropTypes.bool.isRequired, - enableDirPrivateShare: PropTypes.bool.isRequired, - userPerm: PropTypes.string.isRequired, - isAdmin: PropTypes.bool.isRequired, - isGroupOwnedRepo: PropTypes.bool.isRequired, - // whether the file or dir corresponding to the path exist - pathExist: PropTypes.bool.isRequired, - isFileLoading: PropTypes.bool.isRequired, - isViewFile: PropTypes.bool.isRequired, - isDirentListLoading: PropTypes.bool.isRequired, - isDirentSelected: PropTypes.bool.isRequired, - isAllDirentSelected: PropTypes.bool.isRequired, - direntList: PropTypes.array.isRequired, - sortBy: PropTypes.string.isRequired, - sortOrder: PropTypes.string.isRequired, - sortItems: PropTypes.func.isRequired, - selectedDirentList: PropTypes.array.isRequired, - updateDirent: PropTypes.func.isRequired, - onSideNavMenuClick: PropTypes.func.isRequired, - onSearchedClick: PropTypes.func.isRequired, - onMainNavBarClick: PropTypes.func.isRequired, - onItemClick: PropTypes.func.isRequired, - onAllDirentSelected: PropTypes.func.isRequired, - onItemSelected: PropTypes.func.isRequired, - onItemDelete: PropTypes.func.isRequired, - onItemRename: PropTypes.func.isRequired, - onItemMove: PropTypes.func.isRequired, - onItemCopy: PropTypes.func.isRequired, - onAddFile: PropTypes.func.isRequired, - onAddFolder: PropTypes.func.isRequired, - onFileTagChanged: PropTypes.func.isRequired, - onItemsMove: PropTypes.func.isRequired, - onItemsCopy: PropTypes.func.isRequired, - onItemsDelete: PropTypes.func.isRequired, - onLinkClick: PropTypes.func.isRequired, - onFileUploadSuccess: PropTypes.func.isRequired, - isDraft: PropTypes.bool, - hasDraft: PropTypes.bool, - goDraftPage: PropTypes.func, - usedRepoTags: PropTypes.array.isRequired, - readmeMarkdown: PropTypes.object, - draftCounts: PropTypes.number, - updateUsedRepoTags: PropTypes.func.isRequired, -}; - -class MainPanel extends Component { - - constructor(props) { - super(props); - this.state = { - currentMode: 'wiki', - isDirentDetailShow: false, - currentDirent: null, - direntPath: '', - currentRepoInfo: null, - }; - } - - componentDidMount() { - seafileAPI.getRepoInfo(repoID).then(res => { - let repoInfo = new RepoInfo(res.data); - this.setState({ - currentRepoInfo: repoInfo, - }); - }); - if (this.props.hash) { - let hash = this.props.hash; - setTimeout(function() { - window.location.hash = hash; - }, 500); - } - } - - switchViewMode = (mode) => { - cookie.save('view_mode', mode, { path: '/' }); - let repoName = this.state.currentRepoInfo.repo_name; - let dirPath = this.props.isViewFile ? Utils.getDirName(this.props.path) : this.props.path; - window.location.href = siteRoot + 'library/' + repoID + '/' + repoName + dirPath; - } - - onSideNavMenuClick = () => { - this.props.onSideNavMenuClick(); - } - - onItemClick = (dirent) => { - this.setState({isDirentDetailShow: false}); - this.props.onItemClick(dirent); - } - - - onMainNavBarClick = (path) => { - this.setState({isDirentDetailShow: false}); - this.props.onMainNavBarClick(path); - } - - // on '' - onDirentClick = (dirent) => { - if (this.state.isDirentDetailShow) { - this.onItemDetails(dirent); - } - } - - onItemDetails = (dirent) => { - this.setState({ - currentDirent: dirent, - isDirentDetailShow: true, - }); - } - - onItemDetailsClose = () => { - this.setState({isDirentDetailShow: false}); - } - - onFileTagChanged = (dirent, direntPath) => { - this.props.onFileTagChanged(dirent, direntPath); - } - - onUploadFile = (e) => { - e.nativeEvent.stopImmediatePropagation(); - this.uploader.onFileUpload(); - } - - onUploadFolder = (e) => { - e.nativeEvent.stopImmediatePropagation(); - this.uploader.onFolderUpload(); - } - - onFileUploadSuccess = (direntObject) => { - this.props.onFileUploadSuccess(direntObject); - } - - render() { - - const ErrMessage = (
    {gettext('Folder does not exist.')}
    ); - const showRepoInfoBar = this.props.path === '/' && ( - this.props.usedRepoTags.length != 0 || this.props.readmeMarkdown != null || - this.props.draftCounts != 0); - - return ( -
    -
    -
    - -
    - {this.props.isDirentSelected ? - : - - } -
    - -
    - -
    -
    -
    -
    - {this.state.currentRepoInfo && ( - - )} -
    -
    - {!this.props.pathExist && ErrMessage } - {(this.props.pathExist && this.props.isViewFile) && ( - - - {(!this.props.isDraft && this.props.hasDraft) && -
    -
    - {gettext('This file is in draft stage.')} - {gettext('View Draft')} -
    -
    - } -
    -
    - )} - {(this.props.pathExist && !this.props.isViewFile) && ( - - {showRepoInfoBar && ( - - )} - - this.uploader = uploader} - dragAndDrop={true} - path={this.props.path} - repoID={repoID} - direntList={this.props.direntList} - onFileUploadSuccess={this.onFileUploadSuccess} - /> - - )} -
    -
    - {this.state.isDirentDetailShow && ( -
    - -
    - )} -
    -
    - ); - } -} - -MainPanel.propTypes = propTypes; - -export default MainPanel; diff --git a/frontend/src/repo-wiki-mode.js b/frontend/src/repo-wiki-mode.js deleted file mode 100644 index 169e0c284d..0000000000 --- a/frontend/src/repo-wiki-mode.js +++ /dev/null @@ -1,1113 +0,0 @@ -import React, { Component } from 'react'; -import ReactDOM from 'react-dom'; -import moment from 'moment'; -import { gettext, repoID, siteRoot, initialPath, isDir, canGenerateShareLink, canGenerateUploadLink, username, isDocs } from './utils/constants'; -import { seafileAPI } from './utils/seafile-api'; -import { Utils } from './utils/utils'; -import collabServer from './utils/collab-server'; -import SidePanel from './pages/repo-wiki-mode/side-panel'; -import MainPanel from './pages/repo-wiki-mode/main-panel'; -import TreeNode from './components/tree-view/tree-node'; -import treeHelper from './components/tree-view/tree-helper'; -import toaster from './components/toast'; -import LibDecryptDialog from './components/dialog/lib-decrypt-dialog'; -import ModalPortal from './components/modal-portal'; -import Dirent from './models/dirent'; -import FileTag from './models/file-tag'; -import RepoTag from './models/repo-tag'; -import RepoInfo from './models/repo-info'; - -import './assets/css/fa-solid.css'; -import './assets/css/fa-regular.css'; -import './assets/css/fontawesome.css'; -import './css/layout.css'; -import './css/side-panel.css'; -import './css/wiki.css'; -import './css/toolbar.css'; -import './css/search.css'; - -class Wiki extends Component { - constructor(props) { - super(props); - this.state = { - repoName: '', - repoEncrypted: false, - isGroupOwnedRepo: false, - isAdmin: false, - ownerEmail: '', - userPerm: '', - - path: '', - pathExist: true, - treeData: treeHelper.buildTree(), - closeSideBar: false, - currentNode: null, - isTreeDataLoading: true, - isDirentListLoading: true, - isViewFile: false, - sortBy: 'name', // 'name' or 'time' - sortOrder: 'asc', // 'asc' or 'desc' - direntList: [], - isFileLoading: true, - content: '', - lastModified: '', - latestContributor: '', - permission: '', - isDirentSelected: false, - isAllDirentSelected: false, - selectedDirentList: [], - libNeedDecrypt: false, - isDraft: false, - hasDraft: false, - draftID: '', - dirID: '', - usedRepoTags: [], - readmeMarkdown: null, - draftCounts: 0, - }; - window.onpopstate = this.onpopstate; - this.hash = ''; - this.lastModifyTime = new Date(); - } - - componentWillMount() { - const hash = window.location.hash; - if (hash.slice(0, 1) === '#') { - this.hash = hash; - } - } - - componentDidMount() { - seafileAPI.getRepoInfo(repoID).then(res => { - let repoInfo = new RepoInfo(res.data); - this.setState({ - libNeedDecrypt: res.data.lib_need_decrypt, - repoName: repoInfo.repo_name, - repoEncrypted: repoInfo.encrypted, - isVirtual: repoInfo.is_virtual, - isAdmin: repoInfo.is_admin, - ownerEmail: repoInfo.owner_email - }); - - const ownerEmail = repoInfo.owner_email; - if (repoInfo.owner_email.indexOf('@seafile_group') != -1) { - const groupID = ownerEmail.substring(0, ownerEmail.indexOf('@')); - this.getGroupInfo(groupID); - this.setState({ - isGroupOwnedRepo: true - }); - } - - if (!res.data.lib_need_decrypt) { - this.loadWikiData(); - } - }); - } - - componentWillUnmount() { - collabServer.unwatchRepo(repoID, this.onRepoUpdateEvent); - } - - componentDidUpdate() { - this.lastModifyTime = new Date(); - } - - getGroupInfo = (groupID) => { - seafileAPI.getGroup(groupID).then(res => { - if (res.data.admins.indexOf(username) != -1) { - this.setState({isDepartmentAdmin: true}); - } - }); - } - - onRepoUpdateEvent = () => { - let currentTime = new Date(); - if ((parseFloat(currentTime - this.lastModifyTime)/1000) <= 5) { - return; - } - let { path, dirID } = this.state; - seafileAPI.dirMetaData(repoID, path).then((res) => { - if (res.data.id !== dirID) { - toaster.notify( - - {gettext('This folder has been updated. ')} - {gettext('Refresh')} - , - {id: 'repo_updated', duration: 3600} - ); - } - }); - } - - loadWikiData = () => { - // listen current repo - collabServer.watchRepo(repoID, this.onRepoUpdateEvent); - - // list used FileTags - this.updateUsedRepoTags(); - - // list draft counts and revierw counts - if (isDocs) { - seafileAPI.getRepoDraftCounts(repoID).then(res => { - this.setState({ - draftCounts: res.data.draft_counts, - }); - }); - } - - // load side-panel data - this.loadSidePanel(initialPath); - - // load main-panel data - if (isDir === 'None') { - this.setState({pathExist: false}); - } else if (isDir === 'True') { - this.showDir(initialPath); - } else if (isDir === 'False') { - this.showFile(initialPath); - } - - } - - loadSidePanel = (initialPath) => { - - if (initialPath === '/' || isDir === 'None') { - seafileAPI.listDir(repoID, '/').then(res => { - let tree = this.state.treeData; - this.addResponseListToNode(res.data.dirent_list, tree.root); - this.setState({ - isTreeDataLoading: false, - treeData: tree - }); - }).catch(() => { - this.setState({isLoadFailed: true}); - }); - } else { - this.loadNodeAndParentsByPath(initialPath); - } - } - - showDir = (path) => { - this.loadDirentList(path); - this.setState({ - path: path, - isViewFile: false - }); - - // update location url - let url = siteRoot + 'wiki/lib/' + repoID + Utils.encodePath(path); - window.history.pushState({ url: url, path: path}, path, url); - } - - showFile = (filePath) => { - this.setState({ - path: filePath, - isViewFile: true - }); - - this.setState({isFileLoading: true}); - seafileAPI.getFileInfo(repoID, filePath).then((res) => { - let { mtime, permission, last_modifier_name, is_draft, has_draft, draft_id } = res.data; - seafileAPI.getFileDownloadLink(repoID, filePath).then((res) => { - seafileAPI.getFileContent(res.data).then((res) => { - this.setState({ - content: res.data, - permission: permission, - latestContributor: last_modifier_name, - lastModified: moment.unix(mtime).fromNow(), - isFileLoading: false, - isDraft: is_draft, - hasDraft: has_draft, - draftID: draft_id - }); - }); - }); - }); - - let fileUrl = siteRoot + 'wiki/lib/' + repoID + Utils.encodePath(filePath); - window.history.pushState({url: fileUrl, path: filePath}, filePath, fileUrl); - } - - updateReadmeMarkdown = (direntList) => { - this.setState({readmeMarkdown: null}); - direntList.some(item => { - let fileName = item.name.toLowerCase(); - if (fileName === 'readme.md' || fileName === 'readme.markdown') { - this.setState({readmeMarkdown: item}); - return true; - } - }); - } - - loadDirentList = (path) => { - this.setState({isDirentListLoading: true}); - seafileAPI.listDir(repoID, path, {'with_thumbnail': true}).then(res => { - let direntList = []; - res.data.dirent_list.forEach(item => { - let fileName = item.name.toLowerCase(); - if (fileName === 'readme.md' || fileName === 'readme.markdown') { - this.setState({readmeMarkdown: item}); - } - let dirent = new Dirent(item); - direntList.push(dirent); - }); - - this.setState({ - userPerm: res.data.user_perm, - direntList: Utils.sortDirents(direntList, this.state.sortBy, this.state.sortOrder), - isDirentListLoading: false, - dirID: res.data.dir_id, - }); - - if (!this.state.repoEncrypted && direntList.length) { - this.getThumbnails(repoID, path, this.state.direntList); - } - }); - } - - getThumbnails = (repoID, path, direntList) => { - let items = direntList.filter((item) => { - return Utils.imageCheck(item.name) && !item.encoded_thumbnail_src; - }); - if (items.length == 0) { - return ; - } - - const _this = this; - const len = items.length; - const thumbnailSize = 48; - let getThumbnail = (i) => { - const curItem = items[i]; - const curItemPath = [path, curItem.name].join('/'); - seafileAPI.createThumbnail(repoID, curItemPath, thumbnailSize).then((res) => { - curItem.encoded_thumbnail_src = res.data.encoded_thumbnail_src; - }).catch((error) => { - // do nothing - }).then(() => { - if (i < len - 1) { - getThumbnail(++i); - } else { - _this.setState({ - direntList: direntList - }); - } - }); - }; - getThumbnail(0); - } - - onLinkClick = (link) => { - const url = link; - if (Utils.isInternalMarkdownLink(url, repoID)) { - let path = Utils.getPathFromInternalMarkdownLink(url, repoID); - this.showFile(path); - } else if (Utils.isInternalDirLink(url, repoID)) { - let path = Utils.getPathFromInternalDirLink(url, repoID); - this.showDir(path); - } else { - window.open(url); - } - } - - updateUsedRepoTags = () => { - seafileAPI.listRepoTags(repoID).then(res => { - let usedRepoTags = []; - res.data.repo_tags.forEach(item => { - let usedRepoTag = new RepoTag(item); - if (usedRepoTag.fileCount > 0) { - usedRepoTags.push(usedRepoTag); - } - }); - this.setState({usedRepoTags: usedRepoTags}); - }); - } - - updateDirent = (dirent, paramKey, paramValue) => { - let newDirentList = this.state.direntList.map(item => { - if (item.name === dirent.name) { - item[paramKey] = paramValue; - } - return item; - }); - this.setState({direntList: newDirentList}); - } - - onpopstate = (event) => { - if (event.state && event.state.path) { - let path = event.state.path; - if (Utils.isMarkdownFile(path)) { - this.showFile(path); - } else { - this.loadDirentList(path); - this.setState({ - path: path, - isViewFile: false - }); - } - } - } - - onSearchedClick = (item) => { - let path = item.is_dir ? item.path.slice(0, item.path.length - 1) : item.path; - if (this.state.currentPath === path) { - return; - } - - // load sidePanel - let index = -1; - let paths = Utils.getPaths(path); - for (let i = 0; i < paths.length; i++) { - let node = this.state.treeData.getNodeByPath(node); - if (!node) { - index = i; - break; - } - } - if (index === -1) { // all the data has been loaded already. - let node = this.state.treeData.getNodeByPath(path); - this.setState({currentNode: node}); - } else { - this.loadNodeAndParentsByPath(path); - } - - // load mainPanel - if (item.is_dir) { - this.showDir(path); - } else { - if (Utils.isMarkdownFile(path)) { - this.showFile(path); - } else { - let url = siteRoot + 'lib/' + item.repo_id + '/file' + Utils.encodePath(path); - let newWindow = window.open('about:blank'); - newWindow.location.href = url; - } - } - } - - onMainNavBarClick = (nodePath) => { - //just for dir - this.resetSelected(); - let tree = this.state.treeData.clone(); - let node = tree.getNodeByPath(nodePath); - tree.expandNode(node); - - this.setState({treeData: tree, currentNode: node}); - this.showDir(node.path); - } - - onAddFolder = (dirPath) => { - // todo Double name check - seafileAPI.createDir(repoID, dirPath).then(() => { - let name = Utils.getFileName(dirPath); - let parentPath = Utils.getDirName(dirPath); - - this.addNodeToTree(name, parentPath, 'dir'); - if (parentPath === this.state.path && !this.state.isViewFile) { - this.addDirent(name, 'dir'); - } - }).catch(() => { - // return error message - }); - } - - onAddFile = (filePath, isDraft) => { - // Double name check - seafileAPI.createFile(repoID, filePath, isDraft).then(res => { - let name = Utils.getFileName(filePath); - let parentPath = Utils.getDirName(filePath); - - this.addNodeToTree(name, parentPath, 'file'); - if (parentPath === this.state.path && !this.state.isViewFile) { - this.addDirent(name, 'file', res.data.size); - } - }).catch(() => { - // todo - }); - } - - onRenameTreeNode = (node, newName) => { - this.renameItem(node.path, node.object.isDir(), newName); - } - - onDeleteTreeNode = (node) => { - this.deleteItem(node.path, node.object.isDir()); - } - - onMainPanelItemRename = (dirent, newName) => { - let path = Utils.joinPath(this.state.path, dirent.name); - this.renameItem(path, dirent.isDir(), newName); - } - - onMainPanelItemDelete = (dirent) => { - let path = Utils.joinPath(this.state.path, dirent.name); - this.deleteItem(path, dirent.isDir()); - } - - renameItem = (path, isDir, newName) => { - //validate task - if (isDir) { - seafileAPI.renameDir(repoID, path, newName).then(() => { - this.renameItemAjaxCallback(path, newName); - }).catch(() => { - //todos; - }); - } else { - seafileAPI.renameFile(repoID, path, newName).then(() => { - this.renameItemAjaxCallback(path, newName); - }).catch(() => { - //todos; - }); - } - } - - renameItemAjaxCallback(path, newName) { - this.renameTreeNode(path, newName); - this.renameDirent(path, newName); - } - - deleteItem(path, isDir) { - if (isDir) { - seafileAPI.deleteDir(repoID, path).then(() => { - this.deleteItemAjaxCallback(path, isDir); - }).catch(() => { - //todos; - }); - } else { - seafileAPI.deleteFile(repoID, path).then(() => { - this.deleteItemAjaxCallback(path, isDir); - }).catch(() => { - //todos; - }); - } - } - - deleteItemAjaxCallback(path) { - this.deleteTreeNode(path); - this.deleteDirent(path); - } - - onMoveItem = (destRepo, dirent, moveToDirentPath) => { - //just for view list state - let dirName = dirent.name; - let direntPath = Utils.joinPath(this.state.path, dirName); - seafileAPI.moveDir(repoID, destRepo.repo_id,moveToDirentPath, this.state.path, dirName).then(res => { - let nodeName = res.data[0].obj_name; - this.moveTreeNode(direntPath, moveToDirentPath, destRepo, nodeName); - this.moveDirent(direntPath); - - let message = gettext('Successfully moved %(name)s.'); - message = message.replace('%(name)s', dirName); - toaster.success(message); - }).catch(() => { - let message = gettext('Failed to move %(name)s'); - message = message.replace('%(name)s', dirName); - toaster.danger(message); - }); - } - - onCopyItem = (destRepo, dirent, copyToDirentPath) => { - //just for view list state - let dirName = dirent.name; - let direntPath = Utils.joinPath(this.state.path, dirName); - seafileAPI.copyDir(repoID, destRepo.repo_id, copyToDirentPath, this.state.path, dirName).then(res => { - let nodeName = res.data[0].obj_name; - this.copyTreeNode(direntPath, copyToDirentPath, destRepo, nodeName); - let message = gettext('Successfully copied %(name)s.'); - message = message.replace('%(name)s', dirName); - toaster.success(message); - }).catch(() => { - let message = gettext('Failed to copy %(name)s'); - message = message.replace('%(name)s', dirName); - toaster.danger(message); - }); - } - - onMoveItems = (destRepo, destDirentPath) => { - let direntPaths = this.getSelectedDirentPaths(); - let dirNames = this.getSelectedDirentNames(); - - seafileAPI.moveDir(repoID, destRepo.repo_id, destDirentPath, this.state.path, dirNames).then(res => { - let names = res.data.map(item => { - return item.obj_name; - }); - direntPaths.forEach((direntPath, index) => { - this.moveTreeNode(direntPath, destDirentPath, destRepo, names[index]); - this.moveDirent(direntPath); - }); - let message = Utils.getMoveSuccessMessage(dirNames); - toaster.success(message); - }).catch(() => { - let message = Utils.getMoveFailedMessage(dirNames); - toaster.danger(message); - }); - } - - onCopyItems = (destRepo, destDirentPath) => { - let direntPaths = this.getSelectedDirentPaths(); - let dirNames = this.getSelectedDirentNames(); - - seafileAPI.copyDir(repoID, destRepo.repo_id, destDirentPath, this.state.path, dirNames).then(res => { - let names = res.data.map(item => { - return item.obj_name; - }); - direntPaths.forEach((direntPath, index) => { - this.copyTreeNode(direntPath, destDirentPath, destRepo, names[index]); - }); - let message = Utils.getCopySuccessfulMessage(dirNames); - toaster.success(message); - }).catch(() => { - let message = Utils.getCopyFailedMessage(dirNames); - toaster.danger(message); - }); - } - - onDeleteItems = () => { - let direntPaths = this.getSelectedDirentPaths(); - let dirNames = this.getSelectedDirentNames(); - - seafileAPI.deleteMutipleDirents(repoID, this.state.path, dirNames).then(res => { - direntPaths.forEach(direntPath => { - this.deleteTreeNode(direntPath); - this.deleteDirent(direntPath); - }); - }); - } - - onDirentClick = (dirent) => { - this.resetSelected(); - let direntPath = Utils.joinPath(this.state.path, dirent.name); - if (dirent.isDir()) { // is dir - this.loadTreeNodeByPath(direntPath); - this.showDir(direntPath); - } else { // is file - if (Utils.isMarkdownFile(direntPath)) { - this.showFile(direntPath); - } else { - const w=window.open('about:blank'); - const url = siteRoot + 'lib/' + repoID + '/file' + Utils.encodePath(direntPath); - w.location.href = url; - } - } - } - - onDirentSelected = (dirent) => { - let direntList = this.state.direntList.map(item => { - if (item.name === dirent.name) { - item.isSelected = !item.isSelected; - } - return item; - }); - let selectedDirentList = direntList.filter(item => { - return item.isSelected; - }); - - if (selectedDirentList.length) { - this.setState({isDirentSelected: true}); - if (selectedDirentList.length === direntList.length) { - this.setState({ - isAllDirentSelected: true, - direntList: direntList, - selectedDirentList: selectedDirentList, - }); - } else { - this.setState({ - isAllDirentSelected: false, - direntList: direntList, - selectedDirentList: selectedDirentList - }); - } - } else { - this.setState({ - isDirentSelected: false, - isAllDirentSelected: false, - direntList: direntList, - selectedDirentList: [] - }); - } - } - - onAllDirentSelected = () => { - if (this.state.isAllDirentSelected) { - let direntList = this.state.direntList.map(item => { - item.isSelected = false; - return item; - }); - this.setState({ - isDirentSelected: false, - isAllDirentSelected: false, - direntList: direntList, - selectedDirentList: [], - }); - } else { - let direntList = this.state.direntList.map(item => { - item.isSelected = true; - return item; - }); - this.setState({ - isDirentSelected: true, - isAllDirentSelected: true, - direntList: direntList, - selectedDirentList: direntList, - }); - } - } - - onFileTagChanged = (dirent, direntPath) => { - seafileAPI.listFileTags(repoID, direntPath).then(res => { - let fileTags = res.data.file_tags.map(item => { - return new FileTag(item); - }); - this.updateDirent(dirent, 'file_tags', fileTags); - }); - - this.updateUsedRepoTags(); - } - - onFileUploadSuccess = (direntObject) => { - let isExist = this.state.direntList.some(item => { - return item.name === direntObject.name && item.type === direntObject.type; - }); - if (isExist) { - let direntList = this.state.direntList; - for (let i = 0; i < direntList.length; i++) { - let dirent = direntList[i]; - if (dirent.name === direntObject.name && dirent.type === direntObject.type) { - let mtime = moment.unix(direntObject.mtime).fromNow(); - this.updateDirent(dirent, 'mtime', mtime); // todo file size is need update too, api is not return; - break; - } - } - } else { - direntObject.permission = 'rw'; - let dirent = new Dirent(direntObject); - this.addNodeToTree(dirent.name, this.state.path, dirent.type); - if (direntObject.type === 'dir') { - this.setState({direntList: [dirent, ...this.state.direntList]}); - } else { - this.setState({direntList: [...this.state.direntList, dirent]}); - this.updateReadmeMarkdown(this.state.direntList); - } - } - } - - addDirent = (name, type, size) => { - let item = this.createDirent(name, type, size); - let direntList = this.state.direntList; - if (type === 'dir') { - direntList.unshift(item); - } else { - // there will be there conditions; - // first: direntList.length === 0; - // second: all the direntList's items are dir; - // third: direntList has dir and file; - let length = direntList.length; - if (length === 0 || direntList[length - 1].type === 'dir') { - direntList.push(item); - } else { - let index = 0; - for (let i = 0; i <= length; i++) { - if (direntList[i].type === 'file') { - index = i; - break; - } - } - direntList.splice(index, 0, item); - } - } - this.setState({direntList: direntList}); - this.updateReadmeMarkdown(direntList); - } - - renameDirent = (direntPath, newName) => { - let parentPath = Utils.getDirName(direntPath); - let newDirentPath = Utils.joinPath(parentPath, newName); - if (direntPath === this.state.path) { - // the renamed item is current viewed item - // example: direntPath = /A/B/C, state.path = /A/B/C - - this.setState({ path: newDirentPath }); - let url = siteRoot + 'wiki/lib/' + repoID + newDirentPath; - window.history.replaceState({ url: url, path: newDirentPath}, newDirentPath, url); - } else if (Utils.isChildPath(direntPath, this.state.path)) { - // example: direntPath = /A/B/C/D, state.path = /A/B/C - let oldName = Utils.getFileName(direntPath); - let direntList = this.state.direntList.map(item => { - if (item.name === oldName) { - item.name = newName; - } - return item; - }); - this.setState({ direntList: direntList }); - this.updateReadmeMarkdown(direntList); - } else if (Utils.isAncestorPath(direntPath, this.state.path)) { - // example: direntPath = /A/B, state.path = /A/B/C - let newPath = Utils.renameAncestorPath(this.state.path, direntPath, newDirentPath); - this.setState({ path: newPath }); - } - } - - deleteDirent(direntPath) { - if (direntPath === this.state.path) { - // The deleted item is current item - let parentPath = Utils.getDirName(direntPath); - this.showDir(parentPath); - } else if (Utils.isChildPath(direntPath, this.state.path)) { - // The deleted item is inside current path - let name = Utils.getFileName(direntPath); - let direntList = this.state.direntList.filter(item => { - return item.name !== name; - }); - this.setState({ direntList: direntList }); - this.updateReadmeMarkdown(direntList); - } else if (Utils.isAncestorPath(direntPath, this.state.path)) { - // the deleted item is ancester of the current item - let parentPath = Utils.getDirName(direntPath); - this.showDir(parentPath); - } - // else do nothing - } - - moveDirent = (direntPath) => { - let name = direntPath.slice(direntPath.lastIndexOf('/') + 1); - let direntList = this.state.direntList.filter(item => { - return item.name !== name; - }); - this.setState({direntList: direntList}); - this.updateReadmeMarkdown(direntList); - } - - onSideNavMenuClick = () => { - this.setState({ - closeSideBar: !this.state.closeSideBar, - }); - } - - onCloseSide = () => { - this.setState({ - closeSideBar: !this.state.closeSideBar, - }); - } - - loadTreeNodeByPath = (path) => { - let tree = this.state.treeData.clone(); - let node = tree.getNodeByPath(path); - if (!node.isLoaded) { - seafileAPI.listDir(repoID, node.path).then(res => { - this.addResponseListToNode(res.data.dirent_list, node); - let parentNode = tree.getNodeByPath(node.parentNode.path); - parentNode.isExpanded = true; - this.setState({ - treeData: tree, - currentNode: node - }); - }); - } else { - let parentNode = tree.getNodeByPath(node.parentNode.path); - parentNode.isExpanded = true; - this.setState({treeData: tree, currentNode: node}); //tree - } - } - - loadNodeAndParentsByPath = (path) => { - let tree = this.state.treeData.clone(); - if (Utils.isMarkdownFile(path)) { - path = Utils.getDirName(path); - } - seafileAPI.listDir(repoID, path, {with_parents: true}).then(res => { - let direntList = res.data.dirent_list; - let results = {}; - for (let i = 0; i < direntList.length; i++) { - let object = direntList[i]; - let key = object.parent_dir; - if (!results[key]) { - results[key] = []; - } - results[key].push(object); - } - for (let key in results) { - let node = tree.getNodeByPath(key); - if (!node.isLoaded) { - this.addResponseListToNode(results[key], node); - } - } - this.setState({ - isTreeDataLoading: false, - treeData: tree - }); - }).catch(() => { - this.setState({isLoadFailed: true}); - }); - } - - onTreeNodeClick = (node) => { - this.resetSelected(); - if (!this.state.pathExist) { - this.setState({pathExist: true}); - } - - if (node.object.isDir()) { - if (!node.isLoaded) { - let tree = this.state.treeData.clone(); - node = tree.getNodeByPath(node.path); - seafileAPI.listDir(repoID, node.path).then(res => { - this.addResponseListToNode(res.data.dirent_list, node); - tree.collapseNode(node); - this.setState({treeData: tree}); - }); - } - if (node.path === this.state.path) { - if (node.isExpanded) { - let tree = treeHelper.collapseNode(this.state.treeData, node); - this.setState({treeData: tree}); - } else { - let tree = this.state.treeData.clone(); - node = tree.getNodeByPath(node.path); - tree.expandNode(node); - this.setState({treeData: tree}); - } - } - } - - if (node.path === this.state.path ) { - return; - } - - if (node.object.isDir()) { // isDir - this.showDir(node.path); - } else { - if (Utils.isMarkdownFile(node.path)) { - if (node.path !== this.state.path) { - this.showFile(node.path); - } - } else { - const w = window.open('about:blank'); - const url = siteRoot + 'lib/' + repoID + '/file' + Utils.encodePath(node.path); - w.location.href = url; - } - } - } - - onTreeNodeCollapse = (node) => { - let tree = treeHelper.collapseNode(this.state.treeData, node); - this.setState({treeData: tree}); - } - - onTreeNodeExpanded = (node) => { - let tree = this.state.treeData.clone(); - node = tree.getNodeByPath(node.path); - if (!node.isLoaded) { - seafileAPI.listDir(repoID, node.path).then(res => { - this.addResponseListToNode(res.data.dirent_list, node); - this.setState({treeData: tree}); - }); - } else { - tree.expandNode(node); - this.setState({treeData: tree}); - } - } - - addNodeToTree = (name, parentPath, type) => { - let node = this.createTreeNode(name, type); - let tree = treeHelper.addNodeToParentByPath(this.state.treeData, node, parentPath); - this.setState({treeData: tree}); - } - - renameTreeNode = (path, newName) => { - let tree = treeHelper.renameNodeByPath(this.state.treeData, path, newName); - this.setState({treeData: tree}); - } - - deleteTreeNode = (path) => { - let tree = treeHelper.deleteNodeByPath(this.state.treeData, path); - this.setState({treeData: tree}); - } - - moveTreeNode = (nodePath, moveToPath, moveToRepo, nodeName) => { - if (repoID !== moveToRepo.repo_id) { - let tree = treeHelper.deleteNodeByPath(this.state.treeData, nodePath); - this.setState({treeData: tree}); - return; - } - let tree = treeHelper.moveNodeByPath(this.state.treeData, nodePath, moveToPath, nodeName); - this.setState({treeData: tree}); - } - - copyTreeNode = (nodePath, copyToPath, destRepo, nodeName) => { - if (repoID !== destRepo.repo_id) { - return; - } - let tree = treeHelper.copyNodeByPath(this.state.treeData, nodePath, copyToPath, nodeName); - this.setState({treeData: tree}); - } - - createTreeNode(name, type) { - let object = this.createDirent(name, type); - return new TreeNode({object}); - } - - createDirent(name, type, size) { - let mtime = new Date().getTime()/1000; - let dirent = new Dirent({name, type, mtime, size}); - return dirent; - } - - addResponseListToNode = (list, node) => { - node.isLoaded = true; - node.isExpanded = true; - let direntList = list.map(item => { - return new Dirent(item); - }); - direntList = Utils.sortDirents(direntList, 'name', 'asc'); - - let nodeList = direntList.map(object => { - return new TreeNode({object}); - }); - node.addChildren(nodeList); - } - - getSelectedDirentPaths = () => { - let paths = []; - this.state.selectedDirentList.forEach(selectedDirent => { - paths.push(Utils.joinPath(this.state.path, selectedDirent.name)); - }); - return paths; - } - - getSelectedDirentNames = () => { - let names = []; - this.state.selectedDirentList.forEach(selectedDirent => { - names.push(selectedDirent.name); - }); - return names; - } - - resetSelected = () => { - this.setState({ - isDirentSelected: false, - isAllDirentSelected: false, - }); - } - - onLibDecryptDialog = () => { - this.setState({libNeedDecrypt: false}); - this.loadWikiData(); - } - - goDraftPage = () => { - window.location.href = siteRoot + 'drafts/' + this.state.draftID + '/'; - } - - sortItems = (sortBy, sortOrder) => { - this.setState({ - sortBy: sortBy, - sortOrder: sortOrder, - items: Utils.sortDirents(this.state.direntList, sortBy, sortOrder) - }); - } - - render() { - let { libNeedDecrypt } = this.state; - if (libNeedDecrypt) { - return ( - - - - ); - } - - let showShareBtn = false, - enableDirPrivateShare = false; - const { repoEncrypted, isAdmin, ownerEmail, userPerm, isVirtual, isDepartmentAdmin } = this.state; - const isRepoOwner = ownerEmail == username; - if (!repoEncrypted && ( - canGenerateShareLink || canGenerateUploadLink || - isRepoOwner || isAdmin) && ( - userPerm == 'rw' || userPerm == 'r')) { - showShareBtn = true; - if (!isVirtual && (isRepoOwner || isAdmin || isDepartmentAdmin)) { - enableDirPrivateShare = true; - } - } - - return ( -
    - - -
    - ); - } -} - -ReactDOM.render ( - , - document.getElementById('wrapper') -); diff --git a/frontend/src/utils/constants.js b/frontend/src/utils/constants.js index 527e063023..0651672543 100644 --- a/frontend/src/utils/constants.js +++ b/frontend/src/utils/constants.js @@ -58,6 +58,7 @@ export const canAddPublicRepo = window.app.pageOptions.canAddPublicRepo; export const canInvitePeople = window.app.pageOptions.canInvitePeople; export const canLockUnlockFile = window.app.pageOptions.canLockUnlockFile; export const customNavItems = window.app.pageOptions.customNavItems; +export const maxUploadFileSize = window.app.pageOptions.maxUploadFileSize; export const curNoteMsg = window.app.pageOptions.curNoteMsg; export const curNoteID = window.app.pageOptions.curNoteID; diff --git a/seahub/api2/endpoints/groups.py b/seahub/api2/endpoints/groups.py index 6fef1431e9..5dad50e9d6 100644 --- a/seahub/api2/endpoints/groups.py +++ b/seahub/api2/endpoints/groups.py @@ -92,7 +92,7 @@ class Groups(APIView): username = request.user.username if is_org_context(request): org_id = request.user.org.org_id - user_groups = seaserv.get_org_groups_by_user(org_id, username) + user_groups = seaserv.get_org_groups_by_user(org_id, username, return_ancestors=True) else: user_groups = ccnet_api.get_groups(username, return_ancestors=True) diff --git a/seahub/templates/base_for_react.html b/seahub/templates/base_for_react.html index d01e7555fc..448c08bf75 100644 --- a/seahub/templates/base_for_react.html +++ b/seahub/templates/base_for_react.html @@ -96,6 +96,9 @@ canAddPublicRepo: {% if can_add_public_repo %} true {% else %} false {% endif %}, canInvitePeople: {% if enable_guest_invitation and user.permissions.can_invite_guest %} true {% else %} false {% endif %}, customNavItems: {% if custom_nav_items %} JSON.parse('{{ custom_nav_items | escapejs }}') {% else %} {{'[]'}} {% endif %}, + {% if max_upload_file_size > 0 %} + maxUploadFileSize: {{ max_upload_file_size }}, + {% endif %} {% if request.user.is_authenticated and request.cur_note %} curNoteMsg: '{{ request.cur_note.message|urlize|escapejs }}', diff --git a/seahub/templates/registration/registration_form.html b/seahub/templates/registration/registration_form.html index bf33621b6f..73f4bf147b 100644 --- a/seahub/templates/registration/registration_form.html +++ b/seahub/templates/registration/registration_form.html @@ -81,7 +81,6 @@ $('#signup-form').on('submit', function(){ var email = $.trim($('input[name="email"]').val()), pwd1 = $.trim($('input[name="password1"]').val()), pwd2 = $.trim($('input[name="password2"]').val()); - level = getStrengthLevel(pwd1); if (!email) { $('.error').html("{% trans "Email cannot be blank" %}").removeClass('hide'); @@ -100,6 +99,7 @@ $('#signup-form').on('submit', function(){ return false; } {% if strong_pwd_required %} + var level = getStrengthLevel(pwd1); if (level < {{level}}) { $('.error').html(passwd_tip).removeClass('hide'); return false; diff --git a/seahub/templates/view_lib_as_wiki.html b/seahub/templates/view_lib_as_wiki.html deleted file mode 100644 index d9935d3c8a..0000000000 --- a/seahub/templates/view_lib_as_wiki.html +++ /dev/null @@ -1,22 +0,0 @@ -{% extends "base_for_react.html" %} -{% load render_bundle from webpack_loader %} -{% block extra_style %} -{% render_bundle 'repoview' 'css' %} -{% endblock %} - -{% block extra_script %} - - -{% render_bundle 'repoview' 'js' %} -{% endblock %} diff --git a/seahub/views/__init__.py b/seahub/views/__init__.py index e0ad20a40e..dbdc3e3eda 100644 --- a/seahub/views/__init__.py +++ b/seahub/views/__init__.py @@ -1131,10 +1131,17 @@ def react_fake_view(request, **kwargs): folder_perm_enabled = True if is_pro_version() and ENABLE_FOLDER_PERM else False + try: + max_upload_file_size = seafile_api.get_server_config_int('fileserver', 'max_upload_size') + except Exception as e: + logger.error(e) + max_upload_file_size = -1 + return render(request, "react_app.html", { "guide_enabled": guide_enabled, 'trash_repos_expire_days': expire_days if expire_days > 0 else 30, 'dtable_web_server': DTABLE_WEB_SERVER, + 'max_upload_file_size': max_upload_file_size, 'seafile_collab_server': SEAFILE_COLLAB_SERVER, 'storages': get_library_storages(request), 'enable_repo_snapshot_label': settings.ENABLE_REPO_SNAPSHOT_LABEL, diff --git a/thirdpart/shibboleth/backends.py b/thirdpart/shibboleth/backends.py index 1f16fdf1b2..67cec514e9 100644 --- a/thirdpart/shibboleth/backends.py +++ b/thirdpart/shibboleth/backends.py @@ -1,6 +1,7 @@ from django.conf import settings from django.db import connection +from seaserv import ccnet_api from seahub.auth.backends import RemoteUserBackend from seahub.base.accounts import User from registration.models import ( @@ -43,9 +44,12 @@ class ShibbolethRemoteUserBackend(RemoteUserBackend): return username = self.clean_username(remote_user) - try: - user = User.objects.get(email=username) - except User.DoesNotExist: + + local_ccnet_users = ccnet_api.search_emailusers('DB', username, -1, -1) + if not local_ccnet_users: + local_ccnet_users = ccnet_api.search_emailusers('LDAP', username, -1, -1) + + if not local_ccnet_users: if self.create_unknown_user: user = User.objects.create_user( email=username, is_active=self.activate_after_creation)