mirror of
https://github.com/haiwen/seahub.git
synced 2025-04-28 03:10:45 +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.base.templatetags.seahub_tags import email2nickname
|
||||
from seahub.avatar.templatetags.avatar_tags import api_avatar_url
|
||||
from seahub.drafts.models import Draft
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -81,19 +80,6 @@ class ActivitiesView(APIView):
|
||||
d['old_name'] = os.path.basename(e.old_path)
|
||||
elif e.op_type == 'publish':
|
||||
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)
|
||||
|
||||
|
@ -18,7 +18,6 @@ from seahub.api2.throttling import UserRateThrottle
|
||||
from seahub.api2.authentication import TokenAuthentication
|
||||
from seahub.base.templatetags.seahub_tags import email2nickname
|
||||
from seahub.avatar.templatetags.avatar_tags import api_avatar_url
|
||||
from seahub.drafts.models import Draft
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -98,20 +97,6 @@ class UserActivitiesView(APIView):
|
||||
d['old_name'] = os.path.basename(e.old_path)
|
||||
elif e.op_type == 'publish':
|
||||
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)
|
||||
|
||||
response = {'events': events_list}
|
||||
|
@ -1901,26 +1901,6 @@ class AdminUpdateUserCcnetEmail(APIView):
|
||||
except Exception as 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:
|
||||
from seahub.file_participants.models import FileParticipant
|
||||
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.api2.endpoints.utils import convert_file, sdoc_convert_to_docx
|
||||
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 pysearpc import SearpcError
|
||||
|
||||
@ -170,8 +166,6 @@ class FileView(APIView):
|
||||
username = request.user.username
|
||||
parent_dir = os.path.dirname(path)
|
||||
|
||||
is_draft = request.POST.get('is_draft', '')
|
||||
|
||||
if operation == 'create':
|
||||
|
||||
# resource check
|
||||
@ -191,17 +185,6 @@ class FileView(APIView):
|
||||
error_msg = 'Permission denied.'
|
||||
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
|
||||
new_file_name = os.path.basename(path)
|
||||
|
||||
@ -223,9 +206,6 @@ class FileView(APIView):
|
||||
error_msg = 'Internal Server Error'
|
||||
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 = {
|
||||
'cs': 'cs-CZ',
|
||||
'de': 'de-DE',
|
||||
@ -349,18 +329,6 @@ class FileView(APIView):
|
||||
|
||||
# rename draft file
|
||||
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)
|
||||
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.utils import EVENTS_ENABLED, get_user_activities_by_timestamp
|
||||
from seahub.api2.utils import api_error
|
||||
from seahub.drafts.models import Draft
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -59,22 +58,6 @@ class RecentAddedFilesView(APIView):
|
||||
file_dict = dict(repo_id=event.repo_id)
|
||||
file_dict['path'] = event.path
|
||||
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)
|
||||
|
||||
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.views import check_folder_permission
|
||||
|
||||
from seahub.drafts.models import Draft
|
||||
|
||||
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,14 +1120,13 @@ class ShareLinkUploadDone(APIView):
|
||||
share_link = None
|
||||
upload_link = None
|
||||
|
||||
try:
|
||||
share_link = FileShare.objects.get_valid_dir_link_by_token(token=token)
|
||||
except FileShare.DoesNotExist:
|
||||
upload_link = UploadLinkShare.objects.get(token=token)
|
||||
except UploadLinkShare.DoesNotExist:
|
||||
share_link = FileShare.objects.get_valid_dir_link_by_token(token=token)
|
||||
upload_link = UploadLinkShare.objects.filter(token=token).first()
|
||||
|
||||
if not (share_link or upload_link):
|
||||
error_msg = 'token %s not found.' % token
|
||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||
|
||||
|
||||
if share_link:
|
||||
|
||||
# check if login required
|
||||
@ -1182,7 +1181,7 @@ class ShareLinkUploadDone(APIView):
|
||||
if upload_link.is_expired():
|
||||
error_msg = 'Upload link is expired'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
|
||||
repo_id = upload_link.repo_id
|
||||
repo = seafile_api.get_repo(repo_id)
|
||||
if not repo:
|
||||
@ -1196,7 +1195,7 @@ class ShareLinkUploadDone(APIView):
|
||||
link_owner) != 'rw':
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
|
||||
# send signal
|
||||
dirent_path = request.data.get('file_path')
|
||||
if not dirent_path:
|
||||
|
@ -19,8 +19,6 @@ from urllib.parse import quote
|
||||
|
||||
from seahub.api2.authentication import RepoAPITokenAuthentication
|
||||
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.api2.throttling import UserRateThrottle
|
||||
from seahub.api2.utils import api_error, to_python_boolean
|
||||
@ -817,9 +815,6 @@ class ViaRepoTokenFile(APIView):
|
||||
|
||||
username = ''
|
||||
parent_dir = os.path.dirname(path)
|
||||
|
||||
is_draft = request.POST.get('is_draft', '')
|
||||
|
||||
if operation == 'create':
|
||||
|
||||
# resource check
|
||||
@ -839,17 +834,6 @@ class ViaRepoTokenFile(APIView):
|
||||
error_msg = 'Permission denied.'
|
||||
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
|
||||
new_file_name = os.path.basename(path)
|
||||
|
||||
@ -871,9 +855,6 @@ class ViaRepoTokenFile(APIView):
|
||||
error_msg = 'Internal Server Error'
|
||||
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 = {
|
||||
'cs': 'cs-CZ',
|
||||
'de': 'de-DE',
|
||||
|
@ -9,9 +9,6 @@ from .endpoints.dir_shared_items import DirSharedItemsEndpoint
|
||||
from .endpoints.admin.account import Account
|
||||
from .endpoints.shared_upload_links import SharedUploadLinksView
|
||||
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.send_share_link_email import SendShareLinkView
|
||||
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/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-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/history/$', FileHistory.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.options.models import UserOptions
|
||||
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.share.models import FileShare, OrgFileShare, UploadLinkShare
|
||||
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
|
||||
parent_dir = os.path.dirname(path)
|
||||
operation = request.POST.get('operation', '')
|
||||
is_draft = request.POST.get('is_draft', '')
|
||||
|
||||
file_info = {}
|
||||
if operation.lower() == 'rename':
|
||||
@ -3186,17 +3182,6 @@ class FileView(APIView):
|
||||
return api_error(status.HTTP_403_FORBIDDEN,
|
||||
'You do not have permission to create file.')
|
||||
|
||||
if is_draft.lower() == 'true':
|
||||
file_name = os.path.basename(path)
|
||||
file_dir = os.path.dirname(path)
|
||||
|
||||
draft_type = os.path.splitext(file_name)[0][-7:]
|
||||
file_type = os.path.splitext(file_name)[-1]
|
||||
|
||||
if draft_type != '(draft)':
|
||||
f = os.path.splitext(file_name)[0]
|
||||
path = file_dir + '/' + f + '(draft)' + file_type
|
||||
|
||||
new_file_name = os.path.basename(path)
|
||||
|
||||
if not is_valid_dirent_name(new_file_name):
|
||||
@ -3212,9 +3197,6 @@ class FileView(APIView):
|
||||
return api_error(HTTP_520_OPERATION_FAILED,
|
||||
'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':
|
||||
return reloaddir(request, repo, parent_dir)
|
||||
else:
|
||||
@ -3385,18 +3367,10 @@ class FileDetailView(APIView):
|
||||
|
||||
file_type, file_ext = get_file_type_and_ext(file_name)
|
||||
if file_type == MARKDOWN:
|
||||
is_draft = is_draft_file(repo_id, path)
|
||||
|
||||
has_draft = False
|
||||
if not is_draft:
|
||||
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']
|
||||
entry['is_draft'] = False
|
||||
entry['has_draft'] = False
|
||||
entry['draft_file_path'] = ''
|
||||
entry['draft_id'] = None
|
||||
|
||||
# fetch file contributors and latest contributor
|
||||
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.utils import normalize_cache_key, get_site_scheme_and_netloc
|
||||
from seahub.constants import HASH_URLS
|
||||
from seahub.drafts.models import DraftReviewer
|
||||
from seahub.file_participants.utils import list_file_participants
|
||||
|
||||
# Get an instance of a logger
|
||||
@ -988,14 +987,11 @@ class UserNotification(models.Model):
|
||||
########## handle signals
|
||||
from django.dispatch import receiver
|
||||
|
||||
from seahub.signals import upload_file_successful, upload_folder_successful,\
|
||||
comment_file_successful, repo_transfer
|
||||
from seahub.signals import upload_file_successful, upload_folder_successful, repo_transfer
|
||||
from seahub.group.signals import group_join_request, add_user_to_group
|
||||
from seahub.share.signals import share_repo_to_user_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.drafts.signals import comment_draft_successful, \
|
||||
request_reviewer_successful
|
||||
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,
|
||||
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)
|
||||
def accept_guest_invitation_successful_cb(sender, **kwargs):
|
||||
|
@ -245,7 +245,7 @@ INSTALLED_APPS = [
|
||||
'seahub.api2',
|
||||
'seahub.avatar',
|
||||
'seahub.contacts',
|
||||
'seahub.drafts',
|
||||
# 'seahub.drafts',
|
||||
'seahub.institutions',
|
||||
'seahub.invitations',
|
||||
'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.user_avatar import UserAvatarView
|
||||
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.wiki_pages import WikiPagesDirView, WikiPageContentView
|
||||
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/convert-wiki/$', WikiConvertView.as_view(), name='api-v2.1-wiki-convert'),
|
||||
## 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
|
||||
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('weixin/', include('seahub.weixin.urls')),
|
||||
# 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
|
||||
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.thumbnail.utils import extract_xmind_image, get_thumbnail_src, \
|
||||
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.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