diff --git a/frontend/src/app.js b/frontend/src/app.js index 86064ac4bf..231d8c2b48 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -9,6 +9,7 @@ import DraftContent from './pages/drafts/draft-content'; import ReviewContent from './pages/drafts/review-content'; import FilesActivities from './pages/dashboard/files-activities'; import Starred from './pages/starred/starred'; +import editUtilties from './utils/editor-utilties'; import 'seafile-ui'; import './assets/css/fa-solid.css'; @@ -25,9 +26,24 @@ class App extends Component { this.state = { isOpen: false, isSidePanelClosed: false, + draftCounts: 0, + draftList:[] }; } + componentDidMount() { + this.getDrafts() + } + + getDrafts = () => { + editUtilties.listDrafts().then(res => { + this.setState({ + draftCounts: res.data.draft_counts, + draftList: res.data.data + }) + }) + } + onCloseSidePanel = () => { this.setState({ isSidePanelClosed: !this.state.isSidePanelClosed @@ -41,18 +57,19 @@ class App extends Component { } render() { + let href = window.location.href.split('/'); let currentTab = href[href.length - 2]; return (
- + - + diff --git a/frontend/src/components/main-side-nav.js b/frontend/src/components/main-side-nav.js index 8a2d2eba2d..df36e03847 100644 --- a/frontend/src/components/main-side-nav.js +++ b/frontend/src/components/main-side-nav.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { Link } from '@reach/router'; import { gettext, siteRoot } from '../utils/constants'; import { seafileAPI } from '../utils/seafile-api'; +import { Badge } from 'reactstrap'; const propTypes = { currentTab: PropTypes.string.isRequired, @@ -172,7 +173,7 @@ class MainSideNav extends React.Component {
  • this.tabItemClick('drafts')}> - {gettext('Drafts')} + {gettext('Drafts')} {this.props.draftCounts === 0 ? '' : {this.props.draftCounts}}
  • diff --git a/frontend/src/components/side-panel.js b/frontend/src/components/side-panel.js index c379df27ae..1c93a6c446 100644 --- a/frontend/src/components/side-panel.js +++ b/frontend/src/components/side-panel.js @@ -19,7 +19,7 @@ class SidePanel extends React.Component {
  • - +
    diff --git a/frontend/src/markdown-editor.js b/frontend/src/markdown-editor.js index 2e68201aac..d7916cc5c6 100644 --- a/frontend/src/markdown-editor.js +++ b/frontend/src/markdown-editor.js @@ -13,6 +13,8 @@ let mode = window.app.pageOptions.mode; let draftID = window.app.pageOptions.draftID; let reviewID = window.app.pageOptions.reviewID; let isDraft = window.app.pageOptions.isDraft; +let hasDraft = window.app.pageOptions.hasDraft; +let draftFilePath = window.app.pageOptions.draftFilePath; let userName = window.app.userInfo.username; let dirPath = '/'; @@ -210,6 +212,10 @@ class EditorUtilities { getUserAvatar(size) { return seafileAPI.getUserAvatar(userName, size); } + + goDraftPage() { + window.location.href = serviceUrl + '/lib/' + repoID + '/file' + draftFilePath + '?mode=edit' + } } @@ -286,6 +292,7 @@ class MarkdownEditor extends React.Component { draftID={draftID} reviewID={reviewID} isDraft={isDraft} + hasDraft={hasDraft} /> ); } diff --git a/frontend/src/pages/drafts/draft-content.js b/frontend/src/pages/drafts/draft-content.js index a818f8e97a..02eeb7d626 100644 --- a/frontend/src/pages/drafts/draft-content.js +++ b/frontend/src/pages/drafts/draft-content.js @@ -12,7 +12,6 @@ class DraftContent extends React.Component { constructor(props) { super(props); this.state = { - draftList: [], isLoadingDraft: true, isMenuShow: false, menuPosition: {top:'', left: ''}, @@ -32,11 +31,9 @@ class DraftContent extends React.Component { initDraftList() { this.setState({isLoadingDraft: true}); - editUtilties.listDrafts().then(res => { - this.setState({ - draftList: res.data.data, - isLoadingDraft: false, - }); + this.props.getDrafts(); + this.setState({ + isLoadingDraft: false, }); } @@ -113,14 +110,14 @@ class DraftContent extends React.Component { return (
    {this.state.isLoadingDraft && } - {(!this.state.isLoadingDraft && this.state.draftList.length !==0) && + {(!this.state.isLoadingDraft && this.props.draftList.length !==0) && } - {(!this.state.isLoadingDraft && this.state.draftList.length === 0) && + {(!this.state.isLoadingDraft && this.props.draftList.length === 0) &&

    {gettext('No draft yet')}

    {gettext('Draft is a way to let you collaborate with others on files. You can create a draft from a file, edit the draft and then ask for a review. The original file will be updated only after the draft be reviewed.')}

    diff --git a/seahub/api2/endpoints/drafts.py b/seahub/api2/endpoints/drafts.py index 8ffcaaae48..692b3fa39e 100644 --- a/seahub/api2/endpoints/drafts.py +++ b/seahub/api2/endpoints/drafts.py @@ -42,7 +42,12 @@ class DraftsView(APIView): username = request.user.username data = [x.to_dict() for x in Draft.objects.filter(username=username)] - return Response({'data': data}) + draft_counts = len(data) + + result = {} + result['data'] = data + result['draft_counts'] = draft_counts + return Response(result) @add_org_context def post(self, request, org_id, format=None): diff --git a/seahub/api2/endpoints/file.py b/seahub/api2/endpoints/file.py index 94e9317d8b..3884a3085f 100644 --- a/seahub/api2/endpoints/file.py +++ b/seahub/api2/endpoints/file.py @@ -18,17 +18,21 @@ from seahub.api2.utils import api_error from seahub.utils import check_filename_with_rename, is_pro_version, \ gen_inner_file_upload_url, is_valid_dirent_name, normalize_file_path, \ - normalize_dir_path + normalize_dir_path, get_file_type_and_ext from seahub.utils.timeutils import timestamp_to_isoformat_timestr from seahub.views import check_folder_permission from seahub.utils.file_op import check_file_lock, if_locked_by_online_office from seahub.views.file import can_preview_file, can_edit_file from seahub.constants import PERMISSION_READ_WRITE from seahub.utils.repo import parse_repo_perm +from seahub.utils.file_types import MARKDOWN, TEXT from seahub.settings import MAX_UPLOAD_FILE_NAME_LEN, \ FILE_LOCK_EXPIRATION_DAYS, OFFICE_TEMPLATE_ROOT +from seahub.drafts.models import Draft, DraftReview +from seahub.drafts.utils import is_draft_file + from seaserv import seafile_api from pysearpc import SearpcError @@ -283,6 +287,27 @@ class FileView(APIView): return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) new_file_path = posixpath.join(parent_dir, new_file_name) + + # rename draft file + filetype, fileext = get_file_type_and_ext(new_file_name) + if filetype == MARKDOWN or filetype == TEXT: + is_draft, review_id, draft_id = is_draft_file(repo.id, path) + if is_draft: + try: + draft = Draft.objects.get(pk=draft_id) + draft.draft_file_path = new_file_path + draft.save() + except Draft.DoesNotExist: + pass + + if review_id is not None: + try: + review = DraftReview.objects.get(pk=review_id, draft_id=draft) + review.draft_file_path = new_file_path + review.save() + except DraftReview.DoesNotExist: + pass + file_info = self.get_file_info(username, repo_id, new_file_path) return Response(file_info) diff --git a/seahub/drafts/models.py b/seahub/drafts/models.py index 43e53c0c01..c6e29772f0 100644 --- a/seahub/drafts/models.py +++ b/seahub/drafts/models.py @@ -35,6 +35,9 @@ class DraftManager(models.Manager): draft_file_name = get_draft_file_name(repo.id, file_path) draft_file_path = '/Drafts/' + draft_file_name + if seafile_api.get_file_id_by_path(repo.id, draft_file_path): + raise DraftFileExist + # copy file to draft dir seafile_api.copy_file(repo.id, file_uuid.parent_path, file_uuid.filename, repo.id, '/Drafts', draft_file_name, diff --git a/seahub/drafts/utils.py b/seahub/drafts/utils.py index da3b3f684a..c0d731eb5f 100644 --- a/seahub/drafts/utils.py +++ b/seahub/drafts/utils.py @@ -4,6 +4,7 @@ import os from seaserv import seafile_api from seahub.utils import normalize_file_path, check_filename_with_rename +from seahub.tags.models import FileUUIDMap def create_user_draft_repo(username, org_id=-1): @@ -20,12 +21,10 @@ def create_user_draft_repo(username, org_id=-1): def get_draft_file_name(repo_id, file_path): file_path = normalize_file_path(file_path) file_name, file_ext = os.path.splitext(os.path.basename(file_path)) - # md5 = hashlib.md5((repo_id + file_path).encode('utf-8')).hexdigest()[:10] draft_file_name = "%s%s%s" % (file_name, '(draft)', file_ext) - new_file_name = check_filename_with_rename(repo_id, '/Drafts', draft_file_name) - return new_file_name + return draft_file_name def is_draft_file(repo_id, file_path): @@ -47,3 +46,25 @@ def is_draft_file(repo_id, file_path): pass return is_draft, review_id, draft_id + +def has_draft_file(repo_id, file_path): + has_draft = False + draft_file_path = None + + file_path = normalize_file_path(file_path) + parent_path = os.path.dirname(file_path) + filename = os.path.basename(file_path) + + file_uuid = FileUUIDMap.objects.get_fileuuidmap_by_path( + repo_id, parent_path, filename, is_dir=False) + + from .models import Draft + if file_uuid: + try: + draft = Draft.objects.get(origin_file_uuid=file_uuid) + has_draft = True + draft_file_path = draft.draft_file_path + except Draft.DoesNotExist: + pass + + return has_draft, draft_file_path diff --git a/seahub/templates/view_file_markdown.html b/seahub/templates/view_file_markdown.html index e5653de672..fea78f1d08 100644 --- a/seahub/templates/view_file_markdown.html +++ b/seahub/templates/view_file_markdown.html @@ -29,6 +29,8 @@ draftID: '{{ draft_id }}', reviewID: '{{ review_id }}', isDraft: '{{ is_draft }}', + hasDraft: '{{ has_draft }}', + draftFilePath: '{{ draft_file_path }}', }, userInfo: { username: '{{ user.username }}', diff --git a/seahub/views/file.py b/seahub/views/file.py index e41f4f3ca8..d65f62984b 100644 --- a/seahub/views/file.py +++ b/seahub/views/file.py @@ -71,7 +71,7 @@ from seahub.utils.repo import is_repo_owner, parse_repo_perm from seahub.group.utils import is_group_member from seahub.thumbnail.utils import extract_xmind_image, get_thumbnail_src, \ XMIND_IMAGE_SIZE, THUMBNAIL_ROOT -from seahub.drafts.utils import is_draft_file +from seahub.drafts.utils import is_draft_file, has_draft_file from seahub.constants import HASH_URLS @@ -625,6 +625,11 @@ def view_lib_file(request, repo_id, path): is_draft, review_id, draft_id = is_draft_file(repo.id, path) + has_draft = False + draft_file_path = '' + if not is_draft: + has_draft, draft_file_path = has_draft_file(repo.id, path) + if filetype == MARKDOWN: return_dict['protocol'] = request.is_secure() and 'https' or 'http' return_dict['domain'] = get_current_site(request).domain @@ -636,6 +641,8 @@ def view_lib_file(request, repo_id, path): return_dict['draft_id'] = draft_id return_dict['review_id'] = review_id return_dict['is_draft'] = is_draft + return_dict['has_draft'] = has_draft + return_dict['draft_file_path'] = draft_file_path else: return_dict['file_content'] = file_content