1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-02 15:38:15 +00:00

update draft (#2491)

This commit is contained in:
C_Q
2018-11-01 17:52:59 +08:00
committed by Daniel Pan
parent 41bc505562
commit 4cc735cf1f
11 changed files with 104 additions and 19 deletions

View File

@@ -9,6 +9,7 @@ import DraftContent from './pages/drafts/draft-content';
import ReviewContent from './pages/drafts/review-content'; import ReviewContent from './pages/drafts/review-content';
import FilesActivities from './pages/dashboard/files-activities'; import FilesActivities from './pages/dashboard/files-activities';
import Starred from './pages/starred/starred'; import Starred from './pages/starred/starred';
import editUtilties from './utils/editor-utilties';
import 'seafile-ui'; import 'seafile-ui';
import './assets/css/fa-solid.css'; import './assets/css/fa-solid.css';
@@ -25,9 +26,24 @@ class App extends Component {
this.state = { this.state = {
isOpen: false, isOpen: false,
isSidePanelClosed: 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 = () => { onCloseSidePanel = () => {
this.setState({ this.setState({
isSidePanelClosed: !this.state.isSidePanelClosed isSidePanelClosed: !this.state.isSidePanelClosed
@@ -41,18 +57,19 @@ class App extends Component {
} }
render() { render() {
let href = window.location.href.split('/'); let href = window.location.href.split('/');
let currentTab = href[href.length - 2]; let currentTab = href[href.length - 2];
return ( return (
<div id="main"> <div id="main">
<SidePanel isSidePanelClosed={this.state.isSidePanelClosed} onCloseSidePanel={this.onCloseSidePanel} currentTab={currentTab} /> <SidePanel isSidePanelClosed={this.state.isSidePanelClosed} onCloseSidePanel={this.onCloseSidePanel} currentTab={currentTab} draftCounts={this.state.draftCounts} />
<MainPanel onShowSidePanel={this.onShowSidePanel}> <MainPanel onShowSidePanel={this.onShowSidePanel}>
<Router> <Router>
<FilesActivities path={siteRoot + 'dashboard'} /> <FilesActivities path={siteRoot + 'dashboard'} />
<DraftsView path={siteRoot + 'drafts'} currentTab={currentTab}> <DraftsView path={siteRoot + 'drafts'} currentTab={currentTab}>
<DraftContent path='/' /> <DraftContent path='/' getDrafts={this.getDrafts} draftList={this.state.draftList}/>
<ReviewContent path='reviews' /> <ReviewContent path='reviews' />
</DraftsView> </DraftsView>
<Starred path={siteRoot + 'starred'} /> <Starred path={siteRoot + 'starred'} />

View File

@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import { Link } from '@reach/router'; import { Link } from '@reach/router';
import { gettext, siteRoot } from '../utils/constants'; import { gettext, siteRoot } from '../utils/constants';
import { seafileAPI } from '../utils/seafile-api'; import { seafileAPI } from '../utils/seafile-api';
import { Badge } from 'reactstrap';
const propTypes = { const propTypes = {
currentTab: PropTypes.string.isRequired, currentTab: PropTypes.string.isRequired,
@@ -172,7 +173,7 @@ class MainSideNav extends React.Component {
<li className={`tab ${this.state.currentTab === 'drafts' ? 'tab-cur' : ''}`} onClick={() => this.tabItemClick('drafts')}> <li className={`tab ${this.state.currentTab === 'drafts' ? 'tab-cur' : ''}`} onClick={() => this.tabItemClick('drafts')}>
<Link to={siteRoot + 'drafts/'} title={gettext('Drafts')}> <Link to={siteRoot + 'drafts/'} title={gettext('Drafts')}>
<span className="sf2-icon-edit" aria-hidden="true"></span> <span className="sf2-icon-edit" aria-hidden="true"></span>
{gettext('Drafts')} {gettext('Drafts')} {this.props.draftCounts === 0 ? '' : <Badge color="info" pill>{this.props.draftCounts}</Badge>}
</Link> </Link>
</li> </li>
<li className="tab" id="share-admin-nav"> <li className="tab" id="share-admin-nav">

View File

@@ -19,7 +19,7 @@ class SidePanel extends React.Component {
<Logo onCloseSidePanel={this.props.onCloseSidePanel}/> <Logo onCloseSidePanel={this.props.onCloseSidePanel}/>
</div> </div>
<div className="side-panel-center"> <div className="side-panel-center">
<MainSideNav currentTab={this.props.currentTab}/> <MainSideNav currentTab={this.props.currentTab} draftCounts={this.props.draftCounts}/>
</div> </div>
<div className="side-panel-footer"> <div className="side-panel-footer">
<SideNavFooter /> <SideNavFooter />

View File

@@ -13,6 +13,8 @@ let mode = window.app.pageOptions.mode;
let draftID = window.app.pageOptions.draftID; let draftID = window.app.pageOptions.draftID;
let reviewID = window.app.pageOptions.reviewID; let reviewID = window.app.pageOptions.reviewID;
let isDraft = window.app.pageOptions.isDraft; 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 userName = window.app.userInfo.username;
let dirPath = '/'; let dirPath = '/';
@@ -210,6 +212,10 @@ class EditorUtilities {
getUserAvatar(size) { getUserAvatar(size) {
return seafileAPI.getUserAvatar(userName, 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} draftID={draftID}
reviewID={reviewID} reviewID={reviewID}
isDraft={isDraft} isDraft={isDraft}
hasDraft={hasDraft}
/> />
); );
} }

View File

@@ -12,7 +12,6 @@ class DraftContent extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
draftList: [],
isLoadingDraft: true, isLoadingDraft: true,
isMenuShow: false, isMenuShow: false,
menuPosition: {top:'', left: ''}, menuPosition: {top:'', left: ''},
@@ -32,12 +31,10 @@ class DraftContent extends React.Component {
initDraftList() { initDraftList() {
this.setState({isLoadingDraft: true}); this.setState({isLoadingDraft: true});
editUtilties.listDrafts().then(res => { this.props.getDrafts();
this.setState({ this.setState({
draftList: res.data.data,
isLoadingDraft: false, isLoadingDraft: false,
}); });
});
} }
onDeleteHandler = () => { onDeleteHandler = () => {
@@ -113,14 +110,14 @@ class DraftContent extends React.Component {
return ( return (
<div className="cur-view-content"> <div className="cur-view-content">
{this.state.isLoadingDraft && <Loading /> } {this.state.isLoadingDraft && <Loading /> }
{(!this.state.isLoadingDraft && this.state.draftList.length !==0) && {(!this.state.isLoadingDraft && this.props.draftList.length !==0) &&
<DraftListView <DraftListView
draftList={this.state.draftList} draftList={this.props.draftList}
isItemFreezed={this.state.isItemFreezed} isItemFreezed={this.state.isItemFreezed}
onMenuToggleClick={this.onMenuToggleClick} onMenuToggleClick={this.onMenuToggleClick}
/> />
} }
{(!this.state.isLoadingDraft && this.state.draftList.length === 0) && {(!this.state.isLoadingDraft && this.props.draftList.length === 0) &&
<div className="message empty-tip"> <div className="message empty-tip">
<h2>{gettext('No draft yet')}</h2> <h2>{gettext('No draft yet')}</h2>
<p>{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.')}</p> <p>{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.')}</p>

View File

@@ -42,7 +42,12 @@ class DraftsView(APIView):
username = request.user.username username = request.user.username
data = [x.to_dict() for x in Draft.objects.filter(username=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 @add_org_context
def post(self, request, org_id, format=None): def post(self, request, org_id, format=None):

View File

@@ -18,17 +18,21 @@ from seahub.api2.utils import api_error
from seahub.utils import check_filename_with_rename, is_pro_version, \ from seahub.utils import check_filename_with_rename, is_pro_version, \
gen_inner_file_upload_url, is_valid_dirent_name, normalize_file_path, \ 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.utils.timeutils import timestamp_to_isoformat_timestr
from seahub.views import check_folder_permission from seahub.views import check_folder_permission
from seahub.utils.file_op import check_file_lock, if_locked_by_online_office 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.views.file import can_preview_file, can_edit_file
from seahub.constants import PERMISSION_READ_WRITE from seahub.constants import PERMISSION_READ_WRITE
from seahub.utils.repo import parse_repo_perm 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, \ from seahub.settings import MAX_UPLOAD_FILE_NAME_LEN, \
FILE_LOCK_EXPIRATION_DAYS, OFFICE_TEMPLATE_ROOT 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 seaserv import seafile_api
from pysearpc import SearpcError from pysearpc import SearpcError
@@ -283,6 +287,27 @@ class FileView(APIView):
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
new_file_path = posixpath.join(parent_dir, new_file_name) 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) file_info = self.get_file_info(username, repo_id, new_file_path)
return Response(file_info) return Response(file_info)

View File

@@ -35,6 +35,9 @@ class DraftManager(models.Manager):
draft_file_name = get_draft_file_name(repo.id, file_path) draft_file_name = get_draft_file_name(repo.id, file_path)
draft_file_path = '/Drafts/' + draft_file_name 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 # copy file to draft dir
seafile_api.copy_file(repo.id, file_uuid.parent_path, file_uuid.filename, seafile_api.copy_file(repo.id, file_uuid.parent_path, file_uuid.filename,
repo.id, '/Drafts', draft_file_name, repo.id, '/Drafts', draft_file_name,

View File

@@ -4,6 +4,7 @@ import os
from seaserv import seafile_api from seaserv import seafile_api
from seahub.utils import normalize_file_path, check_filename_with_rename 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): 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): def get_draft_file_name(repo_id, file_path):
file_path = normalize_file_path(file_path) file_path = normalize_file_path(file_path)
file_name, file_ext = os.path.splitext(os.path.basename(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) 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): def is_draft_file(repo_id, file_path):
@@ -47,3 +46,25 @@ def is_draft_file(repo_id, file_path):
pass pass
return is_draft, review_id, draft_id 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

View File

@@ -29,6 +29,8 @@
draftID: '{{ draft_id }}', draftID: '{{ draft_id }}',
reviewID: '{{ review_id }}', reviewID: '{{ review_id }}',
isDraft: '{{ is_draft }}', isDraft: '{{ is_draft }}',
hasDraft: '{{ has_draft }}',
draftFilePath: '{{ draft_file_path }}',
}, },
userInfo: { userInfo: {
username: '{{ user.username }}', username: '{{ user.username }}',

View File

@@ -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.group.utils import is_group_member
from seahub.thumbnail.utils import extract_xmind_image, get_thumbnail_src, \ from seahub.thumbnail.utils import extract_xmind_image, get_thumbnail_src, \
XMIND_IMAGE_SIZE, THUMBNAIL_ROOT 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 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) 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: if filetype == MARKDOWN:
return_dict['protocol'] = request.is_secure() and 'https' or 'http' return_dict['protocol'] = request.is_secure() and 'https' or 'http'
return_dict['domain'] = get_current_site(request).domain 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['draft_id'] = draft_id
return_dict['review_id'] = review_id return_dict['review_id'] = review_id
return_dict['is_draft'] = is_draft return_dict['is_draft'] = is_draft
return_dict['has_draft'] = has_draft
return_dict['draft_file_path'] = draft_file_path
else: else:
return_dict['file_content'] = file_content return_dict['file_content'] = file_content