1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-06 01:12:03 +00:00

New draft file (#2465)

This commit is contained in:
C_Q
2018-10-24 14:37:41 +08:00
committed by Daniel Pan
parent 26f9d7d9d7
commit 67e19792aa
10 changed files with 155 additions and 43 deletions

View File

@@ -16,6 +16,7 @@ class CreateFile extends React.Component {
this.state = { this.state = {
parentPath: '', parentPath: '',
childName: props.fileType, childName: props.fileType,
isDraft: false,
}; };
this.newInput = React.createRef(); this.newInput = React.createRef();
} }
@@ -28,7 +29,8 @@ class CreateFile extends React.Component {
handleSubmit = () => { handleSubmit = () => {
let path = this.state.parentPath + this.state.childName; let path = this.state.parentPath + this.state.childName;
this.props.onAddFile(path); let isDraft = this.state.isDraft;
this.props.onAddFile(path, isDraft);
} }
handleKeyPress = (e) => { handleKeyPress = (e) => {
@@ -37,6 +39,55 @@ class CreateFile extends React.Component {
} }
} }
handleCheck = () => {
let pos = this.state.childName.lastIndexOf(".");
if (this.state.isDraft) {
// from draft to not draft
// case 1, normally, the file name is ended with `(draft)`, like `test(draft).md`
// case 2, the file name is not ended with `(draft)`, the user has deleted some characters, like `test(dra.md`
let p = this.state.childName.substring(pos-7, pos);
let fileName = this.state.childName.substring(0, pos-7);
let fileType = this.state.childName.substring(pos);
if (p === '(draft)') {
// remove `(draft)` from file name
this.setState({
childName: fileName + fileType,
isDraft: !this.state.isDraft
})
} else {
// don't change file name
this.setState({
isDraft: !this.state.isDraft
})
}
}
if (!this.state.isDraft) {
// from not draft to draft
// case 1, test.md ===> test(draft).md
// case 2, .md ===> (draft).md
// case 3, no '.' in the file name, don't change the file name
if (pos > 0) {
let fileName = this.state.childName.substring(0, pos);
let fileType = this.state.childName.substring(pos);
this.setState({
childName: fileName + '(draft)' + fileType,
isDraft: !this.state.isDraft
})
} else if (pos === 0 ) {
this.setState({
childName: '(draft)' + this.state.childname,
isDraft: !this.state.isdraft
})
} else {
this.setState({
isDraft: !this.state.isdraft
})
}
}
}
toggle = () => { toggle = () => {
this.props.addFileCancel(); this.props.addFileCancel();
} }
@@ -67,6 +118,13 @@ class CreateFile extends React.Component {
<Input onKeyPress={this.handleKeyPress} innerRef={input => {this.newInput = input;}} id="fileName" placeholder={gettext('newName')} value={this.state.childName} onChange={this.handleChange}/> <Input onKeyPress={this.handleKeyPress} innerRef={input => {this.newInput = input;}} id="fileName" placeholder={gettext('newName')} value={this.state.childName} onChange={this.handleChange}/>
</Col> </Col>
</FormGroup> </FormGroup>
<FormGroup row>
<Label sm={3} check />
<Col sm={9}>
<Input type="checkbox" onChange={this.handleCheck}/>{' '}{gettext("This is a draft.")}
</Col>
</FormGroup>
</Form> </Form>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>

View File

@@ -64,7 +64,8 @@ class DraftContent extends React.Component {
let draft = this.state.currentDraft; let draft = this.state.currentDraft;
editUtilties.createDraftReview(draft.id).then(res => { editUtilties.createDraftReview(draft.id).then(res => {
window.open(siteRoot + 'drafts/review/' + res.data.id); const w = window.open()
w.location = siteRoot + 'drafts/review/' + res.data.id;
}).catch((error) => { }).catch((error) => {
if (error.response.status == '409') { if (error.response.status == '409') {
Toast.error('The draft review is existing.'); Toast.error('The draft review is existing.');

View File

@@ -158,9 +158,9 @@ class MainPanel extends Component {
this.setState({showFileDialog: !this.state.showFileDialog}); this.setState({showFileDialog: !this.state.showFileDialog});
} }
onMainAddFile = (filePath) => { onMainAddFile = (filePath, isDraft) => {
this.setState({showFileDialog: !this.state.showFileDialog}); this.setState({showFileDialog: !this.state.showFileDialog});
this.props.onMainAddFile(filePath); this.props.onMainAddFile(filePath, isDraft);
} }
onMainAddFolder = (dirPath) => { onMainAddFolder = (dirPath) => {

View File

@@ -127,9 +127,9 @@ class SidePanel extends Component {
this.props.onAddFolderNode(dirPath); this.props.onAddFolderNode(dirPath);
} }
onAddFileNode = (filePath) => { onAddFileNode = (filePath, isDraft) => {
this.setState({showFile: !this.state.showFile}); this.setState({showFile: !this.state.showFile});
this.props.onAddFileNode(filePath); this.props.onAddFileNode(filePath, isDraft);
} }
onRenameNode = (newName) => { onRenameNode = (newName) => {

View File

@@ -252,8 +252,8 @@ class Wiki extends Component {
}); });
} }
onAddFileNode = (filePath) => { onAddFileNode = (filePath, isDraft) => {
editorUtilities.createFile(filePath).then(res => { editorUtilities.createFile(filePath, isDraft).then(res => {
let tree = this.state.tree_data.clone(); let tree = this.state.tree_data.clone();
let name = this.getFileNameByPath(filePath); let name = this.getFileNameByPath(filePath);
let index = filePath.lastIndexOf('/'); let index = filePath.lastIndexOf('/');

View File

@@ -38,8 +38,8 @@ class EditorUtilities {
}); });
} }
createFile(filePath) { createFile(filePath, isDraft) {
return seafileAPI.createFile(repoID, filePath); return seafileAPI.createFile(repoID, filePath, isDraft);
} }
deleteFile(filePath) { deleteFile(filePath) {

View File

@@ -1,4 +1,6 @@
# Copyright (c) 2012-2016 Seafile Ltd. # Copyright (c) 2012-2016 Seafile Ltd.
import os
from rest_framework import status from rest_framework import status
from rest_framework.authentication import SessionAuthentication from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
@@ -89,7 +91,33 @@ class DraftReviewView(APIView):
return api_error(status.HTTP_409_CONFLICT, return api_error(status.HTTP_409_CONFLICT,
'There is a conflict between the draft and the original file') 'There is a conflict between the draft and the original file')
file_id = seafile_api.get_file_id_by_path(r.origin_repo_id, r.origin_file_path) origin_file_path = r.origin_file_path
# if it is a new draft
# case1. '/path/test(draft).md' ---> '/path/test.md'
# case2. '/path/test(dra.md' ---> '/path/test(dra.md'
if d.draft_file_path == r.origin_file_path:
new_draft_dir = os.path.dirname(origin_file_path)
new_draft_name = os.path.basename(origin_file_path)
draft_flag = os.path.splitext(new_draft_name)[0][-7:]
# remove `(draft)` from file name
if draft_flag == '(draft)':
f = os.path.splitext(new_draft_name)[0][:-7]
file_type = os.path.splitext(new_draft_name)[-1]
new_draft_name = f + file_type
if new_draft_dir == '/':
origin_file_path = new_draft_dir + new_draft_name
else:
origin_file_path = new_draft_dir + '/' + new_draft_name
r.draft_file_path = origin_file_path
r.origin_file_path = origin_file_path
# get draft published version
file_id = seafile_api.get_file_id_by_path(r.origin_repo_id, origin_file_path)
r.publish_file_version = file_id r.publish_file_version = file_id
r.save() r.save()
d.delete() d.delete()

View File

@@ -56,17 +56,17 @@ class DraftsView(APIView):
error_msg = 'Library %s not found.' % repo_id error_msg = 'Library %s not found.' % repo_id
return api_error(status.HTTP_404_NOT_FOUND, error_msg) return api_error(status.HTTP_404_NOT_FOUND, error_msg)
file_id = seafile_api.get_file_id_by_path(repo.id, file_path)
if not file_id:
return api_error(status.HTTP_404_NOT_FOUND,
"File %s not found" % file_path)
# perm check # perm check
perm = check_folder_permission(request, repo.id, file_path) perm = check_folder_permission(request, repo.id, file_path)
if perm != PERMISSION_READ_WRITE: if perm != PERMISSION_READ_WRITE:
error_msg = 'Permission denied.' error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg) return api_error(status.HTTP_403_FORBIDDEN, error_msg)
file_id = seafile_api.get_file_id_by_path(repo.id, file_path)
if not file_id:
return api_error(status.HTTP_404_NOT_FOUND,
"File %s not found" % file_path)
username = request.user.username username = request.user.username
try: try:

View File

@@ -58,6 +58,7 @@ from seahub.thumbnail.utils import generate_thumbnail
from seahub.notifications.models import UserNotification from seahub.notifications.models import UserNotification
from seahub.options.models import UserOptions from seahub.options.models import UserOptions
from seahub.profile.models import Profile, DetailedProfile from seahub.profile.models import Profile, DetailedProfile
from seahub.drafts.models import Draft
from seahub.signals import (repo_created, repo_deleted) from seahub.signals import (repo_created, repo_deleted)
from seahub.share.models import FileShare, OrgFileShare, UploadLinkShare from seahub.share.models import FileShare, OrgFileShare, UploadLinkShare
from seahub.utils import gen_file_get_url, gen_token, gen_file_upload_url, \ from seahub.utils import gen_file_get_url, gen_token, gen_file_upload_url, \
@@ -2632,6 +2633,7 @@ class FileView(APIView):
username = request.user.username username = request.user.username
parent_dir = os.path.dirname(path) parent_dir = os.path.dirname(path)
operation = request.POST.get('operation', '') operation = request.POST.get('operation', '')
is_draft = request.POST.get('is_draft', '')
file_info = {} file_info = {}
if operation.lower() == 'rename': if operation.lower() == 'rename':
@@ -2772,6 +2774,17 @@ class FileView(APIView):
return api_error(status.HTTP_403_FORBIDDEN, return api_error(status.HTTP_403_FORBIDDEN,
'You do not have permission to create file.') 'You do not have permission to create file.')
if is_draft.lower() == 'true':
file_name = os.path.basename(path)
file_dir = os.path.dirname(path)
draft_type = os.path.splitext(file_name)[0][-7:]
file_type = os.path.splitext(file_name)[-1]
if draft_type != '(draft)':
f = os.path.splitext(file_name)[0]
path = file_dir + '/' + f + '(draft)' + file_type
new_file_name = os.path.basename(path) new_file_name = os.path.basename(path)
if not seafile_api.is_valid_filename('fake_repo_id', new_file_name): if not seafile_api.is_valid_filename('fake_repo_id', new_file_name):
@@ -2787,6 +2800,10 @@ class FileView(APIView):
return api_error(HTTP_520_OPERATION_FAILED, return api_error(HTTP_520_OPERATION_FAILED,
'Failed to create file.') 'Failed to create file.')
if is_draft.lower() == 'true':
repo = seafile_api.get_repo(repo_id)
Draft.objects.add(username, repo, path, file_exist=False)
if request.GET.get('reloaddir', '').lower() == 'true': if request.GET.get('reloaddir', '').lower() == 'true':
return reloaddir(request, repo, parent_dir) return reloaddir(request, repo, parent_dir)
else: else:

View File

@@ -10,7 +10,7 @@ from seahub.base.fields import LowerCaseCharField
from seahub.base.models import TimestampedModel from seahub.base.models import TimestampedModel
from seahub.base.templatetags.seahub_tags import email2nickname from seahub.base.templatetags.seahub_tags import email2nickname
from seahub.tags.models import FileUUIDMap from seahub.tags.models import FileUUIDMap
from seahub.utils import normalize_file_path from seahub.utils import normalize_file_path, EMPTY_SHA1
from seahub.utils.timeutils import datetime_to_isoformat_timestr from seahub.utils.timeutils import datetime_to_isoformat_timestr
from .utils import create_user_draft_repo, get_draft_file_name from .utils import create_user_draft_repo, get_draft_file_name
@@ -24,24 +24,8 @@ class DraftFileConflict(Exception):
class DraftManager(models.Manager): class DraftManager(models.Manager):
def get_user_draft_repo_id(self, username): def create_exist_file_draft(self, repo, username, file_uuid, file_path):
r = self.filter(username=username).first() # create drafts dir if any
if r is None:
return None
else:
return r.draft_repo_id
def add(self, username, repo, file_path, file_id=None, org_id=-1):
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_or_create_fileuuidmap(
repo.id, parent_path, filename, is_dir=False)
if file_id is None:
file_id = seafile_api.get_file_id_by_path(repo.id, file_path)
# create drafts dir if any
draft_dir_id = seafile_api.get_dir_id_by_path(repo.id, '/Drafts') draft_dir_id = seafile_api.get_dir_id_by_path(repo.id, '/Drafts')
if draft_dir_id is None: if draft_dir_id is None:
seafile_api.post_dir(repo.id, '/', 'Drafts', username) seafile_api.post_dir(repo.id, '/', 'Drafts', username)
@@ -56,10 +40,25 @@ class DraftManager(models.Manager):
repo.id, '/Drafts', draft_file_name, repo.id, '/Drafts', draft_file_name,
username=username, need_progress=0, synchronous=1) username=username, need_progress=0, synchronous=1)
return draft_file_path
def add(self, username, repo, file_path, file_exist=True, file_id=None, org_id=-1):
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_or_create_fileuuidmap(
repo.id, parent_path, filename, is_dir=False)
if file_id is None:
file_id = seafile_api.get_file_id_by_path(repo.id, file_path)
if file_exist:
file_path = self.create_exist_file_draft(repo, username, file_uuid, file_path)
draft = self.model(username=username, draft = self.model(username=username,
origin_repo_id=repo.id, origin_file_uuid=file_uuid, origin_repo_id=repo.id, origin_file_uuid=file_uuid,
origin_file_version=file_id, origin_file_version=file_id,
draft_file_path=draft_file_path) draft_file_path=file_path)
draft.save(using=self._db) draft.save(using=self._db)
return draft return draft
@@ -80,7 +79,8 @@ class Draft(TimestampedModel):
def delete(self): def delete(self):
draft_file_name = os.path.basename(self.draft_file_path) draft_file_name = os.path.basename(self.draft_file_path)
seafile_api.del_file(self.origin_repo_id, '/Drafts/', draft_file_path = os.path.dirname(self.draft_file_path)
seafile_api.del_file(self.origin_repo_id, draft_file_path,
draft_file_name, self.username) draft_file_name, self.username)
super(Draft, self).delete() super(Draft, self).delete()
@@ -101,22 +101,30 @@ class Draft(TimestampedModel):
if not file_id: if not file_id:
raise DraftFileConflict raise DraftFileConflict
if file_id != self.origin_file_version: draft_file_name = os.path.basename(self.draft_file_path)
draft_file_path = os.path.dirname(self.draft_file_path)
file_name = self.origin_file_uuid.filename
if file_id != self.origin_file_version and self.draft_file_path != origin_file_path:
raise DraftFileConflict raise DraftFileConflict
draft_file_name = os.path.basename(self.draft_file_path) if self.draft_file_path == origin_file_path:
f = os.path.splitext(draft_file_name)[0][:-7]
file_type = os.path.splitext(draft_file_name)[-1]
file_name = f + file_type
# move draft file to origin file # move draft file to origin file
seafile_api.move_file( seafile_api.move_file(
self.origin_repo_id, '/Drafts', draft_file_name, self.origin_repo_id, draft_file_path, draft_file_name,
self.origin_repo_id, self.origin_file_uuid.parent_path, self.origin_repo_id, self.origin_file_uuid.parent_path,
self.origin_file_uuid.filename, replace=1, file_name, replace=1,
username=self.username, need_progress=0, synchronous=1 username=self.username, need_progress=0, synchronous=1
) )
def to_dict(self): def to_dict(self):
uuid = self.origin_file_uuid uuid = self.origin_file_uuid
file_path = posixpath.join(uuid.parent_path, uuid.filename) # TODO: refactor uuid file_path = posixpath.join(uuid.parent_path, uuid.filename)
repo = seafile_api.get_repo(self.origin_repo_id) repo = seafile_api.get_repo(self.origin_repo_id)