mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-25 14:50:29 +00:00
update api validation
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Copyright (c) 2012-2016 Seafile Ltd.
|
# Copyright (c) 2012-2016 Seafile Ltd.
|
||||||
import logging
|
import logging
|
||||||
|
import json
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.authentication import SessionAuthentication
|
from rest_framework.authentication import SessionAuthentication
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
@@ -22,52 +22,354 @@ from seahub.signals import comment_file_successful
|
|||||||
from seahub.api2.endpoints.utils import generate_links_header_for_paginator
|
from seahub.api2.endpoints.utils import generate_links_header_for_paginator
|
||||||
from seahub.views import check_folder_permission
|
from seahub.views import check_folder_permission
|
||||||
|
|
||||||
from seahub.seadoc.models import SeadocCommentReply
|
from seahub.seadoc.models import SeadocCommentReply, SeadocNotification
|
||||||
from seahub.file_participants.models import FileParticipant
|
from seahub.file_participants.models import FileParticipant
|
||||||
from seahub.utils.timeutils import utc_to_local, datetime_to_isoformat_timestr, datetime_to_timestamp
|
from seahub.utils.timeutils import utc_to_local, datetime_to_isoformat_timestr, datetime_to_timestamp
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
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.')
|
||||||
|
#
|
||||||
|
# file_uuid = request.GET.get('docuuid', None)
|
||||||
|
# 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)
|
||||||
|
#
|
||||||
|
# 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]
|
||||||
|
#
|
||||||
|
# reply_queryset = SeadocCommentReply.objects.list_by_doc_uuid(file_uuid)
|
||||||
|
#
|
||||||
|
# for file_comment in file_comments:
|
||||||
|
# comment = file_comment.to_dict(reply_queryset)
|
||||||
|
# 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.
|
||||||
|
# """
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
# 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.')
|
||||||
|
#
|
||||||
|
# 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)
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# comment = file_comment.to_dict()
|
||||||
|
# comment.update(user_to_dict(username, request=request))
|
||||||
|
# return Response(comment, status=201)
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# class FileCommentRepliesView(APIView):
|
||||||
|
# authentication_classes = ()
|
||||||
|
# throttle_classes = (UserRateThrottle,)
|
||||||
|
#
|
||||||
|
# def get(self, request, repo_id, file_uuid, comment_id):
|
||||||
|
# """list replies
|
||||||
|
# """
|
||||||
|
# # auth = request.headers.get('authorization', '').split()
|
||||||
|
# # if not is_valid_seadoc_access_token(auth, file_uuid):
|
||||||
|
# # error_msg = 'Permission denied.'
|
||||||
|
# # return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
#
|
||||||
|
# start = None
|
||||||
|
# end = None
|
||||||
|
# page = request.GET.get('page', '')
|
||||||
|
# if page:
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
# # resource check
|
||||||
|
# file_comment = FileComment.objects.filter(
|
||||||
|
# id=comment_id, uuid=file_uuid).first()
|
||||||
|
# if not file_comment:
|
||||||
|
# return api_error(status.HTTP_404_NOT_FOUND, 'comment not found.')
|
||||||
|
#
|
||||||
|
# total_count = SeadocCommentReply.objects.list_by_comment_id(comment_id).count()
|
||||||
|
# replies = []
|
||||||
|
# reply_queryset = SeadocCommentReply.objects.list_by_comment_id(comment_id)[start: end]
|
||||||
|
# for reply in reply_queryset:
|
||||||
|
# data = reply.to_dict()
|
||||||
|
# data.update(
|
||||||
|
# user_to_dict(reply.author, request=request))
|
||||||
|
# replies.append(data)
|
||||||
|
#
|
||||||
|
# result = {'replies': replies, 'total_count': total_count}
|
||||||
|
# return Response(result)
|
||||||
|
#
|
||||||
|
# def post(self, request, repo_id, file_uuid, comment_id):
|
||||||
|
# """post a reply
|
||||||
|
# """
|
||||||
|
# # argument check
|
||||||
|
# # auth = request.headers.get('authorization', '').split()
|
||||||
|
# # is_valid, payload = is_valid_seadoc_access_token(auth, file_uuid, return_payload=True)
|
||||||
|
# # if not is_valid:
|
||||||
|
# # error_msg = 'Permission denied.'
|
||||||
|
# # return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
#
|
||||||
|
# reply_content = request.data.get('reply', '')
|
||||||
|
# type_content = request.data.get('type', 'reply')
|
||||||
|
# author = request.data.get('author', '')
|
||||||
|
# username = author
|
||||||
|
#
|
||||||
|
# if reply_content is None:
|
||||||
|
# return api_error(status.HTTP_400_BAD_REQUEST, 'reply invalid.')
|
||||||
|
# if not username:
|
||||||
|
# return api_error(status.HTTP_400_BAD_REQUEST, 'author invalid.')
|
||||||
|
#
|
||||||
|
# # resource check
|
||||||
|
# file_comment = FileComment.objects.filter(
|
||||||
|
# id=comment_id, uuid=file_uuid).first()
|
||||||
|
# if not file_comment:
|
||||||
|
# return api_error(status.HTTP_404_NOT_FOUND, 'comment not found.')
|
||||||
|
#
|
||||||
|
# reply = SeadocCommentReply.objects.create(
|
||||||
|
# author=username,
|
||||||
|
# reply=str(reply_content),
|
||||||
|
# type=str(type_content),
|
||||||
|
# comment_id=comment_id,
|
||||||
|
# doc_uuid=file_uuid,
|
||||||
|
# )
|
||||||
|
# data = reply.to_dict()
|
||||||
|
# data.update(user_to_dict(reply.author, request=request))
|
||||||
|
#
|
||||||
|
# # notification
|
||||||
|
# to_users = set()
|
||||||
|
# participant_queryset = FileParticipant.objects.get_participants(file_uuid)
|
||||||
|
# for participant in participant_queryset:
|
||||||
|
# to_users.add(participant.username)
|
||||||
|
# to_users.discard(username) # remove author
|
||||||
|
# to_users = list(to_users)
|
||||||
|
# detail = {
|
||||||
|
# 'author': username,
|
||||||
|
# 'comment_id': int(comment_id),
|
||||||
|
# 'reply_id': reply.pk,
|
||||||
|
# 'reply': str(reply_content),
|
||||||
|
# 'msg_type': 'reply',
|
||||||
|
# 'created_at': datetime_to_isoformat_timestr(reply.created_at),
|
||||||
|
# 'updated_at': datetime_to_isoformat_timestr(reply.updated_at),
|
||||||
|
# 'is_resolved': type(reply_content) is bool and reply_content is True,
|
||||||
|
# 'resolve_comment': file_comment.comment.strip()
|
||||||
|
# }
|
||||||
|
# detail.update(user_to_dict(username, request=request))
|
||||||
|
#
|
||||||
|
# # new_notifications = []
|
||||||
|
# # for to_user in to_users:
|
||||||
|
# # new_notifications.append(
|
||||||
|
# # SeadocNotification(
|
||||||
|
# # doc_uuid=file_uuid,
|
||||||
|
# # username=to_user,
|
||||||
|
# # msg_type='reply',
|
||||||
|
# # detail=json.dumps(detail),
|
||||||
|
# # ))
|
||||||
|
# # try:
|
||||||
|
# # SeadocNotification.objects.bulk_create(new_notifications)
|
||||||
|
# # except Exception as e:
|
||||||
|
# # logger.error(e)
|
||||||
|
# # error_msg = 'Internal Server Error'
|
||||||
|
# # return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
#
|
||||||
|
# notification = detail
|
||||||
|
# notification['to_users'] = to_users
|
||||||
|
# data['notification'] = notification
|
||||||
|
# return Response(data)
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# class FileCommentReplyView(APIView):
|
||||||
|
# authentication_classes = ()
|
||||||
|
# throttle_classes = (UserRateThrottle,)
|
||||||
|
#
|
||||||
|
# def get(self, request, repo_id, file_uuid, comment_id, reply_id):
|
||||||
|
# """Get a comment reply
|
||||||
|
# """
|
||||||
|
# # auth = request.headers.get('authorization', '').split()
|
||||||
|
# # if not is_valid_seadoc_access_token(auth, file_uuid):
|
||||||
|
# # error_msg = 'Permission denied.'
|
||||||
|
# # return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
#
|
||||||
|
# # resource check
|
||||||
|
# file_comment = FileComment.objects.filter(
|
||||||
|
# id=comment_id, uuid=file_uuid).first()
|
||||||
|
# if not file_comment:
|
||||||
|
# return api_error(status.HTTP_404_NOT_FOUND, 'comment not found.')
|
||||||
|
#
|
||||||
|
# reply = SeadocCommentReply.objects.filter(
|
||||||
|
# id=reply_id, doc_uuid=file_uuid, comment_id=comment_id).first()
|
||||||
|
# if not reply:
|
||||||
|
# return api_error(status.HTTP_404_NOT_FOUND, 'reply not found.')
|
||||||
|
#
|
||||||
|
# data = reply.to_dict()
|
||||||
|
# data.update(
|
||||||
|
# user_to_dict(reply.author, request=request))
|
||||||
|
# return Response(data)
|
||||||
|
#
|
||||||
|
# def delete(self, request, repo_id, file_uuid, comment_id, reply_id):
|
||||||
|
# """Delete a comment reply
|
||||||
|
# """
|
||||||
|
# # auth = request.headers.get('authorization', '').split()
|
||||||
|
# # if not is_valid_seadoc_access_token(auth, file_uuid):
|
||||||
|
# # error_msg = 'Permission denied.'
|
||||||
|
# # return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
#
|
||||||
|
# # resource check
|
||||||
|
# file_comment = FileComment.objects.filter(
|
||||||
|
# id=comment_id, uuid=file_uuid).first()
|
||||||
|
# if not file_comment:
|
||||||
|
# return api_error(status.HTTP_404_NOT_FOUND, 'comment not found.')
|
||||||
|
#
|
||||||
|
# reply = SeadocCommentReply.objects.filter(
|
||||||
|
# id=reply_id, doc_uuid=file_uuid, comment_id=comment_id).first()
|
||||||
|
# if not reply:
|
||||||
|
# return api_error(status.HTTP_404_NOT_FOUND, 'reply not found.')
|
||||||
|
# reply.delete()
|
||||||
|
# return Response({'success': True})
|
||||||
|
#
|
||||||
|
# def put(self, request, repo_id, file_uuid, comment_id, reply_id):
|
||||||
|
# """Update a comment reply
|
||||||
|
# """
|
||||||
|
# # auth = request.headers.get('authorization', '').split()
|
||||||
|
# # if not is_valid_seadoc_access_token(auth, file_uuid):
|
||||||
|
# # error_msg = 'Permission denied.'
|
||||||
|
# # return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
#
|
||||||
|
# # argument check
|
||||||
|
# reply_content = request.data.get('reply')
|
||||||
|
# if reply_content is None:
|
||||||
|
# return api_error(status.HTTP_400_BAD_REQUEST, 'reply invalid.')
|
||||||
|
#
|
||||||
|
# # resource check
|
||||||
|
# file_comment = FileComment.objects.filter(
|
||||||
|
# id=comment_id, uuid=file_uuid).first()
|
||||||
|
# if not file_comment:
|
||||||
|
# return api_error(status.HTTP_404_NOT_FOUND, 'comment not found.')
|
||||||
|
#
|
||||||
|
# reply = SeadocCommentReply.objects.filter(
|
||||||
|
# id=reply_id, doc_uuid=file_uuid, comment_id=comment_id).first()
|
||||||
|
# if not reply:
|
||||||
|
# return api_error(status.HTTP_404_NOT_FOUND, 'reply not found.')
|
||||||
|
#
|
||||||
|
# # save
|
||||||
|
# reply.reply = str(reply_content)
|
||||||
|
# reply.updated_at = timezone.now()
|
||||||
|
# reply.save()
|
||||||
|
#
|
||||||
|
# data = reply.to_dict()
|
||||||
|
# data.update(
|
||||||
|
# user_to_dict(reply.author, request=request))
|
||||||
|
# return Response(data)
|
||||||
|
|
||||||
|
|
||||||
class FileCommentsView(APIView):
|
class FileCommentsView(APIView):
|
||||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||||
permission_classes = (IsAuthenticated, IsRepoAccessible)
|
permission_classes = (IsAuthenticated, IsRepoAccessible)
|
||||||
throttle_classes = (UserRateThrottle, )
|
throttle_classes = (UserRateThrottle,)
|
||||||
|
|
||||||
def get(self, request, repo_id, format=None):
|
def get(self, request, repo_id, file_uuid):
|
||||||
"""List all comments of a file.
|
"""list comments of a sdoc, same as FileCommentsView
|
||||||
"""
|
"""
|
||||||
path = request.GET.get('p', '/').rstrip('/')
|
|
||||||
if not path:
|
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, 'Wrong path.')
|
|
||||||
|
|
||||||
file_uuid = request.GET.get('docuuid', None)
|
|
||||||
resolved = request.GET.get('resolved', None)
|
resolved = request.GET.get('resolved', None)
|
||||||
if resolved not in ('true', 'false', None):
|
if resolved not in ('true', 'false', None):
|
||||||
error_msg = 'resolved invalid.'
|
error_msg = 'resolved invalid.'
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
if check_folder_permission(request, repo_id, '/') is None:
|
start = None
|
||||||
return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.')
|
end = None
|
||||||
|
page = request.GET.get('page', '')
|
||||||
|
if page:
|
||||||
|
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
|
||||||
|
|
||||||
try:
|
total_count = FileComment.objects.list_by_file_uuid(file_uuid).count()
|
||||||
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 = []
|
comments = []
|
||||||
|
|
||||||
if resolved is None:
|
if resolved is None:
|
||||||
file_comments = FileComment.objects.get_by_file_path(repo_id, path)[start: end]
|
file_comments = FileComment.objects.list_by_file_uuid(file_uuid)[start: end]
|
||||||
else:
|
else:
|
||||||
comment_resolved = to_python_boolean(resolved)
|
comment_resolved = to_python_boolean(resolved)
|
||||||
file_comments = FileComment.objects.get_by_file_path(repo_id, path).filter(resolved=comment_resolved)[start: end]
|
file_comments = (
|
||||||
|
FileComment.objects
|
||||||
|
.list_by_file_uuid(file_uuid)
|
||||||
|
.filter(resolved=comment_resolved)
|
||||||
|
[start:end]
|
||||||
|
)
|
||||||
|
|
||||||
reply_queryset = SeadocCommentReply.objects.list_by_doc_uuid(file_uuid)
|
reply_queryset = SeadocCommentReply.objects.list_by_doc_uuid(file_uuid)
|
||||||
|
|
||||||
@@ -77,67 +379,141 @@ class FileCommentsView(APIView):
|
|||||||
comments.append(comment)
|
comments.append(comment)
|
||||||
|
|
||||||
result = {'comments': comments, 'total_count': total_count}
|
result = {'comments': comments, 'total_count': total_count}
|
||||||
resp = Response(result)
|
return 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):
|
def post(self, request, repo_id, file_uuid):
|
||||||
"""Post a comments of a file.
|
|
||||||
"""
|
|
||||||
path = request.GET.get('p', '/').rstrip('/')
|
|
||||||
if not path:
|
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, 'Wrong path.')
|
|
||||||
|
|
||||||
comment = request.data.get('comment', '')
|
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
|
|
||||||
|
|
||||||
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.')
|
|
||||||
|
|
||||||
if check_folder_permission(request, repo_id, '/') is None:
|
|
||||||
return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.')
|
|
||||||
|
|
||||||
detail = request.data.get('detail', '')
|
detail = request.data.get('detail', '')
|
||||||
|
author = request.data.get('author', '')
|
||||||
username = request.user.username
|
username = request.user.username
|
||||||
file_comment = FileComment.objects.add_by_file_path(
|
if comment is None:
|
||||||
repo_id=repo_id, file_path=path, author=username, comment=comment, detail=detail)
|
return api_error(status.HTTP_400_BAD_REQUEST, 'comment invalid.')
|
||||||
repo = seafile_api.get_repo(repo_id)
|
if not username:
|
||||||
repo_owner = get_repo_owner(request, repo.id)
|
return api_error(status.HTTP_400_BAD_REQUEST, 'author invalid.')
|
||||||
|
|
||||||
comment_file_successful.send(sender=None, repo=repo, repo_owner=repo_owner, file_path=path, comment=comment, author=username)
|
|
||||||
|
|
||||||
|
file_comment = FileComment.objects.add_by_file_uuid(
|
||||||
|
file_uuid, username, comment, detail)
|
||||||
comment = file_comment.to_dict()
|
comment = file_comment.to_dict()
|
||||||
comment.update(user_to_dict(username, request=request))
|
comment.update(user_to_dict(username, request=request))
|
||||||
return Response(comment, status=201)
|
|
||||||
|
# notification
|
||||||
|
to_users = set()
|
||||||
|
participant_queryset = FileParticipant.objects.get_participants(file_uuid)
|
||||||
|
for participant in participant_queryset:
|
||||||
|
to_users.add(participant.username)
|
||||||
|
to_users.discard(username) # remove author
|
||||||
|
to_users = list(to_users)
|
||||||
|
detail = {
|
||||||
|
'author': username,
|
||||||
|
'comment_id': int(file_comment.id),
|
||||||
|
'comment': str(file_comment.comment),
|
||||||
|
'msg_type': 'comment',
|
||||||
|
'created_at': datetime_to_isoformat_timestr(file_comment.created_at),
|
||||||
|
'updated_at': datetime_to_isoformat_timestr(file_comment.updated_at),
|
||||||
|
}
|
||||||
|
detail.update(user_to_dict(username, request=request))
|
||||||
|
|
||||||
|
new_notifications = []
|
||||||
|
for to_user in to_users:
|
||||||
|
new_notifications.append(
|
||||||
|
SeadocNotification(
|
||||||
|
doc_uuid=file_uuid,
|
||||||
|
username=to_user,
|
||||||
|
msg_type='comment',
|
||||||
|
detail=json.dumps(detail),
|
||||||
|
))
|
||||||
|
try:
|
||||||
|
SeadocNotification.objects.bulk_create(new_notifications)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
error_msg = 'Internal Server Error'
|
||||||
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
#
|
||||||
|
notification = detail
|
||||||
|
notification['to_users'] = to_users
|
||||||
|
comment['notification'] = notification
|
||||||
|
return Response(comment)
|
||||||
|
|
||||||
|
|
||||||
class FileCommentRepliesView(APIView):
|
class FileCommentView(APIView):
|
||||||
authentication_classes = ()
|
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||||
|
permission_classes = (IsAuthenticated, IsRepoAccessible)
|
||||||
throttle_classes = (UserRateThrottle,)
|
throttle_classes = (UserRateThrottle,)
|
||||||
|
|
||||||
def get(self, request, repo_id, file_uuid, comment_id):
|
def get(self, request, repo_id, file_uuid, comment_id):
|
||||||
"""list replies
|
# resource check
|
||||||
"""
|
try:
|
||||||
# auth = request.headers.get('authorization', '').split()
|
file_comment = FileComment.objects.get(pk=comment_id)
|
||||||
# if not is_valid_seadoc_access_token(auth, file_uuid):
|
except FileComment.DoesNotExist:
|
||||||
# error_msg = 'Permission denied.'
|
return api_error(status.HTTP_400_BAD_REQUEST, 'Wrong comment id')
|
||||||
# return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
if str(file_comment.uuid.uuid) != file_uuid:
|
||||||
|
return api_error(status.HTTP_404_NOT_FOUND, 'comment not found: %s' % comment_id)
|
||||||
|
|
||||||
|
comment = file_comment.to_dict()
|
||||||
|
comment.update(user_to_dict(
|
||||||
|
file_comment.author, request=request))
|
||||||
|
return Response(comment)
|
||||||
|
|
||||||
|
def delete(self, request, file_uuid, comment_id):
|
||||||
|
|
||||||
|
# resource check
|
||||||
|
try:
|
||||||
|
file_comment = FileComment.objects.get(pk=comment_id)
|
||||||
|
except FileComment.DoesNotExist:
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, 'Wrong comment id')
|
||||||
|
if str(file_comment.uuid.uuid) != file_uuid:
|
||||||
|
return api_error(status.HTTP_404_NOT_FOUND, 'comment not found: %s' % comment_id)
|
||||||
|
|
||||||
|
file_comment.delete()
|
||||||
|
SeadocCommentReply.objects.filter(comment_id=comment_id).delete()
|
||||||
|
return Response({'success': True})
|
||||||
|
|
||||||
|
def put(self, request, repo_id, file_uuid, comment_id):
|
||||||
|
|
||||||
|
# argument check
|
||||||
|
resolved = request.data.get('resolved')
|
||||||
|
if resolved not in ('true', 'false', None):
|
||||||
|
error_msg = 'resolved invalid.'
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
detail = request.data.get('detail')
|
||||||
|
comment = request.data.get('comment')
|
||||||
|
|
||||||
|
# resource check
|
||||||
|
try:
|
||||||
|
file_comment = FileComment.objects.get(pk=comment_id)
|
||||||
|
except FileComment.DoesNotExist:
|
||||||
|
error_msg = 'FileComment %s not found.' % comment_id
|
||||||
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
if str(file_comment.uuid.uuid) != file_uuid:
|
||||||
|
return api_error(status.HTTP_404_NOT_FOUND, 'comment not found: %s' % comment_id)
|
||||||
|
|
||||||
|
if resolved is not None:
|
||||||
|
# do not refresh updated_at
|
||||||
|
comment_resolved = to_python_boolean(resolved)
|
||||||
|
file_comment.resolved = comment_resolved
|
||||||
|
file_comment.save(update_fields=['resolved'])
|
||||||
|
|
||||||
|
if detail is not None or comment is not None:
|
||||||
|
if detail is not None:
|
||||||
|
file_comment.detail = detail
|
||||||
|
if comment is not None:
|
||||||
|
file_comment.comment = comment
|
||||||
|
# save
|
||||||
|
file_comment.updated_at = timezone.now()
|
||||||
|
file_comment.save()
|
||||||
|
|
||||||
|
comment = file_comment.to_dict()
|
||||||
|
comment.update(user_to_dict(file_comment.author, request=request))
|
||||||
|
return Response(comment)
|
||||||
|
|
||||||
|
|
||||||
|
class FileCommentRepliesView(APIView):
|
||||||
|
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||||
|
permission_classes = (IsAuthenticated, IsRepoAccessible)
|
||||||
|
throttle_classes = (UserRateThrottle,)
|
||||||
|
|
||||||
|
def get(self, request, repo_id, file_uuid, comment_id):
|
||||||
start = None
|
start = None
|
||||||
end = None
|
end = None
|
||||||
page = request.GET.get('page', '')
|
page = request.GET.get('page', '')
|
||||||
@@ -170,20 +546,13 @@ class FileCommentRepliesView(APIView):
|
|||||||
return Response(result)
|
return Response(result)
|
||||||
|
|
||||||
def post(self, request, repo_id, file_uuid, comment_id):
|
def post(self, request, repo_id, file_uuid, comment_id):
|
||||||
"""post a reply
|
"""post a comment reply of a sdoc.
|
||||||
"""
|
"""
|
||||||
# argument check
|
|
||||||
# auth = request.headers.get('authorization', '').split()
|
|
||||||
# is_valid, payload = is_valid_seadoc_access_token(auth, file_uuid, return_payload=True)
|
|
||||||
# if not is_valid:
|
|
||||||
# error_msg = 'Permission denied.'
|
|
||||||
# return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
|
||||||
|
|
||||||
reply_content = request.data.get('reply', '')
|
reply_content = request.data.get('reply', '')
|
||||||
type_content = request.data.get('type', 'reply')
|
type_content = request.data.get('type', 'reply')
|
||||||
author = request.data.get('author', '')
|
author = request.data.get('author', '')
|
||||||
username = author
|
username = request.user.username or author
|
||||||
|
|
||||||
if reply_content is None:
|
if reply_content is None:
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, 'reply invalid.')
|
return api_error(status.HTTP_400_BAD_REQUEST, 'reply invalid.')
|
||||||
if not username:
|
if not username:
|
||||||
@@ -203,7 +572,8 @@ class FileCommentRepliesView(APIView):
|
|||||||
doc_uuid=file_uuid,
|
doc_uuid=file_uuid,
|
||||||
)
|
)
|
||||||
data = reply.to_dict()
|
data = reply.to_dict()
|
||||||
data.update(user_to_dict(reply.author, request=request))
|
data.update(
|
||||||
|
user_to_dict(reply.author, request=request))
|
||||||
|
|
||||||
# notification
|
# notification
|
||||||
to_users = set()
|
to_users = set()
|
||||||
@@ -225,22 +595,22 @@ class FileCommentRepliesView(APIView):
|
|||||||
}
|
}
|
||||||
detail.update(user_to_dict(username, request=request))
|
detail.update(user_to_dict(username, request=request))
|
||||||
|
|
||||||
# new_notifications = []
|
new_notifications = []
|
||||||
# for to_user in to_users:
|
for to_user in to_users:
|
||||||
# new_notifications.append(
|
new_notifications.append(
|
||||||
# SeadocNotification(
|
SeadocNotification(
|
||||||
# doc_uuid=file_uuid,
|
doc_uuid=file_uuid,
|
||||||
# username=to_user,
|
username=to_user,
|
||||||
# msg_type='reply',
|
msg_type='reply',
|
||||||
# detail=json.dumps(detail),
|
detail=json.dumps(detail),
|
||||||
# ))
|
))
|
||||||
# try:
|
try:
|
||||||
# SeadocNotification.objects.bulk_create(new_notifications)
|
SeadocNotification.objects.bulk_create(new_notifications)
|
||||||
# except Exception as e:
|
except Exception as e:
|
||||||
# logger.error(e)
|
logger.error(e)
|
||||||
# error_msg = 'Internal Server Error'
|
error_msg = 'Internal Server Error'
|
||||||
# return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
#
|
||||||
notification = detail
|
notification = detail
|
||||||
notification['to_users'] = to_users
|
notification['to_users'] = to_users
|
||||||
data['notification'] = notification
|
data['notification'] = notification
|
||||||
@@ -248,17 +618,13 @@ class FileCommentRepliesView(APIView):
|
|||||||
|
|
||||||
|
|
||||||
class FileCommentReplyView(APIView):
|
class FileCommentReplyView(APIView):
|
||||||
authentication_classes = ()
|
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||||
|
permission_classes = (IsAuthenticated, IsRepoAccessible)
|
||||||
throttle_classes = (UserRateThrottle,)
|
throttle_classes = (UserRateThrottle,)
|
||||||
|
|
||||||
def get(self, request, repo_id, file_uuid, comment_id, reply_id):
|
def get(self, request, repo_id, file_uuid, comment_id, reply_id):
|
||||||
"""Get a comment reply
|
"""Get a comment reply
|
||||||
"""
|
"""
|
||||||
# auth = request.headers.get('authorization', '').split()
|
|
||||||
# if not is_valid_seadoc_access_token(auth, file_uuid):
|
|
||||||
# error_msg = 'Permission denied.'
|
|
||||||
# return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
|
||||||
|
|
||||||
# resource check
|
# resource check
|
||||||
file_comment = FileComment.objects.filter(
|
file_comment = FileComment.objects.filter(
|
||||||
id=comment_id, uuid=file_uuid).first()
|
id=comment_id, uuid=file_uuid).first()
|
||||||
@@ -276,12 +642,6 @@ class FileCommentReplyView(APIView):
|
|||||||
return Response(data)
|
return Response(data)
|
||||||
|
|
||||||
def delete(self, request, repo_id, file_uuid, comment_id, reply_id):
|
def delete(self, request, repo_id, file_uuid, comment_id, reply_id):
|
||||||
"""Delete a comment reply
|
|
||||||
"""
|
|
||||||
# auth = request.headers.get('authorization', '').split()
|
|
||||||
# if not is_valid_seadoc_access_token(auth, file_uuid):
|
|
||||||
# error_msg = 'Permission denied.'
|
|
||||||
# return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
|
||||||
|
|
||||||
# resource check
|
# resource check
|
||||||
file_comment = FileComment.objects.filter(
|
file_comment = FileComment.objects.filter(
|
||||||
@@ -297,13 +657,6 @@ class FileCommentReplyView(APIView):
|
|||||||
return Response({'success': True})
|
return Response({'success': True})
|
||||||
|
|
||||||
def put(self, request, repo_id, file_uuid, comment_id, reply_id):
|
def put(self, request, repo_id, file_uuid, comment_id, reply_id):
|
||||||
"""Update a comment reply
|
|
||||||
"""
|
|
||||||
# auth = request.headers.get('authorization', '').split()
|
|
||||||
# if not is_valid_seadoc_access_token(auth, file_uuid):
|
|
||||||
# error_msg = 'Permission denied.'
|
|
||||||
# return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
|
||||||
|
|
||||||
# argument check
|
# argument check
|
||||||
reply_content = request.data.get('reply')
|
reply_content = request.data.get('reply')
|
||||||
if reply_content is None:
|
if reply_content is None:
|
||||||
|
@@ -57,11 +57,11 @@ urlpatterns = [
|
|||||||
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/$', FileView.as_view(), name='FileView'),
|
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/$', FileView.as_view(), name='FileView'),
|
||||||
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/metadata/$', FileMetaDataView.as_view(), name='FileMetaDataView'),
|
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/metadata/$', FileMetaDataView.as_view(), name='FileMetaDataView'),
|
||||||
re_path(r'^repos/(?P<repo_id>[-0-9a-f]{36})/files/(?P<file_id>[0-9a-f]{40})/blks/(?P<block_id>[0-9a-f]{40})/download-link/$', FileBlockDownloadLinkView.as_view()),
|
re_path(r'^repos/(?P<repo_id>[-0-9a-f]{36})/files/(?P<file_id>[0-9a-f]{40})/blks/(?P<block_id>[0-9a-f]{40})/download-link/$', FileBlockDownloadLinkView.as_view()),
|
||||||
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/comments/$', FileCommentsView.as_view(), name='api2-file-comments'),
|
# re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/comments/$', 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/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/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/comments/(?P<file_uuid>[-0-9a-f]{36})/(?P<comment_id>\d+)/replies/$', FileCommentRepliesView.as_view(), name='file_comment_replies'),
|
# re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/comments/(?P<file_uuid>[-0-9a-f]{36})/(?P<comment_id>\d+)/replies/$', FileCommentRepliesView.as_view(), name='file_comment_replies'),
|
||||||
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/comments/(?P<file_uuid>[-0-9a-f]{36})/(?P<comment_id>\d+)/replies/(?P<reply_id>\d+)/$', FileCommentReplyView.as_view(), name='file_comment_reply'),
|
# re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/comments/(?P<file_uuid>[-0-9a-f]{36})/(?P<comment_id>\d+)/replies/(?P<reply_id>\d+)/$', FileCommentReplyView.as_view(), name='file_comment_reply'),
|
||||||
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/detail/$', FileDetailView.as_view()),
|
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/detail/$', FileDetailView.as_view()),
|
||||||
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/history/$', FileHistory.as_view()),
|
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/history/$', FileHistory.as_view()),
|
||||||
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/revision/$', FileRevision.as_view()),
|
re_path(r'^repos/(?P<repo_id>[-0-9-a-f]{36})/file/revision/$', FileRevision.as_view()),
|
||||||
|
@@ -3,6 +3,8 @@ from django.urls import include, path, re_path
|
|||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
from seahub.ai.apis import ImageCaption, GenerateSummary, GenerateFileTags, OCR, Translate, WritingAssistant
|
from seahub.ai.apis import ImageCaption, GenerateSummary, GenerateFileTags, OCR, Translate, WritingAssistant
|
||||||
|
from seahub.api2.endpoints.file_comments import FileCommentsView, FileCommentView, FileCommentRepliesView, \
|
||||||
|
FileCommentReplyView
|
||||||
from seahub.api2.endpoints.share_link_auth import ShareLinkUserAuthView, ShareLinkEmailAuthView
|
from seahub.api2.endpoints.share_link_auth import ShareLinkUserAuthView, ShareLinkEmailAuthView
|
||||||
from seahub.api2.endpoints.internal_api import InternalUserListView, InternalCheckShareLinkAccess, \
|
from seahub.api2.endpoints.internal_api import InternalUserListView, InternalCheckShareLinkAccess, \
|
||||||
InternalCheckFileOperationAccess, CheckThumbnailAccess, CheckShareLinkThumbnailAccess
|
InternalCheckFileOperationAccess, CheckThumbnailAccess, CheckShareLinkThumbnailAccess
|
||||||
@@ -478,6 +480,14 @@ urlpatterns = [
|
|||||||
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/image-rotate/$', RepoImageRotateView.as_view(), name='api-v2.1-repo-image-rotate-view'),
|
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/image-rotate/$', RepoImageRotateView.as_view(), name='api-v2.1-repo-image-rotate-view'),
|
||||||
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/office-suite/$', OfficeSuiteConfig.as_view(), name='api-v2.1-repo-office-suite'),
|
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/office-suite/$', OfficeSuiteConfig.as_view(), name='api-v2.1-repo-office-suite'),
|
||||||
|
|
||||||
|
|
||||||
|
## user: repo file comments
|
||||||
|
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/file/(?P<file_uuid>[-0-9a-f]{36})/comments/$', FileCommentsView.as_view(), name='api-v2.1-file-comments'),
|
||||||
|
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/file/(?P<file_uuid>[-0-9a-f]{36})/comments/(?P<comment_id>\d+)/$', FileCommentView.as_view(), name='api-v2.1-file-comment'),
|
||||||
|
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/file/(?P<file_uuid>[-0-9a-f]{36})/comments/(?P<comment_id>\d+)/replies/$', FileCommentRepliesView.as_view(), name='api-v2.1-file-comment-replies'),
|
||||||
|
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/file/(?P<file_uuid>[-0-9a-f]{36})/comments/(?P<comment_id>\d+)/replies/(?P<reply_id>\d+)/$', FileCommentReplyView.as_view(), name='api-v2.1-file-comment-repolies'),
|
||||||
|
|
||||||
|
|
||||||
## user:: repo-api-tokens
|
## user:: repo-api-tokens
|
||||||
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/repo-api-tokens/$', RepoAPITokensView.as_view(), name='api-v2.1-repo-api-tokens'),
|
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/repo-api-tokens/$', RepoAPITokensView.as_view(), name='api-v2.1-repo-api-tokens'),
|
||||||
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/repo-api-tokens/(?P<app_name>.*)/$', RepoAPITokenView.as_view(), name='api-v2.1-repo-api-token'),
|
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/repo-api-tokens/(?P<app_name>.*)/$', RepoAPITokenView.as_view(), name='api-v2.1-repo-api-token'),
|
||||||
|
Reference in New Issue
Block a user