mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-05 00:43:53 +00:00
New draft file (#2465)
This commit is contained in:
@@ -16,6 +16,7 @@ class CreateFile extends React.Component {
|
||||
this.state = {
|
||||
parentPath: '',
|
||||
childName: props.fileType,
|
||||
isDraft: false,
|
||||
};
|
||||
this.newInput = React.createRef();
|
||||
}
|
||||
@@ -28,7 +29,8 @@ class CreateFile extends React.Component {
|
||||
|
||||
handleSubmit = () => {
|
||||
let path = this.state.parentPath + this.state.childName;
|
||||
this.props.onAddFile(path);
|
||||
let isDraft = this.state.isDraft;
|
||||
this.props.onAddFile(path, isDraft);
|
||||
}
|
||||
|
||||
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 = () => {
|
||||
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}/>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
<FormGroup row>
|
||||
<Label sm={3} check />
|
||||
<Col sm={9}>
|
||||
<Input type="checkbox" onChange={this.handleCheck}/>{' '}{gettext("This is a draft.")}
|
||||
</Col>
|
||||
</FormGroup>
|
||||
|
||||
</Form>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
|
@@ -64,7 +64,8 @@ class DraftContent extends React.Component {
|
||||
let draft = this.state.currentDraft;
|
||||
|
||||
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) => {
|
||||
if (error.response.status == '409') {
|
||||
Toast.error('The draft review is existing.');
|
||||
|
@@ -158,9 +158,9 @@ class MainPanel extends Component {
|
||||
this.setState({showFileDialog: !this.state.showFileDialog});
|
||||
}
|
||||
|
||||
onMainAddFile = (filePath) => {
|
||||
onMainAddFile = (filePath, isDraft) => {
|
||||
this.setState({showFileDialog: !this.state.showFileDialog});
|
||||
this.props.onMainAddFile(filePath);
|
||||
this.props.onMainAddFile(filePath, isDraft);
|
||||
}
|
||||
|
||||
onMainAddFolder = (dirPath) => {
|
||||
|
@@ -127,9 +127,9 @@ class SidePanel extends Component {
|
||||
this.props.onAddFolderNode(dirPath);
|
||||
}
|
||||
|
||||
onAddFileNode = (filePath) => {
|
||||
onAddFileNode = (filePath, isDraft) => {
|
||||
this.setState({showFile: !this.state.showFile});
|
||||
this.props.onAddFileNode(filePath);
|
||||
this.props.onAddFileNode(filePath, isDraft);
|
||||
}
|
||||
|
||||
onRenameNode = (newName) => {
|
||||
|
@@ -252,8 +252,8 @@ class Wiki extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
onAddFileNode = (filePath) => {
|
||||
editorUtilities.createFile(filePath).then(res => {
|
||||
onAddFileNode = (filePath, isDraft) => {
|
||||
editorUtilities.createFile(filePath, isDraft).then(res => {
|
||||
let tree = this.state.tree_data.clone();
|
||||
let name = this.getFileNameByPath(filePath);
|
||||
let index = filePath.lastIndexOf('/');
|
||||
|
@@ -38,8 +38,8 @@ class EditorUtilities {
|
||||
});
|
||||
}
|
||||
|
||||
createFile(filePath) {
|
||||
return seafileAPI.createFile(repoID, filePath);
|
||||
createFile(filePath, isDraft) {
|
||||
return seafileAPI.createFile(repoID, filePath, isDraft);
|
||||
}
|
||||
|
||||
deleteFile(filePath) {
|
||||
|
@@ -1,4 +1,6 @@
|
||||
# Copyright (c) 2012-2016 Seafile Ltd.
|
||||
import os
|
||||
|
||||
from rest_framework import status
|
||||
from rest_framework.authentication import SessionAuthentication
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
@@ -89,7 +91,33 @@ class DraftReviewView(APIView):
|
||||
return api_error(status.HTTP_409_CONFLICT,
|
||||
'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.save()
|
||||
d.delete()
|
||||
|
@@ -56,17 +56,17 @@ class DraftsView(APIView):
|
||||
error_msg = 'Library %s not found.' % repo_id
|
||||
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_folder_permission(request, repo.id, file_path)
|
||||
if perm != PERMISSION_READ_WRITE:
|
||||
error_msg = 'Permission denied.'
|
||||
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
|
||||
|
||||
try:
|
||||
|
@@ -58,6 +58,7 @@ from seahub.thumbnail.utils import generate_thumbnail
|
||||
from seahub.notifications.models import UserNotification
|
||||
from seahub.options.models import UserOptions
|
||||
from seahub.profile.models import Profile, DetailedProfile
|
||||
from seahub.drafts.models import Draft
|
||||
from seahub.signals import (repo_created, repo_deleted)
|
||||
from seahub.share.models import FileShare, OrgFileShare, UploadLinkShare
|
||||
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
|
||||
parent_dir = os.path.dirname(path)
|
||||
operation = request.POST.get('operation', '')
|
||||
is_draft = request.POST.get('is_draft', '')
|
||||
|
||||
file_info = {}
|
||||
if operation.lower() == 'rename':
|
||||
@@ -2772,6 +2774,17 @@ class FileView(APIView):
|
||||
return api_error(status.HTTP_403_FORBIDDEN,
|
||||
'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)
|
||||
|
||||
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,
|
||||
'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':
|
||||
return reloaddir(request, repo, parent_dir)
|
||||
else:
|
||||
|
@@ -10,7 +10,7 @@ from seahub.base.fields import LowerCaseCharField
|
||||
from seahub.base.models import TimestampedModel
|
||||
from seahub.base.templatetags.seahub_tags import email2nickname
|
||||
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 .utils import create_user_draft_repo, get_draft_file_name
|
||||
|
||||
@@ -24,24 +24,8 @@ class DraftFileConflict(Exception):
|
||||
|
||||
|
||||
class DraftManager(models.Manager):
|
||||
def get_user_draft_repo_id(self, username):
|
||||
r = self.filter(username=username).first()
|
||||
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
|
||||
def create_exist_file_draft(self, repo, username, file_uuid, file_path):
|
||||
# create drafts dir if any
|
||||
draft_dir_id = seafile_api.get_dir_id_by_path(repo.id, '/Drafts')
|
||||
if draft_dir_id is None:
|
||||
seafile_api.post_dir(repo.id, '/', 'Drafts', username)
|
||||
@@ -56,10 +40,25 @@ class DraftManager(models.Manager):
|
||||
repo.id, '/Drafts', draft_file_name,
|
||||
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,
|
||||
origin_repo_id=repo.id, origin_file_uuid=file_uuid,
|
||||
origin_file_version=file_id,
|
||||
draft_file_path=draft_file_path)
|
||||
draft_file_path=file_path)
|
||||
draft.save(using=self._db)
|
||||
return draft
|
||||
|
||||
@@ -80,7 +79,8 @@ class Draft(TimestampedModel):
|
||||
|
||||
def delete(self):
|
||||
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)
|
||||
|
||||
super(Draft, self).delete()
|
||||
@@ -101,22 +101,30 @@ class Draft(TimestampedModel):
|
||||
if not file_id:
|
||||
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
|
||||
|
||||
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
|
||||
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_file_uuid.filename, replace=1,
|
||||
file_name, replace=1,
|
||||
username=self.username, need_progress=0, synchronous=1
|
||||
)
|
||||
|
||||
|
||||
def to_dict(self):
|
||||
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)
|
||||
|
||||
|
Reference in New Issue
Block a user