mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-19 07:27:56 +00:00
Remove code of draft (#7154)
* initiate * update * update * Update models.py * Update settings.py * update * update
This commit is contained in:
parent
f4d15fb574
commit
7e2bbdac8e
@ -17,7 +17,6 @@ from seahub.api2.throttling import UserRateThrottle
|
|||||||
from seahub.api2.authentication import TokenAuthentication
|
from seahub.api2.authentication import TokenAuthentication
|
||||||
from seahub.base.templatetags.seahub_tags import email2nickname
|
from seahub.base.templatetags.seahub_tags import email2nickname
|
||||||
from seahub.avatar.templatetags.avatar_tags import api_avatar_url
|
from seahub.avatar.templatetags.avatar_tags import api_avatar_url
|
||||||
from seahub.drafts.models import Draft
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -81,19 +80,6 @@ class ActivitiesView(APIView):
|
|||||||
d['old_name'] = os.path.basename(e.old_path)
|
d['old_name'] = os.path.basename(e.old_path)
|
||||||
elif e.op_type == 'publish':
|
elif e.op_type == 'publish':
|
||||||
d['old_path'] = e.old_path
|
d['old_path'] = e.old_path
|
||||||
elif d['name'].endswith('(draft).md'):
|
|
||||||
if e.op_type in ('create', 'edit') and e.obj_type == 'file':
|
|
||||||
try:
|
|
||||||
draft = Draft.objects.filter(username=e.op_user,
|
|
||||||
origin_repo_id=e.repo_id,
|
|
||||||
draft_file_path=e.path)
|
|
||||||
if draft:
|
|
||||||
draft = draft[0]
|
|
||||||
d['draft_id'] = draft.id
|
|
||||||
else:
|
|
||||||
Draft.DoesNotExist
|
|
||||||
except Draft.DoesNotExist:
|
|
||||||
pass
|
|
||||||
|
|
||||||
events_list.append(d)
|
events_list.append(d)
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ from seahub.api2.throttling import UserRateThrottle
|
|||||||
from seahub.api2.authentication import TokenAuthentication
|
from seahub.api2.authentication import TokenAuthentication
|
||||||
from seahub.base.templatetags.seahub_tags import email2nickname
|
from seahub.base.templatetags.seahub_tags import email2nickname
|
||||||
from seahub.avatar.templatetags.avatar_tags import api_avatar_url
|
from seahub.avatar.templatetags.avatar_tags import api_avatar_url
|
||||||
from seahub.drafts.models import Draft
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -98,20 +97,6 @@ class UserActivitiesView(APIView):
|
|||||||
d['old_name'] = os.path.basename(e.old_path)
|
d['old_name'] = os.path.basename(e.old_path)
|
||||||
elif e.op_type == 'publish':
|
elif e.op_type == 'publish':
|
||||||
d['old_path'] = e.old_path
|
d['old_path'] = e.old_path
|
||||||
elif d['name'].endswith('(draft).md'):
|
|
||||||
if e.op_type in ('create', 'edit') and e.obj_type == 'file':
|
|
||||||
try:
|
|
||||||
draft = Draft.objects.filter(username=e.op_user,
|
|
||||||
origin_repo_id=e.repo_id,
|
|
||||||
draft_file_path=e.path)
|
|
||||||
if draft:
|
|
||||||
draft = draft[0]
|
|
||||||
d['draft_id'] = draft.id
|
|
||||||
else:
|
|
||||||
Draft.DoesNotExist
|
|
||||||
except Draft.DoesNotExist:
|
|
||||||
pass
|
|
||||||
|
|
||||||
events_list.append(d)
|
events_list.append(d)
|
||||||
|
|
||||||
response = {'events': events_list}
|
response = {'events': events_list}
|
||||||
|
@ -1901,26 +1901,6 @@ class AdminUpdateUserCcnetEmail(APIView):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
|
|
||||||
try:
|
|
||||||
from seahub.drafts.models import Draft
|
|
||||||
draft_list = Draft.objects.filter(username=old_ccnet_email)
|
|
||||||
for draft in draft_list:
|
|
||||||
draft.username = new_ccnet_email
|
|
||||||
draft.save()
|
|
||||||
logger.debug('the drafts_draft table in seahub database was successfully updated')
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(e)
|
|
||||||
|
|
||||||
try:
|
|
||||||
from seahub.drafts.models import DraftReviewer
|
|
||||||
draftreviewer_list = DraftReviewer.objects.filter(reviewer=old_ccnet_email)
|
|
||||||
for draftreviewer in draftreviewer_list:
|
|
||||||
draftreviewer.reviewer = new_ccnet_email
|
|
||||||
draftreviewer.save()
|
|
||||||
logger.debug('the drafts_draftreviewer table in seahub database was successfully updated')
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(e)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from seahub.file_participants.models import FileParticipant
|
from seahub.file_participants.models import FileParticipant
|
||||||
fileparticipant_list = FileParticipant.objects.filter(username=old_ccnet_email)
|
fileparticipant_list = FileParticipant.objects.filter(username=old_ccnet_email)
|
||||||
|
@ -1,152 +0,0 @@
|
|||||||
# Copyright (c) 2012-2016 Seafile Ltd.
|
|
||||||
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 django.utils.translation import gettext as _
|
|
||||||
|
|
||||||
from seaserv import seafile_api
|
|
||||||
from seahub.api2.authentication import TokenAuthentication
|
|
||||||
from seahub.api2.throttling import UserRateThrottle
|
|
||||||
from seahub.api2.utils import api_error, user_to_dict
|
|
||||||
|
|
||||||
from seahub.base.templatetags.seahub_tags import email2nickname
|
|
||||||
from seahub.base.accounts import User
|
|
||||||
from seahub.tags.models import FileUUIDMap
|
|
||||||
from seahub.views import check_folder_permission
|
|
||||||
from seahub.utils import is_valid_username
|
|
||||||
from seahub.drafts.models import Draft, DraftReviewer
|
|
||||||
from seahub.drafts.signals import request_reviewer_successful
|
|
||||||
|
|
||||||
|
|
||||||
class DraftReviewerView(APIView):
|
|
||||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
|
||||||
permission_classes = (IsAuthenticated, )
|
|
||||||
throttle_classes = (UserRateThrottle, )
|
|
||||||
|
|
||||||
def get(self, request, pk, format=None):
|
|
||||||
try:
|
|
||||||
d = Draft.objects.get(pk=pk)
|
|
||||||
except Draft.DoesNotExist:
|
|
||||||
return api_error(status.HTTP_404_NOT_FOUND,
|
|
||||||
'Draft %s not found' % pk)
|
|
||||||
|
|
||||||
# format user result
|
|
||||||
try:
|
|
||||||
avatar_size = int(request.GET.get('avatar_size', 32))
|
|
||||||
except ValueError:
|
|
||||||
avatar_size = 32
|
|
||||||
|
|
||||||
# get reviewer list
|
|
||||||
reviewers = []
|
|
||||||
for x in d.draftreviewer_set.all():
|
|
||||||
reviewer = user_to_dict(x.reviewer, request=request)
|
|
||||||
reviewers.append(reviewer)
|
|
||||||
|
|
||||||
return Response({'reviewers': reviewers})
|
|
||||||
|
|
||||||
def post(self, request, pk, format=None):
|
|
||||||
"""add draft reviewer
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
d = Draft.objects.get(pk=pk)
|
|
||||||
except Draft.DoesNotExist:
|
|
||||||
return api_error(status.HTTP_404_NOT_FOUND,
|
|
||||||
'Draft %s not found' % pk)
|
|
||||||
|
|
||||||
result = {}
|
|
||||||
result['failed'] = []
|
|
||||||
result['success'] = []
|
|
||||||
|
|
||||||
reviewers = request.data.getlist('reviewer')
|
|
||||||
for reviewer in reviewers:
|
|
||||||
if not is_valid_username(reviewer):
|
|
||||||
result['failed'].append({
|
|
||||||
'email': reviewer,
|
|
||||||
'error_msg': _('username invalid.')
|
|
||||||
})
|
|
||||||
continue
|
|
||||||
|
|
||||||
try:
|
|
||||||
User.objects.get(email=reviewer)
|
|
||||||
except User.DoesNotExist:
|
|
||||||
result['failed'].append({
|
|
||||||
'email': reviewer,
|
|
||||||
'error_msg': _('User %s not found.') % reviewer
|
|
||||||
})
|
|
||||||
continue
|
|
||||||
|
|
||||||
# can't share to owner
|
|
||||||
if reviewer == d.username:
|
|
||||||
error_msg = 'Draft can not be asked owner to review.'
|
|
||||||
result['failed'].append({
|
|
||||||
'email': reviewer,
|
|
||||||
'error_msg': error_msg
|
|
||||||
})
|
|
||||||
continue
|
|
||||||
|
|
||||||
uuid = FileUUIDMap.objects.get_fileuuidmap_by_uuid(d.origin_file_uuid)
|
|
||||||
origin_file_path = posixpath.join(uuid.parent_path, uuid.filename)
|
|
||||||
# check perm
|
|
||||||
if seafile_api.check_permission_by_path(d.origin_repo_id, origin_file_path, reviewer) != 'rw':
|
|
||||||
error_msg = _('Permission denied.')
|
|
||||||
result['failed'].append({
|
|
||||||
'email': reviewer,
|
|
||||||
'error_msg': error_msg
|
|
||||||
})
|
|
||||||
continue
|
|
||||||
|
|
||||||
if DraftReviewer.objects.filter(draft=d, reviewer=reviewer):
|
|
||||||
error_msg = 'Reviewer %s has existed.' % reviewer
|
|
||||||
result['failed'].append({
|
|
||||||
'email': reviewer,
|
|
||||||
'error_msg': error_msg
|
|
||||||
})
|
|
||||||
continue
|
|
||||||
|
|
||||||
result['success'].append({
|
|
||||||
"user_info": {
|
|
||||||
"name": reviewer,
|
|
||||||
"nickname": email2nickname(reviewer)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
DraftReviewer.objects.add(reviewer, d)
|
|
||||||
|
|
||||||
request_reviewer_successful.send(sender=None, from_user=request.user.username,
|
|
||||||
to_user=reviewer, draft_id=d.id)
|
|
||||||
|
|
||||||
return Response(result)
|
|
||||||
|
|
||||||
def delete(self, request, pk):
|
|
||||||
"""Delete a reviewer
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
d = Draft.objects.get(pk=pk)
|
|
||||||
except Draft.DoesNotExist:
|
|
||||||
return api_error(status.HTTP_404_NOT_FOUND,
|
|
||||||
'Draft %s not found' % pk)
|
|
||||||
|
|
||||||
perm = check_folder_permission(request, d.origin_repo_id, '/')
|
|
||||||
|
|
||||||
if perm is None:
|
|
||||||
error_msg = 'Permission denied.'
|
|
||||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
|
||||||
|
|
||||||
reviewer = request.GET.get('username')
|
|
||||||
|
|
||||||
if reviewer is None:
|
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, 'Email %s invalid.' % reviewer)
|
|
||||||
|
|
||||||
try:
|
|
||||||
reviewer = DraftReviewer.objects.get(reviewer=reviewer, draft=d)
|
|
||||||
except DraftReviewer.DoesNotExist:
|
|
||||||
return Response(status.HTTP_200_OK)
|
|
||||||
|
|
||||||
reviewer.delete()
|
|
||||||
|
|
||||||
return Response(status.HTTP_200_OK)
|
|
@ -1,206 +0,0 @@
|
|||||||
# Copyright (c) 2012-2016 Seafile Ltd.
|
|
||||||
import os
|
|
||||||
import json
|
|
||||||
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
|
|
||||||
|
|
||||||
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
|
|
||||||
from seahub.tags.models import FileUUIDMap
|
|
||||||
from seahub.views import check_folder_permission
|
|
||||||
from seahub.drafts.utils import send_draft_publish_msg
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
HTTP_520_OPERATION_FAILED = 520
|
|
||||||
|
|
||||||
|
|
||||||
class DraftsView(APIView):
|
|
||||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
|
||||||
permission_classes = (IsAuthenticated, )
|
|
||||||
throttle_classes = (UserRateThrottle, )
|
|
||||||
|
|
||||||
def get(self, request, format=None):
|
|
||||||
"""List all user drafts.
|
|
||||||
"""
|
|
||||||
username = request.user.username
|
|
||||||
data = Draft.objects.list_draft_by_username(username)
|
|
||||||
|
|
||||||
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):
|
|
||||||
"""Create a file draft if the user has read-write permission to the origin file
|
|
||||||
"""
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
username = request.user.username
|
|
||||||
|
|
||||||
# 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.')
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(e)
|
|
||||||
error_msg = 'Internal Server Error'
|
|
||||||
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
|
||||||
|
|
||||||
|
|
||||||
class DraftView(APIView):
|
|
||||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
|
||||||
permission_classes = (IsAuthenticated, )
|
|
||||||
throttle_classes = (UserRateThrottle, )
|
|
||||||
|
|
||||||
def put(self, request, pk, format=None):
|
|
||||||
"""Publish a draft if the user has read-write permission to the origin file
|
|
||||||
|
|
||||||
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:
|
|
||||||
draft = Draft.objects.get(pk=pk)
|
|
||||||
except Draft.DoesNotExist:
|
|
||||||
return api_error(status.HTTP_404_NOT_FOUND,
|
|
||||||
'Draft %s not found.' % pk)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
# 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, '/')
|
|
||||||
|
|
||||||
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,
|
|
||||||
json.dumps([draft_file_name]),
|
|
||||||
repo_id, dst_parent_path,
|
|
||||||
json.dumps([dst_file_name]),
|
|
||||||
replace=1, username=username,
|
|
||||||
need_progress=0, synchronous=1)
|
|
||||||
|
|
||||||
try:
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
result = {}
|
|
||||||
result['published_file_path'] = dst_file_path
|
|
||||||
result['draft_status'] = draft.status
|
|
||||||
return Response(result)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(e)
|
|
||||||
error_msg = 'Internal Server Error'
|
|
||||||
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
|
||||||
|
|
||||||
def delete(self, request, pk, format=None):
|
|
||||||
"""Delete a draft if user is draft owner or has repo rw permission
|
|
||||||
"""
|
|
||||||
username = request.user.username
|
|
||||||
try:
|
|
||||||
d = Draft.objects.get(pk=pk)
|
|
||||||
except Draft.DoesNotExist:
|
|
||||||
return api_error(status.HTTP_404_NOT_FOUND,
|
|
||||||
'Draft %s not found.' % pk)
|
|
||||||
|
|
||||||
# perm check
|
|
||||||
if d.username != username:
|
|
||||||
perm = check_folder_permission(request, d.origin_repo_id, '/')
|
|
||||||
if perm != PERMISSION_READ_WRITE:
|
|
||||||
error_msg = 'Permission denied.'
|
|
||||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
|
||||||
|
|
||||||
d.delete(operator=username)
|
|
||||||
|
|
||||||
return Response(status.HTTP_200_OK)
|
|
@ -37,10 +37,6 @@ from seahub.base.models import FileComment
|
|||||||
from seahub.settings import MAX_UPLOAD_FILE_NAME_LEN, OFFICE_TEMPLATE_ROOT
|
from seahub.settings import MAX_UPLOAD_FILE_NAME_LEN, OFFICE_TEMPLATE_ROOT
|
||||||
from seahub.api2.endpoints.utils import convert_file, sdoc_convert_to_docx
|
from seahub.api2.endpoints.utils import convert_file, sdoc_convert_to_docx
|
||||||
from seahub.seadoc.utils import get_seadoc_file_uuid
|
from seahub.seadoc.utils import get_seadoc_file_uuid
|
||||||
|
|
||||||
from seahub.drafts.models import Draft
|
|
||||||
from seahub.drafts.utils import is_draft_file, get_file_draft
|
|
||||||
|
|
||||||
from seaserv import seafile_api
|
from seaserv import seafile_api
|
||||||
from pysearpc import SearpcError
|
from pysearpc import SearpcError
|
||||||
|
|
||||||
@ -170,8 +166,6 @@ class FileView(APIView):
|
|||||||
username = request.user.username
|
username = request.user.username
|
||||||
parent_dir = os.path.dirname(path)
|
parent_dir = os.path.dirname(path)
|
||||||
|
|
||||||
is_draft = request.POST.get('is_draft', '')
|
|
||||||
|
|
||||||
if operation == 'create':
|
if operation == 'create':
|
||||||
|
|
||||||
# resource check
|
# resource check
|
||||||
@ -191,17 +185,6 @@ class FileView(APIView):
|
|||||||
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)
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
# create new empty file
|
# create new empty file
|
||||||
new_file_name = os.path.basename(path)
|
new_file_name = os.path.basename(path)
|
||||||
|
|
||||||
@ -223,9 +206,6 @@ class FileView(APIView):
|
|||||||
error_msg = 'Internal Server Error'
|
error_msg = 'Internal Server Error'
|
||||||
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
|
||||||
if is_draft.lower() == 'true':
|
|
||||||
Draft.objects.add(username, repo, path, file_exist=False)
|
|
||||||
|
|
||||||
LANGUAGE_DICT = {
|
LANGUAGE_DICT = {
|
||||||
'cs': 'cs-CZ',
|
'cs': 'cs-CZ',
|
||||||
'de': 'de-DE',
|
'de': 'de-DE',
|
||||||
@ -349,18 +329,6 @@ class FileView(APIView):
|
|||||||
|
|
||||||
# rename draft file
|
# rename draft file
|
||||||
filetype, fileext = get_file_type_and_ext(new_file_name)
|
filetype, fileext = get_file_type_and_ext(new_file_name)
|
||||||
if filetype == MARKDOWN or filetype == TEXT:
|
|
||||||
is_draft = is_draft_file(repo.id, path)
|
|
||||||
review = get_file_draft(repo.id, path, is_draft)
|
|
||||||
draft_id = review['draft_id']
|
|
||||||
if is_draft:
|
|
||||||
try:
|
|
||||||
draft = Draft.objects.get(pk=draft_id)
|
|
||||||
draft.draft_file_path = new_file_path
|
|
||||||
draft.save()
|
|
||||||
except Draft.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)
|
||||||
|
|
||||||
|
@ -1,142 +0,0 @@
|
|||||||
# Copyright (c) 2012-2016 Seafile Ltd.
|
|
||||||
import logging
|
|
||||||
|
|
||||||
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
|
|
||||||
from pysearpc import SearpcError
|
|
||||||
from django.urls import reverse
|
|
||||||
|
|
||||||
from seahub.api2.authentication import TokenAuthentication
|
|
||||||
from seahub.api2.permissions import IsRepoAccessible
|
|
||||||
from seahub.api2.throttling import UserRateThrottle
|
|
||||||
from seahub.api2.utils import api_error, user_to_dict, to_python_boolean
|
|
||||||
from seahub.avatar.settings import AVATAR_DEFAULT_SIZE
|
|
||||||
from seahub.base.models import FileComment
|
|
||||||
from seahub.utils.repo import get_repo_owner
|
|
||||||
from seahub.signals import comment_file_successful
|
|
||||||
from seahub.drafts.signals import comment_draft_successful
|
|
||||||
from seahub.drafts.utils import is_draft_file
|
|
||||||
from seahub.drafts.models import Draft
|
|
||||||
from seahub.api2.endpoints.utils import generate_links_header_for_paginator
|
|
||||||
from seahub.views import check_folder_permission
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class FileCommentsView(APIView):
|
|
||||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
|
||||||
permission_classes = (IsAuthenticated, IsRepoAccessible)
|
|
||||||
throttle_classes = (UserRateThrottle, )
|
|
||||||
|
|
||||||
def get(self, request, repo_id, format=None):
|
|
||||||
"""List all comments of a file.
|
|
||||||
"""
|
|
||||||
path = request.GET.get('p', '/').rstrip('/')
|
|
||||||
if not path:
|
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, 'Wrong path.')
|
|
||||||
|
|
||||||
resolved = request.GET.get('resolved', None)
|
|
||||||
if resolved not in ('true', 'false', None):
|
|
||||||
error_msg = 'resolved invalid.'
|
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
|
||||||
|
|
||||||
# permission check
|
|
||||||
if check_folder_permission(request, repo_id, '/') is None:
|
|
||||||
return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.')
|
|
||||||
|
|
||||||
try:
|
|
||||||
page = int(request.GET.get('page', '1'))
|
|
||||||
per_page = int(request.GET.get('per_page', '25'))
|
|
||||||
except ValueError:
|
|
||||||
page = 1
|
|
||||||
per_page = 25
|
|
||||||
|
|
||||||
start = (page - 1) * per_page
|
|
||||||
end = page * per_page
|
|
||||||
|
|
||||||
total_count = FileComment.objects.get_by_file_path(repo_id, path).count()
|
|
||||||
comments = []
|
|
||||||
|
|
||||||
if resolved is None:
|
|
||||||
file_comments = FileComment.objects.get_by_file_path(repo_id, path)[start: end]
|
|
||||||
else:
|
|
||||||
comment_resolved = to_python_boolean(resolved)
|
|
||||||
file_comments = FileComment.objects.get_by_file_path(repo_id, path).filter(resolved=comment_resolved)[start: end]
|
|
||||||
|
|
||||||
for file_comment in file_comments:
|
|
||||||
comment = file_comment.to_dict()
|
|
||||||
comment.update(user_to_dict(file_comment.author, request=request))
|
|
||||||
comments.append(comment)
|
|
||||||
|
|
||||||
result = {'comments': comments, 'total_count': total_count}
|
|
||||||
resp = Response(result)
|
|
||||||
base_url = reverse('api2-file-comments', args=[repo_id])
|
|
||||||
links_header = generate_links_header_for_paginator(base_url, page,
|
|
||||||
per_page, total_count)
|
|
||||||
resp['Links'] = links_header
|
|
||||||
return resp
|
|
||||||
|
|
||||||
def post(self, request, repo_id, format=None):
|
|
||||||
"""Post a comments of a file.
|
|
||||||
"""
|
|
||||||
# argument check
|
|
||||||
path = request.GET.get('p', '/').rstrip('/')
|
|
||||||
if not path:
|
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, 'Wrong path.')
|
|
||||||
|
|
||||||
comment = request.data.get('comment', '')
|
|
||||||
if not comment:
|
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, 'Comment can not be empty.')
|
|
||||||
|
|
||||||
try:
|
|
||||||
avatar_size = int(request.GET.get('avatar_size',
|
|
||||||
AVATAR_DEFAULT_SIZE))
|
|
||||||
except ValueError:
|
|
||||||
avatar_size = AVATAR_DEFAULT_SIZE
|
|
||||||
|
|
||||||
# resource check
|
|
||||||
try:
|
|
||||||
file_id = seafile_api.get_file_id_by_path(repo_id, path)
|
|
||||||
except SearpcError as e:
|
|
||||||
logger.error(e)
|
|
||||||
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
||||||
'Internal Server Error')
|
|
||||||
if not file_id:
|
|
||||||
return api_error(status.HTTP_404_NOT_FOUND, 'File not found.')
|
|
||||||
|
|
||||||
# permission check
|
|
||||||
if check_folder_permission(request, repo_id, '/') is None:
|
|
||||||
return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.')
|
|
||||||
|
|
||||||
detail = request.data.get('detail', '')
|
|
||||||
username = request.user.username
|
|
||||||
file_comment = FileComment.objects.add_by_file_path(
|
|
||||||
repo_id=repo_id, file_path=path, author=username, comment=comment, detail=detail)
|
|
||||||
repo = seafile_api.get_repo(repo_id)
|
|
||||||
repo_owner = get_repo_owner(request, repo.id)
|
|
||||||
|
|
||||||
if is_draft_file(repo_id, path):
|
|
||||||
draft = Draft.objects.filter(origin_repo_id=repo_id, draft_file_path=path)
|
|
||||||
if draft:
|
|
||||||
draft = draft[0]
|
|
||||||
comment_draft_successful.send(sender=None,
|
|
||||||
draft=draft,
|
|
||||||
comment=comment,
|
|
||||||
author=username)
|
|
||||||
else:
|
|
||||||
Draft.DoesNotExist
|
|
||||||
else:
|
|
||||||
comment_file_successful.send(sender=None,
|
|
||||||
repo=repo,
|
|
||||||
repo_owner=repo_owner,
|
|
||||||
file_path=path,
|
|
||||||
comment=comment,
|
|
||||||
author=username)
|
|
||||||
|
|
||||||
comment = file_comment.to_dict()
|
|
||||||
comment.update(user_to_dict(username, request=request))
|
|
||||||
return Response(comment, status=201)
|
|
@ -12,7 +12,6 @@ from seahub.api2.throttling import UserRateThrottle
|
|||||||
from seahub.api2.authentication import TokenAuthentication
|
from seahub.api2.authentication import TokenAuthentication
|
||||||
from seahub.utils import EVENTS_ENABLED, get_user_activities_by_timestamp
|
from seahub.utils import EVENTS_ENABLED, get_user_activities_by_timestamp
|
||||||
from seahub.api2.utils import api_error
|
from seahub.api2.utils import api_error
|
||||||
from seahub.drafts.models import Draft
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -59,22 +58,6 @@ class RecentAddedFilesView(APIView):
|
|||||||
file_dict = dict(repo_id=event.repo_id)
|
file_dict = dict(repo_id=event.repo_id)
|
||||||
file_dict['path'] = event.path
|
file_dict['path'] = event.path
|
||||||
file_dict['added_time'] = event.timestamp
|
file_dict['added_time'] = event.timestamp
|
||||||
|
|
||||||
if event.path.endswith('(draft).md'):
|
|
||||||
try:
|
|
||||||
draft = Draft.objects.filter(
|
|
||||||
username=event.op_user,
|
|
||||||
origin_repo_id=event.repo_id,
|
|
||||||
draft_file_path=event.path
|
|
||||||
)
|
|
||||||
if draft:
|
|
||||||
draft = draft[0]
|
|
||||||
file_dict['draft_id'] = draft.id
|
|
||||||
else:
|
|
||||||
logger.warning('draft %s not found' % event.path)
|
|
||||||
except Draft.DoesNotExist:
|
|
||||||
pass
|
|
||||||
|
|
||||||
recent_added_files.append(file_dict)
|
recent_added_files.append(file_dict)
|
||||||
|
|
||||||
return Response({'recent_added_files': recent_added_files})
|
return Response({'recent_added_files': recent_added_files})
|
||||||
|
@ -15,57 +15,5 @@ from seahub.api2.throttling import UserRateThrottle
|
|||||||
from seahub.api2.utils import api_error
|
from seahub.api2.utils import api_error
|
||||||
from seahub.views import check_folder_permission
|
from seahub.views import check_folder_permission
|
||||||
|
|
||||||
from seahub.drafts.models import Draft
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class RepoDraftCounts(APIView):
|
|
||||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
|
||||||
permission_classes = (IsAuthenticated, )
|
|
||||||
throttle_classes = (UserRateThrottle, )
|
|
||||||
|
|
||||||
def get(self, request, repo_id, format=None):
|
|
||||||
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)
|
|
||||||
|
|
||||||
# check perm
|
|
||||||
perm = check_folder_permission(request, repo_id, '/')
|
|
||||||
if not perm:
|
|
||||||
error_msg = 'Permission denied.'
|
|
||||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
|
||||||
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
# get draft counts
|
|
||||||
result['draft_counts'] = Draft.objects.get_draft_counts_by_repo_id(repo_id)
|
|
||||||
|
|
||||||
return Response(result)
|
|
||||||
|
|
||||||
|
|
||||||
class RepoDraftInfo(APIView):
|
|
||||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
|
||||||
permission_classes = (IsAuthenticated, )
|
|
||||||
throttle_classes = (UserRateThrottle, )
|
|
||||||
|
|
||||||
def get(self, request, repo_id, format=None):
|
|
||||||
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)
|
|
||||||
|
|
||||||
# check perm
|
|
||||||
perm = check_folder_permission(request, repo_id, '/')
|
|
||||||
if not perm:
|
|
||||||
error_msg = 'Permission denied.'
|
|
||||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
|
||||||
|
|
||||||
result = {}
|
|
||||||
|
|
||||||
# list draft
|
|
||||||
drafts = Draft.objects.list_draft_by_repo_id(repo_id)
|
|
||||||
result['drafts'] = drafts
|
|
||||||
|
|
||||||
return Response(result)
|
|
||||||
|
@ -1120,11 +1120,10 @@ class ShareLinkUploadDone(APIView):
|
|||||||
share_link = None
|
share_link = None
|
||||||
upload_link = None
|
upload_link = None
|
||||||
|
|
||||||
try:
|
|
||||||
share_link = FileShare.objects.get_valid_dir_link_by_token(token=token)
|
share_link = FileShare.objects.get_valid_dir_link_by_token(token=token)
|
||||||
except FileShare.DoesNotExist:
|
upload_link = UploadLinkShare.objects.filter(token=token).first()
|
||||||
upload_link = UploadLinkShare.objects.get(token=token)
|
|
||||||
except UploadLinkShare.DoesNotExist:
|
if not (share_link or upload_link):
|
||||||
error_msg = 'token %s not found.' % token
|
error_msg = 'token %s not found.' % token
|
||||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
|
@ -19,8 +19,6 @@ from urllib.parse import quote
|
|||||||
|
|
||||||
from seahub.api2.authentication import RepoAPITokenAuthentication
|
from seahub.api2.authentication import RepoAPITokenAuthentication
|
||||||
from seahub.base.models import FileComment
|
from seahub.base.models import FileComment
|
||||||
from seahub.drafts.models import Draft
|
|
||||||
from seahub.drafts.utils import is_draft_file, get_file_draft
|
|
||||||
from seahub.repo_api_tokens.utils import get_dir_file_info_list
|
from seahub.repo_api_tokens.utils import get_dir_file_info_list
|
||||||
from seahub.api2.throttling import UserRateThrottle
|
from seahub.api2.throttling import UserRateThrottle
|
||||||
from seahub.api2.utils import api_error, to_python_boolean
|
from seahub.api2.utils import api_error, to_python_boolean
|
||||||
@ -817,9 +815,6 @@ class ViaRepoTokenFile(APIView):
|
|||||||
|
|
||||||
username = ''
|
username = ''
|
||||||
parent_dir = os.path.dirname(path)
|
parent_dir = os.path.dirname(path)
|
||||||
|
|
||||||
is_draft = request.POST.get('is_draft', '')
|
|
||||||
|
|
||||||
if operation == 'create':
|
if operation == 'create':
|
||||||
|
|
||||||
# resource check
|
# resource check
|
||||||
@ -839,17 +834,6 @@ class ViaRepoTokenFile(APIView):
|
|||||||
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)
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
# create new empty file
|
# create new empty file
|
||||||
new_file_name = os.path.basename(path)
|
new_file_name = os.path.basename(path)
|
||||||
|
|
||||||
@ -871,9 +855,6 @@ class ViaRepoTokenFile(APIView):
|
|||||||
error_msg = 'Internal Server Error'
|
error_msg = 'Internal Server Error'
|
||||||
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
|
||||||
if is_draft.lower() == 'true':
|
|
||||||
Draft.objects.add(username, repo, path, file_exist=False)
|
|
||||||
|
|
||||||
LANGUAGE_DICT = {
|
LANGUAGE_DICT = {
|
||||||
'cs': 'cs-CZ',
|
'cs': 'cs-CZ',
|
||||||
'de': 'de-DE',
|
'de': 'de-DE',
|
||||||
|
@ -9,9 +9,6 @@ from .endpoints.dir_shared_items import DirSharedItemsEndpoint
|
|||||||
from .endpoints.admin.account import Account
|
from .endpoints.admin.account import Account
|
||||||
from .endpoints.shared_upload_links import SharedUploadLinksView
|
from .endpoints.shared_upload_links import SharedUploadLinksView
|
||||||
from .endpoints.be_shared_repo import BeSharedRepo
|
from .endpoints.be_shared_repo import BeSharedRepo
|
||||||
from .endpoints.file_comment import FileCommentView
|
|
||||||
from .endpoints.file_comments import FileCommentsView
|
|
||||||
from .endpoints.file_comments_counts import FileCommentsCounts
|
|
||||||
from .endpoints.search_user import SearchUser
|
from .endpoints.search_user import SearchUser
|
||||||
from .endpoints.send_share_link_email import SendShareLinkView
|
from .endpoints.send_share_link_email import SendShareLinkView
|
||||||
from .endpoints.send_upload_link_email import SendUploadLinkView
|
from .endpoints.send_upload_link_email import SendUploadLinkView
|
||||||
@ -57,9 +54,6 @@ urlpatterns = [
|
|||||||
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/$', FileView.as_view(), name='FileView'),
|
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/$', FileView.as_view(), name='FileView'),
|
||||||
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/metadata/$', FileMetaDataView.as_view(), name='FileMetaDataView'),
|
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/metadata/$', FileMetaDataView.as_view(), name='FileMetaDataView'),
|
||||||
re_path(r'^repos/(?P<repo_id>[-0-9a-f]{36})/files/(?P<file_id>[0-9a-f]{40})/blks/(?P<block_id>[0-9a-f]{40})/download-link/$', FileBlockDownloadLinkView.as_view()),
|
re_path(r'^repos/(?P<repo_id>[-0-9a-f]{36})/files/(?P<file_id>[0-9a-f]{40})/blks/(?P<block_id>[0-9a-f]{40})/download-link/$', FileBlockDownloadLinkView.as_view()),
|
||||||
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/comments/$', FileCommentsView.as_view(), name='api2-file-comments'),
|
|
||||||
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/comments/counts/$', FileCommentsCounts.as_view(), name='api2-file-comments-counts'),
|
|
||||||
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/comments/(?P<comment_id>\d+)/$', FileCommentView.as_view(), name='api2-file-comment'),
|
|
||||||
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/detail/$', FileDetailView.as_view()),
|
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/detail/$', FileDetailView.as_view()),
|
||||||
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/history/$', FileHistory.as_view()),
|
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/history/$', FileHistory.as_view()),
|
||||||
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/revision/$', FileRevision.as_view()),
|
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/revision/$', FileRevision.as_view()),
|
||||||
|
@ -62,9 +62,6 @@ 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.drafts.utils import get_file_draft, \
|
|
||||||
is_draft_file, has_draft_file
|
|
||||||
from seahub.signals import (repo_created, repo_deleted, repo_transfer)
|
from seahub.signals import (repo_created, repo_deleted, repo_transfer)
|
||||||
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, \
|
||||||
@ -3041,7 +3038,6 @@ 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':
|
||||||
@ -3186,17 +3182,6 @@ 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 is_valid_dirent_name(new_file_name):
|
if not is_valid_dirent_name(new_file_name):
|
||||||
@ -3212,9 +3197,6 @@ 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':
|
|
||||||
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:
|
||||||
@ -3385,18 +3367,10 @@ class FileDetailView(APIView):
|
|||||||
|
|
||||||
file_type, file_ext = get_file_type_and_ext(file_name)
|
file_type, file_ext = get_file_type_and_ext(file_name)
|
||||||
if file_type == MARKDOWN:
|
if file_type == MARKDOWN:
|
||||||
is_draft = is_draft_file(repo_id, path)
|
entry['is_draft'] = False
|
||||||
|
entry['has_draft'] = False
|
||||||
has_draft = False
|
entry['draft_file_path'] = ''
|
||||||
if not is_draft:
|
entry['draft_id'] = None
|
||||||
has_draft = has_draft_file(repo_id, path)
|
|
||||||
|
|
||||||
draft = get_file_draft(repo_id, path, is_draft, has_draft)
|
|
||||||
|
|
||||||
entry['is_draft'] = is_draft
|
|
||||||
entry['has_draft'] = has_draft
|
|
||||||
entry['draft_file_path'] = draft['draft_file_path']
|
|
||||||
entry['draft_id'] = draft['draft_id']
|
|
||||||
|
|
||||||
# fetch file contributors and latest contributor
|
# fetch file contributors and latest contributor
|
||||||
try:
|
try:
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
# Generated by Django 4.2.2 on 2024-08-27 14:16
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
import seahub.base.fields
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Draft',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('created_at', models.DateTimeField(auto_now_add=True, db_index=True)),
|
|
||||||
('updated_at', models.DateTimeField(auto_now=True, db_index=True)),
|
|
||||||
('username', seahub.base.fields.LowerCaseCharField(db_index=True, max_length=255)),
|
|
||||||
('status', models.CharField(default='open', max_length=20)),
|
|
||||||
('draft_file_path', models.CharField(max_length=1024)),
|
|
||||||
('origin_repo_id', models.CharField(db_index=True, max_length=36)),
|
|
||||||
('origin_file_uuid', models.UUIDField(unique=True)),
|
|
||||||
('origin_file_version', models.CharField(max_length=100)),
|
|
||||||
('publish_file_version', models.CharField(max_length=100, null=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'ordering': ['-created_at', '-updated_at'],
|
|
||||||
'abstract': False,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='DraftReviewer',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('reviewer', seahub.base.fields.LowerCaseCharField(db_index=True, max_length=255)),
|
|
||||||
('draft', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='drafts.draft')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,243 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import os
|
|
||||||
import json
|
|
||||||
import posixpath
|
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
from seaserv import seafile_api
|
|
||||||
|
|
||||||
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
|
|
||||||
from seahub.utils.timeutils import datetime_to_isoformat_timestr
|
|
||||||
from .utils import get_draft_file_name
|
|
||||||
|
|
||||||
|
|
||||||
class DraftFileExist(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class DraftFileConflict(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class OriginalFileConflict(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class DraftManager(models.Manager):
|
|
||||||
def get_draft_counts_by_repo_id(self, repo_id, status='open'):
|
|
||||||
num = self.filter(origin_repo_id=repo_id, status='open').count()
|
|
||||||
|
|
||||||
return num
|
|
||||||
|
|
||||||
def list_draft_by_repo_id(self, repo_id, status='open'):
|
|
||||||
"""list draft by repo id
|
|
||||||
"""
|
|
||||||
drafts = []
|
|
||||||
qs = self.filter(origin_repo_id=repo_id, status=status)
|
|
||||||
|
|
||||||
for d in qs:
|
|
||||||
draft = {}
|
|
||||||
draft['id'] = d.id
|
|
||||||
draft['owner_nickname'] = email2nickname(d.username)
|
|
||||||
draft['origin_repo_id'] = d.origin_repo_id
|
|
||||||
draft['draft_file_path'] = d.draft_file_path
|
|
||||||
draft['created_at'] = datetime_to_isoformat_timestr(d.created_at)
|
|
||||||
|
|
||||||
drafts.append(draft)
|
|
||||||
|
|
||||||
return drafts
|
|
||||||
|
|
||||||
def list_draft_by_username(self, username, status='open'):
|
|
||||||
"""list all user drafts
|
|
||||||
If with_reviews is true, return the draft associated review
|
|
||||||
"""
|
|
||||||
repo_cache = {}
|
|
||||||
|
|
||||||
def get_repo_with_cache(repo_id, repo_cache):
|
|
||||||
"""return repo object
|
|
||||||
Avoid loading the same repo multiple times
|
|
||||||
"""
|
|
||||||
if repo_id in repo_cache:
|
|
||||||
return repo_cache[repo_id]
|
|
||||||
|
|
||||||
repo = seafile_api.get_repo(repo_id)
|
|
||||||
repo_cache[repo_id] = repo
|
|
||||||
return repo
|
|
||||||
|
|
||||||
data = []
|
|
||||||
qs = self.filter(username=username, status=status)
|
|
||||||
|
|
||||||
for d in qs:
|
|
||||||
# If repo does not exist, no related items are displayed.
|
|
||||||
repo = get_repo_with_cache(d.origin_repo_id, repo_cache)
|
|
||||||
if not repo:
|
|
||||||
continue
|
|
||||||
|
|
||||||
uuid = FileUUIDMap.objects.get_fileuuidmap_by_uuid(d.origin_file_uuid)
|
|
||||||
file_path = posixpath.join(uuid.parent_path, uuid.filename)
|
|
||||||
|
|
||||||
draft = {}
|
|
||||||
draft['id'] = d.id
|
|
||||||
draft['owner'] = d.username
|
|
||||||
draft['repo_name'] = repo.name
|
|
||||||
draft['owner_nickname'] = email2nickname(d.username)
|
|
||||||
draft['origin_repo_id'] = d.origin_repo_id
|
|
||||||
draft['origin_file_path'] = file_path
|
|
||||||
draft['origin_file_version'] = d.origin_file_version
|
|
||||||
draft['draft_file_path'] = d.draft_file_path
|
|
||||||
draft['created_at'] = datetime_to_isoformat_timestr(d.created_at)
|
|
||||||
draft['updated_at'] = datetime_to_isoformat_timestr(d.updated_at)
|
|
||||||
draft['status'] = d.status
|
|
||||||
|
|
||||||
data.append(draft)
|
|
||||||
|
|
||||||
return data
|
|
||||||
|
|
||||||
def create_exist_file_draft(self, repo, username, file_uuid, file_path):
|
|
||||||
|
|
||||||
# check draft file does not exists and copy origin file content to
|
|
||||||
# draft file
|
|
||||||
draft_file_name = get_draft_file_name(repo.id, file_path)
|
|
||||||
draft_file_path = '/Drafts/' + draft_file_name
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Determine if there is a draft of the file
|
|
||||||
d = self.get(origin_file_uuid=file_uuid.uuid)
|
|
||||||
except Draft.DoesNotExist:
|
|
||||||
try:
|
|
||||||
# Determine if there is a draft with the same name as
|
|
||||||
# the generated draft file path
|
|
||||||
d_2 = self.get(origin_repo_id=repo.id, draft_file_path=draft_file_path)
|
|
||||||
d_2.delete(operator=username)
|
|
||||||
except Draft.DoesNotExist:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# copy file to draft dir
|
|
||||||
seafile_api.copy_file(repo.id, file_uuid.parent_path,
|
|
||||||
json.dumps([file_uuid.filename]),
|
|
||||||
repo.id, '/Drafts',
|
|
||||||
json.dumps([draft_file_name]),
|
|
||||||
username=username, need_progress=0, synchronous=1)
|
|
||||||
|
|
||||||
return draft_file_path
|
|
||||||
|
|
||||||
if d:
|
|
||||||
file_id = seafile_api.get_file_id_by_path(repo.id, d.draft_file_path)
|
|
||||||
# If the database entry exists and the draft file exists,
|
|
||||||
# then raise DraftFileExist
|
|
||||||
if file_id:
|
|
||||||
raise DraftFileExist
|
|
||||||
# If the database entry exists and the draft file does not exist,
|
|
||||||
# delete the database entry
|
|
||||||
else:
|
|
||||||
d.delete(operator=username)
|
|
||||||
|
|
||||||
# copy file to draft dir
|
|
||||||
seafile_api.copy_file(repo.id, file_uuid.parent_path,
|
|
||||||
json.dumps([file_uuid.filename]),
|
|
||||||
repo.id, '/Drafts',
|
|
||||||
json.dumps([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, 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)
|
|
||||||
|
|
||||||
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.uuid,
|
|
||||||
status=status,
|
|
||||||
origin_file_version=file_id,
|
|
||||||
draft_file_path=file_path)
|
|
||||||
draft.save(using=self._db)
|
|
||||||
return draft
|
|
||||||
|
|
||||||
|
|
||||||
class Draft(TimestampedModel):
|
|
||||||
"""Draft models enable user save file as drafts, and publish later.
|
|
||||||
"""
|
|
||||||
username = LowerCaseCharField(max_length=255, db_index=True)
|
|
||||||
status = models.CharField(max_length=20, default='open')
|
|
||||||
draft_file_path = models.CharField(max_length=1024)
|
|
||||||
origin_repo_id = models.CharField(max_length=36, db_index=True)
|
|
||||||
origin_file_uuid = models.UUIDField(unique=True)
|
|
||||||
origin_file_version = models.CharField(max_length=100)
|
|
||||||
publish_file_version = models.CharField(max_length=100, null=True)
|
|
||||||
|
|
||||||
objects = DraftManager()
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
seafile_api.del_file(self.origin_repo_id, draft_file_path,
|
|
||||||
json.dumps([draft_file_name]), operator)
|
|
||||||
|
|
||||||
super(Draft, self).delete()
|
|
||||||
|
|
||||||
def to_dict(self):
|
|
||||||
uuid = FileUUIDMap.objects.get_fileuuidmap_by_uuid(self.origin_file_uuid)
|
|
||||||
file_path = posixpath.join(uuid.parent_path, uuid.filename)
|
|
||||||
|
|
||||||
return {
|
|
||||||
'id': self.pk,
|
|
||||||
'owner': self.username,
|
|
||||||
'owner_nickname': email2nickname(self.username),
|
|
||||||
'origin_repo_id': self.origin_repo_id,
|
|
||||||
'origin_file_path': file_path,
|
|
||||||
'origin_file_version': self.origin_file_version,
|
|
||||||
'draft_file_path': self.draft_file_path,
|
|
||||||
'created_at': datetime_to_isoformat_timestr(self.created_at),
|
|
||||||
'updated_at': datetime_to_isoformat_timestr(self.updated_at),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class DraftReviewerManager(models.Manager):
|
|
||||||
def add(self, reviewer, draft):
|
|
||||||
reviewer = self.model(reviewer=reviewer, draft=draft)
|
|
||||||
reviewer.save(using=self._db)
|
|
||||||
|
|
||||||
return reviewer
|
|
||||||
|
|
||||||
|
|
||||||
class DraftReviewer(models.Model):
|
|
||||||
"""
|
|
||||||
Model used to record review reviewer.
|
|
||||||
"""
|
|
||||||
reviewer = LowerCaseCharField(max_length=255, db_index=True)
|
|
||||||
draft = models.ForeignKey('Draft', on_delete=models.CASCADE)
|
|
||||||
|
|
||||||
objects = DraftReviewerManager()
|
|
||||||
|
|
||||||
def to_dict(self):
|
|
||||||
return {
|
|
||||||
'name': email2nickname(self.reviewer),
|
|
||||||
'email': self.reviewer,
|
|
||||||
'contact_email': email2contact_email(self.reviewer)
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
# Copyright (c) 2012-2018 Seafile Ltd.
|
|
||||||
import django.dispatch
|
|
||||||
|
|
||||||
comment_draft_successful = django.dispatch.Signal()
|
|
||||||
request_reviewer_successful = django.dispatch.Signal()
|
|
||||||
update_review_successful = django.dispatch.Signal()
|
|
@ -1,9 +0,0 @@
|
|||||||
# Copyright (c) 2012-2016 Seafile Ltd.
|
|
||||||
from django.urls import path
|
|
||||||
|
|
||||||
from .views import draft, drafts
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path('', drafts, name='drafts'),
|
|
||||||
path('<int:pk>/', draft, name='draft'),
|
|
||||||
]
|
|
@ -1,135 +0,0 @@
|
|||||||
import hashlib
|
|
||||||
import os
|
|
||||||
import logging
|
|
||||||
import posixpath
|
|
||||||
import json
|
|
||||||
|
|
||||||
from seaserv import seafile_api
|
|
||||||
|
|
||||||
from seahub.utils import normalize_file_path, check_filename_with_rename
|
|
||||||
from seahub.tags.models import FileUUIDMap
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def create_user_draft_repo(username, org_id=-1):
|
|
||||||
repo_name = 'Drafts'
|
|
||||||
if org_id and org_id > 0:
|
|
||||||
repo_id = seafile_api.create_org_repo(repo_name, '', username, org_id)
|
|
||||||
else:
|
|
||||||
repo_id = seafile_api.create_repo(repo_name, '', username)
|
|
||||||
return repo_id
|
|
||||||
|
|
||||||
|
|
||||||
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))
|
|
||||||
|
|
||||||
draft_file_name = "%s%s%s" % (file_name, '(draft)', file_ext)
|
|
||||||
draft_file_name = check_filename_with_rename(repo_id, '/Drafts', draft_file_name)
|
|
||||||
|
|
||||||
return draft_file_name
|
|
||||||
|
|
||||||
|
|
||||||
def is_draft_file(repo_id, file_path):
|
|
||||||
is_draft = False
|
|
||||||
file_path = normalize_file_path(file_path)
|
|
||||||
|
|
||||||
from .models import Draft
|
|
||||||
try:
|
|
||||||
draft = Draft.objects.filter(origin_repo_id=repo_id, draft_file_path=file_path)
|
|
||||||
if draft:
|
|
||||||
is_draft = True
|
|
||||||
except Draft.DoesNotExist:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return is_draft
|
|
||||||
|
|
||||||
|
|
||||||
def has_draft_file(repo_id, file_path):
|
|
||||||
has_draft = False
|
|
||||||
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:
|
|
||||||
d = Draft.objects.filter(origin_file_uuid=file_uuid.uuid)
|
|
||||||
if d:
|
|
||||||
d = d[0]
|
|
||||||
file_id = seafile_api.get_file_id_by_path(repo_id, d.draft_file_path)
|
|
||||||
if file_id:
|
|
||||||
has_draft = True
|
|
||||||
else:
|
|
||||||
Draft.DoesNotExist
|
|
||||||
except Draft.DoesNotExist:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return has_draft
|
|
||||||
|
|
||||||
|
|
||||||
def get_file_draft(repo_id, file_path, is_draft=False, has_draft=False):
|
|
||||||
draft = {}
|
|
||||||
draft['draft_id'] = None
|
|
||||||
draft['draft_file_path'] = ''
|
|
||||||
draft['draft_origin_file_path'] = ''
|
|
||||||
|
|
||||||
from .models import Draft
|
|
||||||
|
|
||||||
if is_draft:
|
|
||||||
d = Draft.objects.filter(origin_repo_id=repo_id, draft_file_path=file_path)
|
|
||||||
if d:
|
|
||||||
d = d[0]
|
|
||||||
uuid = FileUUIDMap.objects.get_fileuuidmap_by_uuid(d.origin_file_uuid)
|
|
||||||
file_path = posixpath.join(uuid.parent_path, uuid.filename)
|
|
||||||
draft['draft_id'] = d.id
|
|
||||||
draft['draft_file_path'] = d.draft_file_path
|
|
||||||
draft['draft_origin_file_path'] = file_path
|
|
||||||
else:
|
|
||||||
Draft.DoesNotExist
|
|
||||||
|
|
||||||
if has_draft:
|
|
||||||
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)
|
|
||||||
|
|
||||||
d = Draft.objects.filter(origin_file_uuid=file_uuid.uuid)
|
|
||||||
if d:
|
|
||||||
d = d[0]
|
|
||||||
draft['draft_id'] = d.id
|
|
||||||
draft['draft_file_path'] = d.draft_file_path
|
|
||||||
else:
|
|
||||||
Draft.DoesNotExist
|
|
||||||
|
|
||||||
return draft
|
|
||||||
|
|
||||||
|
|
||||||
def send_draft_publish_msg(draft, username, path):
|
|
||||||
"""
|
|
||||||
send draft publish msg to seafevents
|
|
||||||
"""
|
|
||||||
|
|
||||||
repo_id = draft.origin_repo_id
|
|
||||||
old_path = draft.draft_file_path
|
|
||||||
|
|
||||||
msg = {
|
|
||||||
'msg_type': 'publish',
|
|
||||||
'obj_type': draft,
|
|
||||||
'repo_id': repo_id,
|
|
||||||
'user_name': username,
|
|
||||||
'path': path,
|
|
||||||
'old_path': old_path,
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
seafile_api.publish_event('seahub.draft', json.dumps(msg))
|
|
||||||
except Exception as e:
|
|
||||||
logger.error("Error when sending draft publish message: %s" % str(e))
|
|
@ -1,62 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
import os
|
|
||||||
import posixpath
|
|
||||||
|
|
||||||
from django.shortcuts import render, get_object_or_404
|
|
||||||
from django.utils.translation import gettext as _
|
|
||||||
from seaserv import seafile_api
|
|
||||||
|
|
||||||
from seahub.auth.decorators import login_required
|
|
||||||
from seahub.views import check_folder_permission
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def drafts(request):
|
|
||||||
return render(request, "react_app.html")
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def draft(request, pk):
|
|
||||||
d = get_object_or_404(Draft, pk=pk)
|
|
||||||
|
|
||||||
# check perm
|
|
||||||
uuid = FileUUIDMap.objects.get_fileuuidmap_by_uuid(d.origin_file_uuid)
|
|
||||||
origin_repo_id = d.origin_repo_id
|
|
||||||
permission = check_folder_permission(request, origin_repo_id, '/')
|
|
||||||
if not permission:
|
|
||||||
return render_permission_error(request, _('Permission denied.'))
|
|
||||||
|
|
||||||
origin_file_path = posixpath.join(uuid.parent_path, uuid.filename)
|
|
||||||
origin_file = seafile_api.get_file_id_by_path(origin_repo_id, origin_file_path)
|
|
||||||
origin_file_exists = True
|
|
||||||
if not origin_file:
|
|
||||||
origin_file_exists = False
|
|
||||||
|
|
||||||
draft_file = seafile_api.get_file_id_by_path(origin_repo_id, d.draft_file_path)
|
|
||||||
draft_file_exists = True
|
|
||||||
if not draft_file:
|
|
||||||
draft_file_exists = False
|
|
||||||
|
|
||||||
draft_file_name = os.path.basename(d.draft_file_path)
|
|
||||||
|
|
||||||
author_info = user_to_dict(d.username)
|
|
||||||
|
|
||||||
return render(request, "draft.html", {
|
|
||||||
"draft_id": d.id,
|
|
||||||
"draft_repo_id": origin_repo_id,
|
|
||||||
"draft_origin_file_path": origin_file_path,
|
|
||||||
"draft_file_path": d.draft_file_path,
|
|
||||||
"draft_file_name": draft_file_name,
|
|
||||||
"permission": permission,
|
|
||||||
"author": author_info['user_name'],
|
|
||||||
"author_avatar_url": author_info['avatar_url'],
|
|
||||||
"origin_file_exists": origin_file_exists,
|
|
||||||
"draft_file_exists": draft_file_exists,
|
|
||||||
"draft_status": d.status,
|
|
||||||
"publish_file_version": d.publish_file_version,
|
|
||||||
"origin_file_version": d.origin_file_version
|
|
||||||
})
|
|
@ -21,7 +21,6 @@ from seahub.base.templatetags.seahub_tags import email2nickname
|
|||||||
from seahub.invitations.models import Invitation
|
from seahub.invitations.models import Invitation
|
||||||
from seahub.utils import normalize_cache_key, get_site_scheme_and_netloc
|
from seahub.utils import normalize_cache_key, get_site_scheme_and_netloc
|
||||||
from seahub.constants import HASH_URLS
|
from seahub.constants import HASH_URLS
|
||||||
from seahub.drafts.models import DraftReviewer
|
|
||||||
from seahub.file_participants.utils import list_file_participants
|
from seahub.file_participants.utils import list_file_participants
|
||||||
|
|
||||||
# Get an instance of a logger
|
# Get an instance of a logger
|
||||||
@ -988,14 +987,11 @@ class UserNotification(models.Model):
|
|||||||
########## handle signals
|
########## handle signals
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
from seahub.signals import upload_file_successful, upload_folder_successful,\
|
from seahub.signals import upload_file_successful, upload_folder_successful, repo_transfer
|
||||||
comment_file_successful, repo_transfer
|
|
||||||
from seahub.group.signals import group_join_request, add_user_to_group
|
from seahub.group.signals import group_join_request, add_user_to_group
|
||||||
from seahub.share.signals import share_repo_to_user_successful, \
|
from seahub.share.signals import share_repo_to_user_successful, \
|
||||||
share_repo_to_group_successful, change_repo_perm_successful, delete_repo_perm_successful
|
share_repo_to_group_successful, change_repo_perm_successful, delete_repo_perm_successful
|
||||||
from seahub.invitations.signals import accept_guest_invitation_successful
|
from seahub.invitations.signals import accept_guest_invitation_successful
|
||||||
from seahub.drafts.signals import comment_draft_successful, \
|
|
||||||
request_reviewer_successful
|
|
||||||
from seahub.adfs_auth.signals import saml_sso_failed
|
from seahub.adfs_auth.signals import saml_sso_failed
|
||||||
|
|
||||||
|
|
||||||
@ -1120,47 +1116,6 @@ def add_user_to_group_cb(sender, **kwargs):
|
|||||||
UserNotification.objects.set_add_user_to_group_notice(to_user=added_user,
|
UserNotification.objects.set_add_user_to_group_notice(to_user=added_user,
|
||||||
detail=detail)
|
detail=detail)
|
||||||
|
|
||||||
@receiver(comment_file_successful)
|
|
||||||
def comment_file_successful_cb(sender, **kwargs):
|
|
||||||
""" send notification to file participants
|
|
||||||
"""
|
|
||||||
repo = kwargs['repo']
|
|
||||||
repo_owner = kwargs['repo_owner']
|
|
||||||
file_path = kwargs['file_path']
|
|
||||||
comment = kwargs['comment']
|
|
||||||
author = kwargs['author']
|
|
||||||
|
|
||||||
notify_users = list_file_participants(repo.id, file_path)
|
|
||||||
notify_users = [x for x in notify_users if x != author]
|
|
||||||
for u in notify_users:
|
|
||||||
detail = file_comment_msg_to_json(repo.id, file_path, author, comment)
|
|
||||||
UserNotification.objects.add_file_comment_msg(u, detail)
|
|
||||||
|
|
||||||
@receiver(comment_draft_successful)
|
|
||||||
def comment_draft_successful_cb(sender, **kwargs):
|
|
||||||
draft = kwargs['draft']
|
|
||||||
comment = kwargs['comment']
|
|
||||||
author = kwargs['author']
|
|
||||||
|
|
||||||
detail = draft_comment_msg_to_json(draft.id, author, comment)
|
|
||||||
|
|
||||||
if draft.username != author:
|
|
||||||
UserNotification.objects.add_draft_comment_msg(draft.username, detail)
|
|
||||||
|
|
||||||
reviewers = DraftReviewer.objects.filter(draft=draft)
|
|
||||||
for r in reviewers:
|
|
||||||
if r.reviewer != author:
|
|
||||||
UserNotification.objects.add_draft_comment_msg(r.reviewer, detail)
|
|
||||||
|
|
||||||
@receiver(request_reviewer_successful)
|
|
||||||
def requeset_reviewer_successful_cb(sender, **kwargs):
|
|
||||||
from_user = kwargs['from_user']
|
|
||||||
draft_id = kwargs['draft_id']
|
|
||||||
to_user = kwargs['to_user']
|
|
||||||
|
|
||||||
detail = request_reviewer_msg_to_json(draft_id, from_user, to_user)
|
|
||||||
|
|
||||||
UserNotification.objects.add_request_reviewer_msg(to_user, detail)
|
|
||||||
|
|
||||||
@receiver(accept_guest_invitation_successful)
|
@receiver(accept_guest_invitation_successful)
|
||||||
def accept_guest_invitation_successful_cb(sender, **kwargs):
|
def accept_guest_invitation_successful_cb(sender, **kwargs):
|
||||||
|
@ -245,7 +245,7 @@ INSTALLED_APPS = [
|
|||||||
'seahub.api2',
|
'seahub.api2',
|
||||||
'seahub.avatar',
|
'seahub.avatar',
|
||||||
'seahub.contacts',
|
'seahub.contacts',
|
||||||
'seahub.drafts',
|
# 'seahub.drafts',
|
||||||
'seahub.institutions',
|
'seahub.institutions',
|
||||||
'seahub.invitations',
|
'seahub.invitations',
|
||||||
'seahub.wiki',
|
'seahub.wiki',
|
||||||
|
@ -93,9 +93,6 @@ from seahub.api2.endpoints.notifications import NotificationsView, NotificationV
|
|||||||
from seahub.api2.endpoints.repo_file_uploaded_bytes import RepoFileUploadedBytesView
|
from seahub.api2.endpoints.repo_file_uploaded_bytes import RepoFileUploadedBytesView
|
||||||
from seahub.api2.endpoints.user_avatar import UserAvatarView
|
from seahub.api2.endpoints.user_avatar import UserAvatarView
|
||||||
from seahub.api2.endpoints.wikis import WikisView, WikiView
|
from seahub.api2.endpoints.wikis import WikisView, WikiView
|
||||||
from seahub.api2.endpoints.drafts import DraftsView, DraftView
|
|
||||||
from seahub.api2.endpoints.draft_reviewer import DraftReviewerView
|
|
||||||
from seahub.api2.endpoints.repo_draft_info import RepoDraftInfo, RepoDraftCounts
|
|
||||||
from seahub.api2.endpoints.activities import ActivitiesView
|
from seahub.api2.endpoints.activities import ActivitiesView
|
||||||
from seahub.api2.endpoints.wiki_pages import WikiPagesDirView, WikiPageContentView
|
from seahub.api2.endpoints.wiki_pages import WikiPagesDirView, WikiPageContentView
|
||||||
from seahub.api2.endpoints.revision_tag import TaggedItemsView, TagNamesView
|
from seahub.api2.endpoints.revision_tag import TaggedItemsView, TagNamesView
|
||||||
@ -557,12 +554,7 @@ urlpatterns = [
|
|||||||
re_path(r'^api/v2.1/wiki2/search/$', WikiSearch.as_view(), name='api-v2.1-wiki2-search'),
|
re_path(r'^api/v2.1/wiki2/search/$', WikiSearch.as_view(), name='api-v2.1-wiki2-search'),
|
||||||
re_path(r'^api/v2.1/convert-wiki/$', WikiConvertView.as_view(), name='api-v2.1-wiki-convert'),
|
re_path(r'^api/v2.1/convert-wiki/$', WikiConvertView.as_view(), name='api-v2.1-wiki-convert'),
|
||||||
## user::drafts
|
## user::drafts
|
||||||
re_path(r'^api/v2.1/drafts/$', DraftsView.as_view(), name='api-v2.1-drafts'),
|
|
||||||
re_path(r'^api/v2.1/drafts/(?P<pk>\d+)/$', DraftView.as_view(), name='api-v2.1-draft'),
|
|
||||||
|
|
||||||
re_path(r'^api/v2.1/drafts/(?P<pk>\d+)/reviewer/$', DraftReviewerView.as_view(), name='api-v2.1-draft-reviewer'),
|
|
||||||
re_path(r'^api/v2.1/repo/(?P<repo_id>[-0-9a-f]{36})/drafts/$', RepoDraftInfo.as_view(), name='api-v2.1-repo-drafts'),
|
|
||||||
re_path(r'^api/v2.1/repo/(?P<repo_id>[-0-9a-f]{36})/draft-counts/$', RepoDraftCounts.as_view(), name='api-v2.1-repo-draft-counts'),
|
|
||||||
|
|
||||||
## user::activities
|
## user::activities
|
||||||
re_path(r'^api/v2.1/activities/$', ActivitiesView.as_view(), name='api-v2.1-acitvity'),
|
re_path(r'^api/v2.1/activities/$', ActivitiesView.as_view(), name='api-v2.1-acitvity'),
|
||||||
@ -760,7 +752,7 @@ urlpatterns = [
|
|||||||
path('work-weixin/', include('seahub.work_weixin.urls')),
|
path('work-weixin/', include('seahub.work_weixin.urls')),
|
||||||
path('weixin/', include('seahub.weixin.urls')),
|
path('weixin/', include('seahub.weixin.urls')),
|
||||||
# Must specify a namespace if specifying app_name.
|
# Must specify a namespace if specifying app_name.
|
||||||
path('drafts/', include(('seahub.drafts.urls', 'drafts'), namespace='drafts')),
|
# path('drafts/', include(('seahub.drafts.urls', 'drafts'), namespace='drafts')),
|
||||||
|
|
||||||
## admin::address book
|
## admin::address book
|
||||||
re_path(r'^api/v2.1/admin/address-book/groups/$', AdminAddressBookGroups.as_view(), name='api-v2.1-admin-address-book-groups'),
|
re_path(r'^api/v2.1/admin/address-book/groups/$', AdminAddressBookGroups.as_view(), name='api-v2.1-admin-address-book-groups'),
|
||||||
|
@ -71,8 +71,6 @@ 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, get_share_link_thumbnail_src, get_thumbnail_image_path
|
XMIND_IMAGE_SIZE, get_share_link_thumbnail_src, get_thumbnail_image_path
|
||||||
from seahub.drafts.utils import get_file_draft, \
|
|
||||||
is_draft_file, has_draft_file
|
|
||||||
from seahub.seadoc.utils import get_seadoc_file_uuid, gen_seadoc_access_token, is_seadoc_revision
|
from seahub.seadoc.utils import get_seadoc_file_uuid, gen_seadoc_access_token, is_seadoc_revision
|
||||||
from seahub.seadoc.models import SeadocRevision
|
from seahub.seadoc.models import SeadocRevision
|
||||||
|
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
import json
|
|
||||||
|
|
||||||
from django.urls import reverse
|
|
||||||
|
|
||||||
from seaserv import seafile_api
|
|
||||||
from seahub.drafts.models import Draft
|
|
||||||
from seahub.test_utils import BaseTestCase
|
|
||||||
|
|
||||||
|
|
||||||
class DraftsViewTest(BaseTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.url = reverse('api-v2.1-drafts')
|
|
||||||
self.login_as(self.user)
|
|
||||||
|
|
||||||
def test_can_list(self):
|
|
||||||
resp = self.client.get(self.url)
|
|
||||||
self.assertEqual(200, resp.status_code)
|
|
||||||
|
|
||||||
json_resp = json.loads(resp.content)
|
|
||||||
|
|
||||||
def test_can_create(self):
|
|
||||||
assert len(Draft.objects.all()) == 0
|
|
||||||
|
|
||||||
resp = self.client.post(self.url, {
|
|
||||||
'repo_id': self.repo.id,
|
|
||||||
'file_path': self.file,
|
|
||||||
})
|
|
||||||
|
|
||||||
self.assertEqual(200, resp.status_code)
|
|
||||||
assert len(Draft.objects.all()) == 1
|
|
||||||
|
|
||||||
json_resp = json.loads(resp.content)
|
|
||||||
assert json_resp['owner'] == self.user.username
|
|
||||||
assert json_resp['origin_repo_id'] == self.repo.id
|
|
||||||
|
|
||||||
def test_create_same_file(self):
|
|
||||||
resp = self.client.post(self.url, {
|
|
||||||
'repo_id': self.repo.id,
|
|
||||||
'file_path': self.file,
|
|
||||||
})
|
|
||||||
|
|
||||||
self.assertEqual(200, resp.status_code)
|
|
||||||
|
|
||||||
resp = self.client.post(self.url, {
|
|
||||||
'repo_id': self.repo.id,
|
|
||||||
'file_path': self.file,
|
|
||||||
})
|
|
||||||
|
|
||||||
self.assertEqual(409, resp.status_code)
|
|
||||||
|
|
||||||
|
|
||||||
class DraftViewTest(BaseTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
seafile_api.post_dir(self.repo.id, '/', 'Drafts', self.user.username)
|
|
||||||
draft = Draft.objects.add(self.user.username, self.repo, self.file)
|
|
||||||
self.url = reverse('api-v2.1-draft', args=[draft.id])
|
|
||||||
|
|
||||||
self.login_as(self.user)
|
|
||||||
|
|
||||||
def test_can_delete(self):
|
|
||||||
assert len(Draft.objects.all()) == 1
|
|
||||||
|
|
||||||
resp = self.client.delete(self.url)
|
|
||||||
self.assertEqual(200, resp.status_code)
|
|
||||||
|
|
||||||
assert len(Draft.objects.all()) == 0
|
|
||||||
|
|
||||||
def test_can_publish(self):
|
|
||||||
assert len(Draft.objects.all()) == 1
|
|
||||||
|
|
||||||
resp = self.client.put(
|
|
||||||
self.url,
|
|
||||||
'operation=publish',
|
|
||||||
'application/x-www-form-urlencoded',
|
|
||||||
)
|
|
||||||
self.assertEqual(200, resp.status_code)
|
|
||||||
|
|
||||||
assert len(Draft.objects.all()) == 1
|
|
@ -1,104 +0,0 @@
|
|||||||
import json
|
|
||||||
|
|
||||||
from django.urls import reverse
|
|
||||||
|
|
||||||
from seahub.base.models import FileComment
|
|
||||||
from seahub.test_utils import BaseTestCase
|
|
||||||
|
|
||||||
class FileCommentTest(BaseTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.tmp_user = self.create_user()
|
|
||||||
|
|
||||||
self.tmp_repo_1_id = self.create_repo(
|
|
||||||
name='tmp-repo-1', desc='', username=self.tmp_user.username, passwd=None)
|
|
||||||
self.file1 = self.create_file(repo_id=self.tmp_repo_1_id, parent_dir='/',
|
|
||||||
filename='test1.txt',
|
|
||||||
username=self.tmp_user.username)
|
|
||||||
|
|
||||||
self.tmp_repo_2_id = self.create_repo(
|
|
||||||
name='tmp-repo-2', desc='', username=self.user.username, passwd=None)
|
|
||||||
self.file2 = self.create_file(repo_id=self.tmp_repo_2_id, parent_dir='/',
|
|
||||||
filename='test2.txt',
|
|
||||||
username=self.user.username)
|
|
||||||
|
|
||||||
o = FileComment.objects.add_by_file_path(repo_id=self.repo.id,
|
|
||||||
file_path=self.file,
|
|
||||||
author=self.tmp_user.username,
|
|
||||||
comment='test comment')
|
|
||||||
o1 = FileComment.objects.add_by_file_path(repo_id=self.tmp_repo_1_id,
|
|
||||||
file_path='/test1.txt',
|
|
||||||
author=self.tmp_user.username,
|
|
||||||
comment='test comment1')
|
|
||||||
o2 = FileComment.objects.add_by_file_path(repo_id=self.tmp_repo_2_id,
|
|
||||||
file_path='/test2.txt',
|
|
||||||
author=self.user.username,
|
|
||||||
comment='test comment2')
|
|
||||||
self.login_as(self.user)
|
|
||||||
|
|
||||||
self.endpoint = reverse('api2-file-comment', args=[self.repo.id, o.pk]) + '?p=' + self.file
|
|
||||||
self.endpoint1 = reverse('api2-file-comment', args=[self.repo.id, o1.pk]) + '?p=' + '/test1.txt'
|
|
||||||
self.endpoint2 = reverse('api2-file-comment', args=[self.repo.id, o2.pk]) + '?p=' + '/test2.txt'
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self.remove_repo()
|
|
||||||
self.remove_repo(repo_id=self.tmp_repo_1_id)
|
|
||||||
self.remove_repo(repo_id=self.tmp_repo_2_id)
|
|
||||||
self.remove_user()
|
|
||||||
self.remove_user(self.tmp_user.email)
|
|
||||||
FileComment.objects.all().delete()
|
|
||||||
|
|
||||||
def test_can_get(self):
|
|
||||||
resp = self.client.get(self.endpoint)
|
|
||||||
self.assertEqual(200, resp.status_code)
|
|
||||||
|
|
||||||
json_resp = json.loads(resp.content)
|
|
||||||
assert json_resp['repo_id'] == self.repo.id
|
|
||||||
assert json_resp['parent_path'] == '/'
|
|
||||||
assert json_resp['item_name'] == 'test.txt'
|
|
||||||
assert json_resp['user_email'] == self.tmp_user.email
|
|
||||||
assert 'avatars' in json_resp['avatar_url']
|
|
||||||
|
|
||||||
def test_can_not_get_other_repo_file_comment(self):
|
|
||||||
resp = self.client.get(self.endpoint1)
|
|
||||||
self.assertEqual(404, resp.status_code)
|
|
||||||
|
|
||||||
def test_can_not_get_other_user_file_comment(self):
|
|
||||||
resp = self.client.get(self.endpoint2)
|
|
||||||
self.assertEqual(404, resp.status_code)
|
|
||||||
|
|
||||||
def test_can_get_with_avatar_size(self):
|
|
||||||
resp = self.client.get(self.endpoint + '&avatar_size=20')
|
|
||||||
self.assertEqual(200, resp.status_code)
|
|
||||||
|
|
||||||
json_resp = json.loads(resp.content)
|
|
||||||
assert json_resp['parent_path'] == '/'
|
|
||||||
assert json_resp['item_name'] == 'test.txt'
|
|
||||||
assert json_resp['user_email'] == self.tmp_user.email
|
|
||||||
assert 'avatars' in json_resp['avatar_url']
|
|
||||||
|
|
||||||
def test_can_delete(self):
|
|
||||||
assert len(FileComment.objects.all()) == 3
|
|
||||||
resp = self.client.delete(self.endpoint)
|
|
||||||
self.assertEqual(204, resp.status_code)
|
|
||||||
assert len(FileComment.objects.all()) == 2
|
|
||||||
|
|
||||||
def test_can_not_delete_other_repo_file_comment(self):
|
|
||||||
assert len(FileComment.objects.all()) == 3
|
|
||||||
resp = self.client.delete(self.endpoint1)
|
|
||||||
self.assertEqual(404, resp.status_code)
|
|
||||||
assert len(FileComment.objects.all()) == 3
|
|
||||||
|
|
||||||
def test_can_not_delete_other_user_file_comment(self):
|
|
||||||
assert len(FileComment.objects.all()) == 3
|
|
||||||
resp = self.client.delete(self.endpoint2)
|
|
||||||
self.assertEqual(404, resp.status_code)
|
|
||||||
assert len(FileComment.objects.all()) == 3
|
|
||||||
|
|
||||||
def test_invalid_user_can_not_delete(self):
|
|
||||||
self.logout()
|
|
||||||
self.login_as(self.admin)
|
|
||||||
|
|
||||||
assert len(FileComment.objects.all()) == 3
|
|
||||||
resp = self.client.delete(self.endpoint)
|
|
||||||
self.assertEqual(403, resp.status_code)
|
|
||||||
assert len(FileComment.objects.all()) == 3
|
|
@ -1,103 +0,0 @@
|
|||||||
import json
|
|
||||||
|
|
||||||
from django.urls import reverse
|
|
||||||
import seaserv
|
|
||||||
from seaserv import seafile_api, ccnet_api
|
|
||||||
|
|
||||||
from seahub.base.models import FileComment
|
|
||||||
from seahub.notifications.models import UserNotification
|
|
||||||
from seahub.test_utils import BaseTestCase
|
|
||||||
from seahub.file_participants.models import FileParticipant
|
|
||||||
from seahub.tags.models import FileUUIDMap
|
|
||||||
|
|
||||||
class FileCommentsTest(BaseTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.tmp_user = self.create_user()
|
|
||||||
|
|
||||||
self.login_as(self.user)
|
|
||||||
self.endpoint = reverse('api2-file-comments', args=[self.repo.id]) + '?p=' + self.file
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self.remove_repo()
|
|
||||||
self.remove_user(self.tmp_user.email)
|
|
||||||
|
|
||||||
def test_can_list(self):
|
|
||||||
for i in range(10):
|
|
||||||
o = FileComment.objects.add_by_file_path(repo_id=self.repo.id,
|
|
||||||
file_path=self.file,
|
|
||||||
author=self.tmp_user.username,
|
|
||||||
comment='test comment'+str(i))
|
|
||||||
resp = self.client.get(self.endpoint + '&page=2&per_page=5')
|
|
||||||
self.assertEqual(200, resp.status_code)
|
|
||||||
|
|
||||||
json_resp = json.loads(resp.content)
|
|
||||||
link = reverse('api2-file-comments', args=[self.repo.id]) + '?page=1&per_page=5'
|
|
||||||
assert link in resp.headers.get('links')
|
|
||||||
assert len(json_resp['comments']) == 5
|
|
||||||
assert json_resp['comments'][0]['comment'] == 'test comment5'
|
|
||||||
assert json_resp['comments'][0]['user_email'] == self.tmp_user.email
|
|
||||||
assert 'avatars' in json_resp['comments'][0]['avatar_url']
|
|
||||||
assert json_resp['total_count'] == 10
|
|
||||||
|
|
||||||
def test_can_list_with_avatar_size(self):
|
|
||||||
o = FileComment.objects.add_by_file_path(repo_id=self.repo.id,
|
|
||||||
file_path=self.file,
|
|
||||||
author=self.tmp_user.username,
|
|
||||||
comment='test comment')
|
|
||||||
resp = self.client.get(self.endpoint + '&avatar_size=20')
|
|
||||||
self.assertEqual(200, resp.status_code)
|
|
||||||
|
|
||||||
json_resp = json.loads(resp.content)
|
|
||||||
assert len(json_resp['comments']) == 1
|
|
||||||
assert json_resp['comments'][0]['comment'] == o.comment
|
|
||||||
assert json_resp['comments'][0]['user_email'] == self.tmp_user.email
|
|
||||||
assert 'avatars' in json_resp['comments'][0]['avatar_url']
|
|
||||||
assert json_resp['total_count'] == 1
|
|
||||||
|
|
||||||
def test_can_post(self):
|
|
||||||
resp = self.client.post(self.endpoint, {
|
|
||||||
'comment': 'new comment'
|
|
||||||
})
|
|
||||||
self.assertEqual(201, resp.status_code)
|
|
||||||
|
|
||||||
json_resp = json.loads(resp.content)
|
|
||||||
assert json_resp['comment'] == 'new comment'
|
|
||||||
assert 'avatars' in json_resp['avatar_url']
|
|
||||||
|
|
||||||
def test_can_post_with_avatar_size(self):
|
|
||||||
resp = self.client.post(self.endpoint + '&avatar_size=20', {
|
|
||||||
'comment': 'new comment'
|
|
||||||
})
|
|
||||||
self.assertEqual(201, resp.status_code)
|
|
||||||
|
|
||||||
json_resp = json.loads(resp.content)
|
|
||||||
assert json_resp['comment'] == 'new comment'
|
|
||||||
assert 'avatars' in json_resp['avatar_url']
|
|
||||||
|
|
||||||
def test_invalid_user(self):
|
|
||||||
self.logout()
|
|
||||||
self.login_as(self.admin)
|
|
||||||
|
|
||||||
resp = self.client.get(self.endpoint)
|
|
||||||
self.assertEqual(403, resp.status_code)
|
|
||||||
|
|
||||||
resp = self.client.post(self.endpoint, {
|
|
||||||
'comment': 'new comment'
|
|
||||||
})
|
|
||||||
self.assertEqual(403, resp.status_code)
|
|
||||||
|
|
||||||
def test_can_notify_participant(self):
|
|
||||||
assert len(UserNotification.objects.all()) == 0
|
|
||||||
|
|
||||||
# share repo and add participant
|
|
||||||
seafile_api.share_repo(self.repo.id, self.user.username, self.admin.username, 'rw')
|
|
||||||
file_uuid = FileUUIDMap.objects.get_or_create_fileuuidmap_by_path(self.repo.id, self.file, False)
|
|
||||||
FileParticipant.objects.add_participant(file_uuid, self.admin.username)
|
|
||||||
|
|
||||||
resp = self.client.post(self.endpoint, {
|
|
||||||
'comment': 'new comment'
|
|
||||||
})
|
|
||||||
self.assertEqual(201, resp.status_code)
|
|
||||||
|
|
||||||
assert len(UserNotification.objects.all()) == 1
|
|
||||||
assert UserNotification.objects.all()[0].to_user == self.admin.username
|
|
@ -1,60 +0,0 @@
|
|||||||
import json
|
|
||||||
|
|
||||||
from django.urls import reverse
|
|
||||||
|
|
||||||
from seahub.base.models import FileComment
|
|
||||||
from seahub.test_utils import BaseTestCase
|
|
||||||
|
|
||||||
class FileCommentsCountsTest(BaseTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.login_as(self.user)
|
|
||||||
self.endpoint = reverse('api2-file-comments-counts', args=[self.repo.id]) + '?p=/'
|
|
||||||
|
|
||||||
self.file2 = self.create_file(repo_id=self.repo.id, parent_dir='/',
|
|
||||||
filename='test2.txt',
|
|
||||||
username=self.user.username)
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self.remove_repo()
|
|
||||||
|
|
||||||
def test_can_get(self):
|
|
||||||
FileComment.objects.add_by_file_path(repo_id=self.repo.id,
|
|
||||||
file_path=self.file,
|
|
||||||
author=self.user.username,
|
|
||||||
comment='test comment')
|
|
||||||
|
|
||||||
FileComment.objects.add_by_file_path(repo_id=self.repo.id,
|
|
||||||
file_path=self.file,
|
|
||||||
author=self.user.username,
|
|
||||||
comment='reply test comment')
|
|
||||||
|
|
||||||
FileComment.objects.add_by_file_path(repo_id=self.repo.id,
|
|
||||||
file_path=self.file2,
|
|
||||||
author=self.user.username,
|
|
||||||
comment='test comment on other file')
|
|
||||||
|
|
||||||
resp = self.client.get(self.endpoint)
|
|
||||||
self.assertEqual(200, resp.status_code)
|
|
||||||
|
|
||||||
json_resp = json.loads(resp.content)
|
|
||||||
assert len(json_resp) == 2
|
|
||||||
for d in json_resp:
|
|
||||||
if list(d.keys())[0] == 'test.txt':
|
|
||||||
assert d['test.txt'] == 2
|
|
||||||
|
|
||||||
if list(d.keys())[0] == 'test2.txt':
|
|
||||||
assert d['test2.txt'] == 1
|
|
||||||
|
|
||||||
# def test_can_get_file(self):
|
|
||||||
# FileComment.objects.add_by_file_path(repo_id=self.repo.id,
|
|
||||||
# file_path=self.file2,
|
|
||||||
# author=self.user.username,
|
|
||||||
# comment='test comment on other file')
|
|
||||||
|
|
||||||
# FileComment.objects.add_by_file_path(repo_id=self.repo.id,
|
|
||||||
# file_path=self.file2,
|
|
||||||
# author=self.user.username,
|
|
||||||
# comment='test comment on other file123')
|
|
||||||
# self.file_request= reverse('api2-file-comments-counts', args=[self.repo.id]) + '?p=' + self.file2
|
|
||||||
# resp = self.client.get(self.file_request)
|
|
||||||
# self.assertEqual(404, resp.status_code)
|
|
@ -1,103 +0,0 @@
|
|||||||
from django.urls import reverse
|
|
||||||
from seahub.drafts.models import Draft
|
|
||||||
from seahub.test_utils import BaseTestCase
|
|
||||||
|
|
||||||
from seaserv import seafile_api
|
|
||||||
|
|
||||||
|
|
||||||
class DraftManagerTest(BaseTestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
seafile_api.post_dir(self.repo.id, '/', 'Drafts', self.user.username)
|
|
||||||
|
|
||||||
def test_list_draft_by_username(self):
|
|
||||||
assert len(Draft.objects.all()) == 0
|
|
||||||
Draft.objects.add(self.user.username, self.repo, self.file)
|
|
||||||
|
|
||||||
draft_list = Draft.objects.list_draft_by_username(self.user.username)
|
|
||||||
|
|
||||||
assert len(draft_list) == 1
|
|
||||||
|
|
||||||
def test_list_draft_by_username_with_invalid_repo(self):
|
|
||||||
self.login_as(self.user)
|
|
||||||
assert len(Draft.objects.all()) == 0
|
|
||||||
Draft.objects.add(self.user.username, self.repo, self.file)
|
|
||||||
|
|
||||||
url = reverse('api2-repo', args=[self.repo.id])
|
|
||||||
resp = self.client.delete(url, {}, 'application/x-www-form-urlencoded')
|
|
||||||
|
|
||||||
self.assertEqual(200, resp.status_code)
|
|
||||||
|
|
||||||
draft_list = Draft.objects.list_draft_by_username(self.user.username)
|
|
||||||
|
|
||||||
assert len(draft_list) == 0
|
|
||||||
assert len(Draft.objects.all()) == 1
|
|
||||||
|
|
||||||
def test_list_draft_by_username_with_invalid_origin_file(self):
|
|
||||||
self.login_as(self.user)
|
|
||||||
assert len(Draft.objects.all()) == 0
|
|
||||||
|
|
||||||
url = reverse('api-v2.1-drafts')
|
|
||||||
resp = self.client.post(url, {
|
|
||||||
'repo_id': self.repo.id,
|
|
||||||
'file_path': self.file,
|
|
||||||
})
|
|
||||||
|
|
||||||
self.assertEqual(200, resp.status_code)
|
|
||||||
|
|
||||||
file_url = reverse('api-v2.1-file-view', args=[self.repo.id])
|
|
||||||
d_resp = self.client.delete(file_url + '?p=' + self.file,
|
|
||||||
{}, 'application/x-www-form-urlencoded')
|
|
||||||
|
|
||||||
self.assertEqual(200, d_resp.status_code)
|
|
||||||
|
|
||||||
draft_list = Draft.objects.list_draft_by_username(self.user.username)
|
|
||||||
|
|
||||||
assert len(draft_list) == 1
|
|
||||||
assert len(Draft.objects.all()) == 1
|
|
||||||
|
|
||||||
def test_add(self):
|
|
||||||
assert len(Draft.objects.all()) == 0
|
|
||||||
draft = Draft.objects.add(self.user.username, self.repo, self.file)
|
|
||||||
|
|
||||||
assert draft is not None
|
|
||||||
assert len(Draft.objects.all()) == 1
|
|
||||||
|
|
||||||
d = draft.to_dict()
|
|
||||||
assert d['origin_repo_id'] == self.repo.id
|
|
||||||
assert d['origin_file_path'] == self.file
|
|
||||||
assert len(d['draft_file_path']) > 0
|
|
||||||
|
|
||||||
def test_add_another_file(self):
|
|
||||||
file2 = self.create_file(repo_id=self.repo.id,
|
|
||||||
parent_dir='/',
|
|
||||||
filename='test2.txt',
|
|
||||||
username=self.user.username)
|
|
||||||
|
|
||||||
assert len(Draft.objects.all()) == 0
|
|
||||||
draft = Draft.objects.add(self.user.username, self.repo, self.file)
|
|
||||||
assert draft is not None
|
|
||||||
assert len(Draft.objects.all()) == 1
|
|
||||||
|
|
||||||
draft2 = Draft.objects.add(self.user.username, self.repo, file2)
|
|
||||||
assert draft2 is not None
|
|
||||||
assert len(Draft.objects.all()) == 2
|
|
||||||
|
|
||||||
|
|
||||||
class DraftTest(BaseTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
seafile_api.post_dir(self.repo.id, '/', 'Drafts', self.user.username)
|
|
||||||
|
|
||||||
def test_delete(self):
|
|
||||||
assert len(Draft.objects.all()) == 0
|
|
||||||
d = Draft.objects.add(self.user.username, self.repo, self.file)
|
|
||||||
|
|
||||||
assert d is not None
|
|
||||||
assert len(Draft.objects.all()) == 1
|
|
||||||
assert seafile_api.get_file_id_by_path(d.origin_repo_id, d.draft_file_path) is not None
|
|
||||||
|
|
||||||
d = Draft.objects.all()[0]
|
|
||||||
d.delete(self.user.username)
|
|
||||||
|
|
||||||
assert len(Draft.objects.all()) == 0
|
|
||||||
assert seafile_api.get_file_id_by_path(d.origin_repo_id, d.draft_file_path) is None
|
|
Loading…
Reference in New Issue
Block a user