From c75c4d76b4fcb96c5c6ff7acf3f75a990275f72f Mon Sep 17 00:00:00 2001 From: lian Date: Fri, 31 May 2019 15:57:32 +0800 Subject: [PATCH] update publish draft api --- seahub/api2/endpoints/drafts.py | 129 ++++++++++++++++++++++---------- seahub/drafts/models.py | 79 +++---------------- seahub/drafts/views.py | 3 +- 3 files changed, 101 insertions(+), 110 deletions(-) diff --git a/seahub/api2/endpoints/drafts.py b/seahub/api2/endpoints/drafts.py index 5fb79fb8d5..0e341a6505 100644 --- a/seahub/api2/endpoints/drafts.py +++ b/seahub/api2/endpoints/drafts.py @@ -1,28 +1,23 @@ # Copyright (c) 2012-2016 Seafile Ltd. +import os import logging +import posixpath from rest_framework import status from rest_framework.authentication import SessionAuthentication from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView -from seaserv import seafile_api, edit_repo -from pysearpc import SearpcError -from django.core.urlresolvers import reverse -from django.db import IntegrityError -from django.db.models import Count -from django.http import HttpResponse -from django.utils.translation import ugettext as _ +from seaserv import seafile_api from seahub.api2.authentication import TokenAuthentication from seahub.api2.endpoints.utils import add_org_context from seahub.api2.throttling import UserRateThrottle from seahub.api2.utils import api_error from seahub.constants import PERMISSION_READ_WRITE -from seahub.drafts.models import Draft, DraftFileExist, DraftFileConflict +from seahub.drafts.models import Draft, DraftFileExist from seahub.tags.models import FileUUIDMap from seahub.views import check_folder_permission -from seahub.utils import gen_file_get_url from seahub.drafts.utils import send_draft_publish_msg logger = logging.getLogger(__name__) @@ -53,29 +48,45 @@ class DraftsView(APIView): def post(self, request, org_id, format=None): """Create a file draft if the user has read-write permission to the origin file """ - repo_id = request.POST.get('repo_id', '') - file_path = request.POST.get('file_path', '') + # argument check + repo_id = request.data.get('repo_id', '') + if not repo_id: + error_msg = 'repo_id invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + file_path = request.data.get('file_path', '') + if not file_path: + error_msg = 'file_path invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + # resource check repo = seafile_api.get_repo(repo_id) if not repo: error_msg = 'Library %s not found.' % repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) - # perm check - perm = check_folder_permission(request, repo.id, file_path) + file_id = seafile_api.get_file_id_by_path(repo_id, file_path) + if not file_id: + error_msg = 'File %s not found.' % file_path + return api_error(status.HTTP_404_NOT_FOUND, error_msg) + + # permission 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: - d = Draft.objects.add(username, repo, file_path, file_id) + # create drafts dir if does not exist + 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) + + # create draft + try: + d = Draft.objects.add(username, repo, file_path, file_id=file_id) return Response(d.to_dict()) except DraftFileExist: return api_error(status.HTTP_409_CONFLICT, 'Draft already exists.') @@ -92,39 +103,77 @@ class DraftView(APIView): def put(self, request, pk, format=None): """Publish a draft if the user has read-write permission to the origin file - """ - op = request.data.get('operation', '') - if op != 'publish': - return api_error(status.HTTP_400_BAD_REQUEST, - 'Operation invalid.') + Process: + 1. Overwrite the origin file with the draft file. + If origin file's parent folder does NOT exist, move draft file to library's root folder. + 2. Update draft database info. + 3. Send draft file publish msg. + """ + + # resource check try: - d = Draft.objects.get(pk=pk) + draft = Draft.objects.get(pk=pk) except Draft.DoesNotExist: return api_error(status.HTTP_404_NOT_FOUND, 'Draft %s not found.' % pk) - # perm check - repo_id = d.origin_repo_id - uuid = FileUUIDMap.objects.get_fileuuidmap_by_uuid(d.origin_file_uuid) + repo_id = draft.origin_repo_id + repo = seafile_api.get_repo(repo_id) + if not repo: + error_msg = 'Library %s not found.' % repo_id + return api_error(status.HTTP_404_NOT_FOUND, error_msg) - if not uuid: - return api_error(status.HTTP_404_NOT_FOUND, 'Origin file uuid not found.') + # permission check + origin_file_uuid = FileUUIDMap.objects.get_fileuuidmap_by_uuid(draft.origin_file_uuid) + if origin_file_uuid and seafile_api.get_dir_id_by_path(repo_id, + origin_file_uuid.parent_path): + permission = check_folder_permission(request, repo_id, origin_file_uuid.parent_path) + else: + permission = check_folder_permission(request, repo_id, '/') - perm = check_folder_permission(request, repo_id, uuid.parent_path) - - if perm != PERMISSION_READ_WRITE: + if permission != PERMISSION_READ_WRITE: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) + # 1. Overwrite the origin file with the draft file. + # If origin file's parent folder does NOT exist, move draft file to library's root folder. + + # get origin file info + origin_file_parent_path = origin_file_uuid.parent_path if origin_file_uuid else '' + + # check if origin file's parent folder exists + if not seafile_api.get_dir_id_by_path(repo_id, origin_file_parent_path): + dst_parent_path = '/' + else: + dst_parent_path = origin_file_parent_path + + # get draft file info + draft_file_name = os.path.basename(draft.draft_file_path) + draft_file_parent_path = os.path.dirname(draft.draft_file_path) + + f = os.path.splitext(draft_file_name)[0][:-7] + file_type = os.path.splitext(draft_file_name)[-1] + dst_file_name = f + file_type + + # move draft file username = request.user.username + seafile_api.move_file( + repo_id, draft_file_parent_path, draft_file_name, + repo_id, dst_parent_path, dst_file_name, + replace=1, username=username, need_progress=0, synchronous=1 + ) + try: - published_file_path = d.publish(operator=username) - send_draft_publish_msg(d, username, published_file_path) - return Response({'published_file_path': published_file_path}) - except DraftFileConflict: - return api_error(status.HTTP_409_CONFLICT, - 'There is a conflict between the draft and the original file') + # 2. Update draft database info. + dst_file_path = posixpath.join(dst_parent_path, dst_file_name) + dst_file_id = seafile_api.get_file_id_by_path(repo_id, dst_file_path) + draft.update(dst_file_id) + + # 3. Send draft file publish msg. + send_draft_publish_msg(draft, username, dst_file_path) + + return Response({'published_file_path': dst_file_path}) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' diff --git a/seahub/drafts/models.py b/seahub/drafts/models.py index 1a5adcf2a5..64211b9688 100644 --- a/seahub/drafts/models.py +++ b/seahub/drafts/models.py @@ -11,9 +11,9 @@ from seahub.base.fields import LowerCaseCharField from seahub.base.models import TimestampedModel from seahub.base.templatetags.seahub_tags import email2nickname, email2contact_email from seahub.tags.models import FileUUIDMap -from seahub.utils import normalize_file_path, EMPTY_SHA1 +from seahub.utils import normalize_file_path from seahub.utils.timeutils import datetime_to_isoformat_timestr -from .utils import create_user_draft_repo, get_draft_file_name +from .utils import get_draft_file_name class DraftFileExist(Exception): @@ -53,7 +53,7 @@ class DraftManager(models.Manager): return drafts def list_draft_by_username(self, username, status='open'): - """list all user drafts + """list all user drafts If with_reviews is true, return the draft associated review """ repo_cache = {} @@ -70,7 +70,7 @@ class DraftManager(models.Manager): return repo data = [] - qs = self.filter(username=username, status='open') + qs = self.filter(username=username, status=status) for d in qs: # If repo does not exist, no related items are displayed. @@ -99,10 +99,6 @@ class DraftManager(models.Manager): return data def create_exist_file_draft(self, repo, username, file_uuid, file_path): - # create drafts dir if does not exist - 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) # check draft file does not exists and copy origin file content to # draft file @@ -146,10 +142,12 @@ class DraftManager(models.Manager): return draft_file_path + def add(self, username, repo, file_path, file_exist=True, file_id=None, org_id=-1, status='open'): file_path = normalize_file_path(file_path) parent_path = os.path.dirname(file_path) filename = os.path.basename(file_path) + # origin file uuid file_uuid = FileUUIDMap.objects.get_or_create_fileuuidmap( repo.id, parent_path, filename, is_dir=False) @@ -186,6 +184,11 @@ class Draft(TimestampedModel): # class Meta: # unique_together = (('username', 'draft_repo_id'), ) + def update(self, publish_file_version, status = 'published'): + self.publish_file_version = publish_file_version + self.status = status + self.save() + def delete(self, operator): draft_file_name = os.path.basename(self.draft_file_path) draft_file_path = os.path.dirname(self.draft_file_path) @@ -194,66 +197,6 @@ class Draft(TimestampedModel): super(Draft, self).delete() - def publish(self, operator): - # check whether origin file is updated - r_repo = seafile_api.get_repo(self.origin_repo_id) - if not r_repo: - raise DraftFileConflict - - file_uuid = FileUUIDMap.objects.get_fileuuidmap_by_uuid(self.origin_file_uuid) - if not file_uuid: - # TODO update error msg - raise DraftFileConflict - - if file_uuid.parent_path == '/': - origin_file_path = file_uuid.parent_path + file_uuid.filename - else: - origin_file_path = file_uuid.parent_path + '/' + file_uuid.filename - - file_id = seafile_api.get_file_id_by_path(self.origin_repo_id, - origin_file_path) - - draft_file_name = os.path.basename(self.draft_file_path) - draft_file_path = os.path.dirname(self.draft_file_path) - file_name = file_uuid.filename - if file_id: - if file_id != self.origin_file_version and self.draft_file_path != origin_file_path: - raise DraftFileConflict - - 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, draft_file_path, draft_file_name, - self.origin_repo_id, file_uuid.parent_path, - file_name, replace=1, - username=operator, need_progress=0, synchronous=1 - ) - - else: - - # move draft file to origin file - seafile_api.move_file( - self.origin_repo_id, draft_file_path, draft_file_name, - self.origin_repo_id, file_uuid.parent_path, - file_name, replace=1, - username=operator, need_progress=0, synchronous=1 - ) - - published_file_path = posixpath.join(file_uuid.parent_path, file_name) - - # get draft published version - file_id = seafile_api.get_file_id_by_path(self.origin_repo_id, published_file_path) - - self.publish_file_version = file_id - self.status = 'published' - self.save() - - return published_file_path - def to_dict(self): uuid = FileUUIDMap.objects.get_fileuuidmap_by_uuid(self.origin_file_uuid) file_path = posixpath.join(uuid.parent_path, uuid.filename) diff --git a/seahub/drafts/views.py b/seahub/drafts/views.py index 2f8da2b122..32696e8925 100644 --- a/seahub/drafts/views.py +++ b/seahub/drafts/views.py @@ -6,10 +6,9 @@ from django.shortcuts import render, get_object_or_404 from django.utils.translation import ugettext as _ from seaserv import seafile_api -from seahub.base.templatetags.seahub_tags import email2nickname from seahub.auth.decorators import login_required from seahub.views import check_folder_permission -from seahub.utils import render_permission_error, render_error +from seahub.utils import render_permission_error from seahub.drafts.models import Draft from seahub.api2.utils import user_to_dict from seahub.tags.models import FileUUIDMap