1
0
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:
Ranjiwei 2024-12-06 21:45:32 +08:00 committed by GitHub
parent f4d15fb574
commit 7e2bbdac8e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 15 additions and 1718 deletions

View File

@ -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)

View File

@ -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}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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})

View File

@ -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)

View File

@ -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:

View File

@ -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',

View File

@ -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()),

View File

@ -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:

View File

@ -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')),
],
),
]

View File

@ -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)
}

View File

@ -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()

View File

@ -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'),
]

View File

@ -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))

View File

@ -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
})

View File

@ -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):

View File

@ -245,7 +245,7 @@ INSTALLED_APPS = [
'seahub.api2',
'seahub.avatar',
'seahub.contacts',
'seahub.drafts',
# 'seahub.drafts',
'seahub.institutions',
'seahub.invitations',
'seahub.wiki',

View File

@ -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'),

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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