mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-01 23:20:51 +00:00
SeadocRevisions
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import os
|
||||
import json
|
||||
import uuid
|
||||
import logging
|
||||
import requests
|
||||
import posixpath
|
||||
@@ -32,12 +33,13 @@ from seahub.tags.models import FileUUIDMap
|
||||
from seahub.utils.error_msg import file_type_error_msg
|
||||
from seahub.utils.repo import parse_repo_perm
|
||||
from seahub.utils.file_revisions import get_file_revisions_within_limit
|
||||
from seahub.seadoc.models import SeadocHistoryName, SeadocDraft
|
||||
from seahub.seadoc.models import SeadocHistoryName, SeadocDraft, SeadocRevision
|
||||
from seahub.avatar.templatetags.avatar_tags import api_avatar_url
|
||||
from seahub.base.templatetags.seahub_tags import email2nickname, \
|
||||
email2contact_email
|
||||
from seahub.utils.timeutils import utc_datetime_to_isoformat_timestr, timestamp_to_isoformat_timestr
|
||||
from seahub.base.models import FileComment
|
||||
from seahub.constants import PERMISSION_READ_WRITE
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -810,3 +812,189 @@ class SeadocCommentView(APIView):
|
||||
comment = file_comment.to_dict()
|
||||
comment.update(user_to_dict(file_comment.author, request=request, avatar_size=avatar_size))
|
||||
return Response(comment)
|
||||
|
||||
|
||||
class SeadocRevisions(APIView):
|
||||
|
||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||
permission_classes = (IsAuthenticated,)
|
||||
throttle_classes = (UserRateThrottle, )
|
||||
|
||||
def get(self, request):
|
||||
"""list
|
||||
"""
|
||||
username = request.user.username
|
||||
# argument check
|
||||
owned = request.GET.get('owned')
|
||||
repo_id = request.GET.get('repo_id')
|
||||
if not repo_id or not owned:
|
||||
error_msg = 'repo_id or owned invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
if repo_id:
|
||||
# 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)
|
||||
# permission check
|
||||
permission = check_folder_permission(request, repo_id, '/')
|
||||
if not permission:
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
revision_queryset = SeadocRevision.objects.list_by_repo_id(repo_id)
|
||||
#
|
||||
elif owned:
|
||||
revision_queryset = SeadocRevision.objects.list_by_username(username)
|
||||
|
||||
revisions = [revision.to_dict() for revision in revision_queryset]
|
||||
|
||||
return Response({'revisions': revisions})
|
||||
|
||||
def post(self, request):
|
||||
"""create
|
||||
"""
|
||||
username = request.user.username
|
||||
# argument check
|
||||
path = request.data.get('p', None)
|
||||
if not path:
|
||||
error_msg = 'p invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
repo_id = request.GET.get('repo_id')
|
||||
if not repo_id:
|
||||
error_msg = 'repo_id invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
path = normalize_file_path(path)
|
||||
parent_dir = os.path.dirname(path)
|
||||
filename = os.path.basename(path)
|
||||
|
||||
filetype, fileext = get_file_type_and_ext(filename)
|
||||
if filetype != SEADOC:
|
||||
error_msg = 'seadoc file type %s invalid.' % filetype
|
||||
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)
|
||||
|
||||
# permission check
|
||||
permission = check_folder_permission(request, repo_id, '/')
|
||||
if not permission:
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
# create revision dir if does not exist
|
||||
revision_dir_id = seafile_api.get_dir_id_by_path(repo_id, '/Revisions')
|
||||
if revision_dir_id is None:
|
||||
seafile_api.post_dir(repo_id, '/', 'Revisions', username)
|
||||
|
||||
#
|
||||
origin_file_uuid = get_seadoc_file_uuid(repo, path)
|
||||
origin_file_id = seafile_api.get_file_id_by_path(repo_id, path)
|
||||
revision_file_uuid = str(uuid.uuid4())
|
||||
revision_filename = revision_file_uuid + '.sdoc'
|
||||
|
||||
# copy file to revision dir
|
||||
seafile_api.copy_file(
|
||||
repo_id, parent_dir,
|
||||
json.dumps([filename]),
|
||||
repo_id, '/Revisions',
|
||||
json.dumps([revision_filename]),
|
||||
username=username, need_progress=0, synchronous=1
|
||||
)
|
||||
|
||||
revision_uuid_map = FileUUIDMap(
|
||||
uuid=revision_file_uuid,
|
||||
repo_id=repo_id,
|
||||
parent_path=parent_dir,
|
||||
filename=revision_filename,
|
||||
)
|
||||
revision_uuid_map.save()
|
||||
|
||||
revision = SeadocRevision.objects.create(
|
||||
doc_uuid=revision_file_uuid,
|
||||
origin_doc_uuid=origin_file_uuid,
|
||||
repo_id=repo_id,
|
||||
origin_file_path=path,
|
||||
username=username,
|
||||
origin_file_version=origin_file_id,
|
||||
)
|
||||
|
||||
return Response(revision.to_dict())
|
||||
|
||||
|
||||
class SeadocPublishRevision(APIView):
|
||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||
permission_classes = (IsAuthenticated, )
|
||||
throttle_classes = (UserRateThrottle, )
|
||||
|
||||
def post(self, request, file_uuid):
|
||||
"""publish
|
||||
"""
|
||||
force = request.data.get('force') # used when origin file deleted
|
||||
|
||||
# resource check
|
||||
revision = SeadocRevision.objects.get_by_doc_uuid(file_uuid)
|
||||
if not revision:
|
||||
error_msg = 'Revision %s not found.' % file_uuid
|
||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||
|
||||
repo_id = revision.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
|
||||
permission = check_folder_permission(request, repo_id, '/')
|
||||
if not permission:
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
if permission != PERMISSION_READ_WRITE:
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
# get origin file info
|
||||
origin_file_uuid = FileUUIDMap.objects.get_fileuuidmap_by_uuid(
|
||||
revision.origin_doc_uuid)
|
||||
|
||||
if not origin_file_uuid and not force:
|
||||
error_msg = 'origin sdoc %s not found.' % file_uuid
|
||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||
|
||||
if origin_file_uuid:
|
||||
origin_file_parent_path = origin_file_uuid.parent_path
|
||||
origin_file_filename = origin_file_uuid.filename
|
||||
else:
|
||||
origin_file_parent_path = os.path.dirname(revision.origin_doc_path)
|
||||
origin_file_filename = os.path.basename(revision.origin_doc_path)
|
||||
|
||||
# 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 revision file info
|
||||
revision_file_uuid = FileUUIDMap.objects.get_fileuuidmap_by_uuid(file_uuid)
|
||||
revision_parent_path = revision_file_uuid.parent_pat
|
||||
revision_filename = revision_file_uuid.filename
|
||||
|
||||
# move revision file
|
||||
username = request.user.username
|
||||
seafile_api.move_file(repo_id, revision_parent_path,
|
||||
json.dumps([revision_filename]),
|
||||
repo_id, dst_parent_path,
|
||||
json.dumps([origin_file_filename]),
|
||||
replace=1, username=username,
|
||||
need_progress=0, synchronous=1)
|
||||
|
||||
dst_file_id = seafile_api.get_file_id_by_path(repo_id, origin_file_filename)
|
||||
revision = SeadocRevision.objects.publish(
|
||||
file_uuid, username, dst_file_id)
|
||||
return Response(revision.to_dict())
|
||||
|
@@ -1,6 +1,9 @@
|
||||
import os
|
||||
|
||||
from django.db import models
|
||||
|
||||
from seahub.utils.timeutils import datetime_to_isoformat_timestr
|
||||
from seahub.base.templatetags.seahub_tags import email2nickname
|
||||
|
||||
|
||||
class SeadocHistoryNameManager(models.Manager):
|
||||
@@ -28,7 +31,6 @@ class SeadocHistoryName(models.Model):
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': self.pk,
|
||||
'doc_uuid': self.doc_uuid,
|
||||
'obj_id': self.obj_id,
|
||||
'name': self.name,
|
||||
@@ -75,3 +77,75 @@ class SeadocDraft(models.Model):
|
||||
'username': self.username,
|
||||
'created_at': datetime_to_isoformat_timestr(self.created_at),
|
||||
}
|
||||
|
||||
class SeadocRevisionManager(models.Manager):
|
||||
|
||||
def get_by_doc_uuid(self, doc_uuid):
|
||||
return self.filter(doc_uuid=doc_uuid).first()
|
||||
|
||||
def list_by_doc_uuids(self, doc_uuid_list):
|
||||
return self.filter(doc_uuid__in=doc_uuid_list)
|
||||
|
||||
def list_by_origin_doc_uuid(self, origin_doc_uuid):
|
||||
return self.filter(origin_doc_uuid=origin_doc_uuid)
|
||||
|
||||
def list_by_username(self, username):
|
||||
return self.filter(username=username)
|
||||
|
||||
def list_by_repo_id(self, repo_id):
|
||||
return self.filter(repo_id=repo_id)
|
||||
|
||||
def publish(self, doc_uuid, publisher, publish_file_version):
|
||||
return self.filter(doc_uuid=doc_uuid).update(
|
||||
publisher=publisher,
|
||||
publish_file_version=publish_file_version,
|
||||
is_published=True,
|
||||
)
|
||||
|
||||
|
||||
class SeadocRevision(models.Model):
|
||||
"""
|
||||
"""
|
||||
doc_uuid = models.CharField(max_length=36, unique=True)
|
||||
origin_doc_uuid = models.CharField(max_length=36, db_index=True)
|
||||
repo_id = models.CharField(max_length=36, db_index=True)
|
||||
origin_doc_path = models.TextField() # used when origin file deleted
|
||||
username = models.CharField(max_length=255, db_index=True)
|
||||
origin_file_version = models.CharField(max_length=100)
|
||||
publish_file_version = models.CharField(max_length=100, null=True)
|
||||
publisher = models.CharField(max_length=255, null=True)
|
||||
is_published = models.BooleanField(default=False)
|
||||
created_at = models.DateTimeField(auto_now_add=True, db_index=True)
|
||||
updated_at = models.DateTimeField(auto_now=True, db_index=True)
|
||||
|
||||
objects = SeadocRevisionManager()
|
||||
|
||||
class Meta:
|
||||
db_table = 'sdoc_revision'
|
||||
|
||||
def to_dict(self):
|
||||
from seahub.tags.models import FileUUIDMap
|
||||
file_uuid = FileUUIDMap.objects.get_fileuuidmap_by_uuid(self.origin_doc_uuid)
|
||||
if file_uuid:
|
||||
origin_parent_path = file_uuid.parent_path
|
||||
origin_filename = file_uuid.filename
|
||||
else:
|
||||
origin_parent_path = os.path.dirname(self.origin_doc_path)
|
||||
origin_filename = os.path.basename(self.origin_doc_path)
|
||||
|
||||
return {
|
||||
'username': self.username,
|
||||
'nickname': email2nickname(self.username),
|
||||
'repo_id': self.repo_id,
|
||||
'doc_uuid': self.doc_uuid,
|
||||
'origin_doc_uuid': self.origin_doc_uuid,
|
||||
'origin_parent_path': origin_parent_path,
|
||||
'origin_filename': origin_filename,
|
||||
'origin_file_version': self.origin_file_version,
|
||||
'publish_file_version': self.publish_file_version,
|
||||
'publisher': self.publisher,
|
||||
'publisher_nickname': email2nickname(self.publisher),
|
||||
'is_published': self.is_published,
|
||||
'created_at': datetime_to_isoformat_timestr(self.created_at),
|
||||
'updated_at': datetime_to_isoformat_timestr(self.updated_at),
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
from django.urls import re_path
|
||||
from .apis import SeadocAccessToken, SeadocUploadLink, SeadocDownloadLink, SeadocUploadFile, \
|
||||
SeadocUploadImage, SeadocDownloadImage, SeadocCopyHistoryFile, SeadocHistory, SeadocDrafts, SeadocMaskAsDraft, \
|
||||
SeadocCommentsView, SeadocCommentView
|
||||
SeadocCommentsView, SeadocCommentView, SeadocRevisions, SeadocPublishRevision
|
||||
|
||||
urlpatterns = [
|
||||
re_path(r'^access-token/(?P<repo_id>[-0-9a-f]{36})/$', SeadocAccessToken.as_view(), name='seadoc_access_token'),
|
||||
@@ -16,4 +16,6 @@ urlpatterns = [
|
||||
re_path(r'^mask-as-draft/(?P<repo_id>[-0-9a-f]{36})/$', SeadocMaskAsDraft.as_view(), name='seadoc_mask_as_draft'),
|
||||
re_path(r'^comments/(?P<file_uuid>[-0-9a-f]{36})/$', SeadocCommentsView.as_view(), name='seadoc_comments'),
|
||||
re_path(r'^comment/(?P<file_uuid>[-0-9a-f]{36})/(?P<comment_id>\d+)/$', SeadocCommentView.as_view(), name='seadoc_comment'),
|
||||
re_path(r'^revisions/$', SeadocRevisions.as_view(), name='seadoc_revisions'),
|
||||
re_path(r'^publish-revision/$', SeadocPublishRevision.as_view(), name='seadoc_publish_revision'),
|
||||
]
|
||||
|
@@ -1397,3 +1397,23 @@ CREATE TABLE `sdoc_draft` (
|
||||
KEY `sdoc_draft_repo_id` (`repo_id`),
|
||||
KEY `sdoc_draft_username` (`username`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `sdoc_revision` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`repo_id` varchar(36) NOT NULL,
|
||||
`doc_uuid` varchar(36) NOT NULL,
|
||||
`origin_doc_uuid` varchar(36) NOT NULL,
|
||||
`origin_file_version` varchar(100) NOT NULL,
|
||||
`publish_file_version` varchar(100) DEFAULT NULL,
|
||||
`username` varchar(255) NOT NULL,
|
||||
`created_at` datetime NOT NULL,
|
||||
`updated_at` datetime NOT NULL,
|
||||
`is_published` tinyint(1) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `sdoc_revise_doc_uuid` (`doc_uuid`),
|
||||
KEY `sdoc_revision_repo_id` (`repo_id`),
|
||||
KEY `sdoc_revision_origin_doc_uuid` (`origin_doc_uuid`),
|
||||
KEY `sdoc_revision_username` (`username`),
|
||||
KEY `sdoc_revision_created_at` (`created_at`),
|
||||
KEY `sdoc_revision_updated_at` (`updated_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
Reference in New Issue
Block a user