mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-19 01:44:13 +00:00
@@ -199,6 +199,9 @@ class DirentGridItem extends React.Component {
|
||||
dirHref = siteRoot + 'library/' + this.props.repoID + '/' + this.props.currentRepoInfo.repo_name + Utils.encodePath(direntPath);
|
||||
}
|
||||
let fileHref = siteRoot + 'lib/' + this.props.repoID + '/file' + Utils.encodePath(direntPath);
|
||||
if (dirent.is_sdoc_revision && dirent.revision_id) {
|
||||
fileHref = siteRoot + 'lib/' + this.props.repoID + '/revisions/' + dirent.revision_id + '/';
|
||||
}
|
||||
|
||||
let gridClass = 'grid-file-img-link cursor-pointer';
|
||||
gridClass += this.state.isGridSelected ? ' grid-selected-active' : ' ';
|
||||
|
@@ -673,6 +673,9 @@ class DirentListItem extends React.Component {
|
||||
dirHref = siteRoot + 'library/' + this.props.repoID + '/' + this.props.currentRepoInfo.repo_name + Utils.encodePath(direntPath);
|
||||
}
|
||||
let fileHref = siteRoot + 'lib/' + this.props.repoID + '/file' + Utils.encodePath(direntPath);
|
||||
if (dirent.is_sdoc_revision && dirent.revision_id) {
|
||||
fileHref = siteRoot + 'lib/' + this.props.repoID + '/revisions/' + dirent.revision_id + '/';
|
||||
}
|
||||
|
||||
let toolTipID = '';
|
||||
let tagTitle = '';
|
||||
|
@@ -39,6 +39,8 @@ class Dirent {
|
||||
}
|
||||
if (Utils.isSdocFile(json.name)) {
|
||||
this.is_sdoc_draft = json.is_sdoc_draft || false;
|
||||
this.is_sdoc_revision = json.is_sdoc_revision || false;
|
||||
this.revision_id = json.revision_id || null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1264,7 +1264,10 @@ class LibContentView extends React.Component {
|
||||
if (this.state.currentMode === 'column' && Utils.isMarkdownFile(direntPath)) {
|
||||
this.showColumnMarkdownFile(direntPath);
|
||||
} else {
|
||||
const url = siteRoot + 'lib/' + repoID + '/file' + Utils.encodePath(direntPath);
|
||||
let url = siteRoot + 'lib/' + repoID + '/file' + Utils.encodePath(direntPath);
|
||||
if (dirent.is_sdoc_revision && dirent.revision_id) {
|
||||
url = siteRoot + 'lib/' + repoID + '/revisions/' + dirent.revision_id + '/';
|
||||
}
|
||||
|
||||
let isWeChat = Utils.isWeChat();
|
||||
if (!isWeChat) {
|
||||
@@ -1633,7 +1636,11 @@ class LibContentView extends React.Component {
|
||||
this.showColumnMarkdownFile(node.path);
|
||||
}
|
||||
} else {
|
||||
const url = siteRoot + 'lib/' + repoID + '/file' + Utils.encodePath(node.path);
|
||||
let url = siteRoot + 'lib/' + repoID + '/file' + Utils.encodePath(node.path);
|
||||
let dirent = node.object;
|
||||
if (dirent.is_sdoc_revision && dirent.revision_id) {
|
||||
url = siteRoot + 'lib/' + repoID + '/revisions/' + dirent.revision_id + '/';
|
||||
}
|
||||
window.open(url);
|
||||
}
|
||||
}
|
||||
|
@@ -107,12 +107,14 @@ def get_dir_file_info_list(username, request_type, repo_obj, parent_dir,
|
||||
|
||||
try:
|
||||
from seahub.tags.models import FileUUIDMap
|
||||
from seahub.seadoc.models import SeadocDraft
|
||||
from seahub.seadoc.models import SeadocDraft, SeadocRevision
|
||||
file_uuid_queryset = FileUUIDMap.objects.get_fileuuidmaps_by_parent_path(
|
||||
repo_id, parent_dir)
|
||||
file_uuid_list = [item.uuid for item in file_uuid_queryset]
|
||||
seadoc_draft_queryset = SeadocDraft.objects.list_by_doc_uuids(
|
||||
file_uuid_list)
|
||||
seadoc_revision_queryset = SeadocRevision.objects.list_by_doc_uuids(
|
||||
file_uuid_list)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
@@ -197,6 +199,13 @@ def get_dir_file_info_list(username, request_type, repo_obj, parent_dir,
|
||||
file_info['is_sdoc_draft'] = True
|
||||
else:
|
||||
file_info['is_sdoc_draft'] = False
|
||||
sdoc_revision = seadoc_revision_queryset.filter(
|
||||
doc_uuid=file_uuid_map.uuid).first()
|
||||
if sdoc_revision:
|
||||
file_info['is_sdoc_revision'] = True
|
||||
file_info['revision_id'] = sdoc_revision.revision_id
|
||||
else:
|
||||
file_info['is_sdoc_revision'] = False
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
|
@@ -15,6 +15,7 @@ from django.utils.translation import gettext as _
|
||||
from django.http import HttpResponseRedirect, HttpResponse
|
||||
from django.core.files.base import ContentFile
|
||||
from django.utils import timezone
|
||||
from django.db import transaction
|
||||
|
||||
from seaserv import seafile_api, check_quota
|
||||
|
||||
@@ -995,6 +996,25 @@ class SeadocRevisions(APIView):
|
||||
revision_file_uuid = str(uuid.uuid4())
|
||||
revision_filename = revision_file_uuid + '.sdoc'
|
||||
|
||||
with transaction.atomic():
|
||||
revision_uuid_map = FileUUIDMap(
|
||||
uuid=revision_file_uuid,
|
||||
repo_id=repo_id,
|
||||
parent_path='/Revisions',
|
||||
filename=revision_filename,
|
||||
is_dir=False,
|
||||
)
|
||||
revision_uuid_map.save()
|
||||
|
||||
revision = SeadocRevision.objects.add(
|
||||
doc_uuid=revision_file_uuid,
|
||||
origin_doc_uuid=origin_file_uuid,
|
||||
repo_id=repo_id,
|
||||
origin_doc_path=path,
|
||||
username=username,
|
||||
origin_file_version=origin_file_id,
|
||||
)
|
||||
|
||||
# copy file to revision dir
|
||||
seafile_api.copy_file(
|
||||
repo_id, parent_dir,
|
||||
@@ -1004,24 +1024,6 @@ class SeadocRevisions(APIView):
|
||||
username=username, need_progress=0, synchronous=1,
|
||||
)
|
||||
|
||||
revision_uuid_map = FileUUIDMap(
|
||||
uuid=revision_file_uuid,
|
||||
repo_id=repo_id,
|
||||
parent_path='/Revisions',
|
||||
filename=revision_filename,
|
||||
is_dir=False,
|
||||
)
|
||||
revision_uuid_map.save()
|
||||
|
||||
revision = SeadocRevision.objects.create(
|
||||
doc_uuid=revision_file_uuid,
|
||||
origin_doc_uuid=origin_file_uuid,
|
||||
repo_id=repo_id,
|
||||
origin_doc_path=path,
|
||||
username=username,
|
||||
origin_file_version=origin_file_id,
|
||||
)
|
||||
|
||||
# copy image files
|
||||
origin_image_parent_path = '/images/sdoc/' + origin_file_uuid + '/'
|
||||
dir_id = seafile_api.get_dir_id_by_path(repo_id, origin_image_parent_path)
|
||||
|
@@ -81,6 +81,25 @@ class SeadocDraft(models.Model):
|
||||
|
||||
class SeadocRevisionManager(models.Manager):
|
||||
|
||||
def add(self, doc_uuid, origin_doc_uuid, repo_id, origin_doc_path, username, origin_file_version):
|
||||
last_revision = self.filter(repo_id=repo_id).order_by('revision_id').last()
|
||||
if not last_revision:
|
||||
revision_id = 1
|
||||
else:
|
||||
revision_id = last_revision.revision_id + 1
|
||||
return self.create(
|
||||
doc_uuid=doc_uuid,
|
||||
origin_doc_uuid=origin_doc_uuid,
|
||||
repo_id=repo_id,
|
||||
revision_id=revision_id,
|
||||
origin_doc_path=origin_doc_path,
|
||||
username=username,
|
||||
origin_file_version=origin_file_version,
|
||||
)
|
||||
|
||||
def get_by_revision_id(self, repo_id, revision_id):
|
||||
return self.filter(repo_id=repo_id, revision_id=revision_id).first()
|
||||
|
||||
def get_by_doc_uuid(self, doc_uuid):
|
||||
return self.filter(doc_uuid=doc_uuid).first()
|
||||
|
||||
@@ -113,6 +132,7 @@ 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)
|
||||
revision_id = models.IntegerField() # revision_id in repo
|
||||
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)
|
||||
@@ -126,6 +146,7 @@ class SeadocRevision(models.Model):
|
||||
|
||||
class Meta:
|
||||
db_table = 'sdoc_revision'
|
||||
unique_together = ('repo_id', 'revision_id')
|
||||
|
||||
def to_dict(self, fileuuidmap_queryset=None):
|
||||
from seahub.tags.models import FileUUIDMap
|
||||
@@ -157,6 +178,7 @@ class SeadocRevision(models.Model):
|
||||
'username': self.username,
|
||||
'nickname': email2nickname(self.username),
|
||||
'repo_id': self.repo_id,
|
||||
'revision_id': self.revision_id,
|
||||
'doc_uuid': self.doc_uuid,
|
||||
'parent_path': parent_path,
|
||||
'filename': filename,
|
||||
|
@@ -178,12 +178,14 @@ def can_access_seadoc_asset(request, repo_id, path, file_uuid):
|
||||
|
||||
return False
|
||||
|
||||
def is_seadoc_revision(doc_uuid):
|
||||
def is_seadoc_revision(doc_uuid, revision=None):
|
||||
info = {}
|
||||
revision = SeadocRevision.objects.get_by_doc_uuid(doc_uuid)
|
||||
if not revision:
|
||||
revision = SeadocRevision.objects.get_by_doc_uuid(doc_uuid)
|
||||
if revision:
|
||||
info = {'is_sdoc_revision': True}
|
||||
revision_info = revision.to_dict()
|
||||
info['revision_id'] = revision_info['revision_id']
|
||||
info['origin_doc_uuid'] = revision_info['origin_doc_uuid']
|
||||
info['origin_parent_path'] = revision_info['origin_parent_path']
|
||||
info['origin_filename'] = revision_info['origin_filename']
|
||||
|
@@ -15,6 +15,7 @@ assetsUrl: '{{ assets_url }}',
|
||||
seadocAccessToken: '{{ seadoc_access_token }}',
|
||||
seadocServerUrl: '{{ seadoc_server_url }}',
|
||||
isSdocRevision: {% if is_sdoc_revision %}true{% else %}false{% endif %},
|
||||
revisionId: '{{ revision_id }}',
|
||||
originDocUuid: '{{ origin_doc_uuid }}',
|
||||
originParentPath: '{{ origin_parent_path }}',
|
||||
originFilename: '{{ origin_filename }}',
|
||||
|
@@ -19,6 +19,7 @@
|
||||
assetsUrl: '{{ assets_url }}',
|
||||
fileDownloadLink: '{{ file_download_link }}',
|
||||
isSdocRevision: {% if is_sdoc_revision %}true{% else %}false{% endif %},
|
||||
revisionId: '{{ revision_id }}',
|
||||
originDocUuid: '{{ origin_doc_uuid }}',
|
||||
originFileDownloadLink: '{{ origin_file_download_link }}',
|
||||
originParentPath: '{{ origin_parent_path }}',
|
||||
|
@@ -13,7 +13,7 @@ from seahub.views.file import view_history_file, view_trash_file,\
|
||||
view_snapshot_file, view_shared_file, view_file_via_shared_dir,\
|
||||
text_diff, view_raw_file, download_file, view_lib_file, \
|
||||
file_access, view_lib_file_via_smart_link, view_media_file_via_share_link, \
|
||||
view_media_file_via_public_wiki
|
||||
view_media_file_via_public_wiki, view_sdoc_revision
|
||||
from seahub.views.repo import repo_history_view, repo_snapshot, view_shared_dir, \
|
||||
view_shared_upload_link, view_lib_as_wiki
|
||||
|
||||
@@ -240,6 +240,7 @@ urlpatterns = [
|
||||
### lib (replace the old `repo` urls) ###
|
||||
# url(r'^lib/(?P<repo_id>[-0-9a-f]{36})/dir/(?P<path>.*)$', view_lib_dir, name='view_lib_dir'),
|
||||
re_path(r'^lib/(?P<repo_id>[-0-9a-f]{36})/file(?P<path>.*)$', view_lib_file, name='view_lib_file'),
|
||||
re_path(r'^lib/(?P<repo_id>[-0-9a-f]{36})/revisions/(?P<revision_id>\d+)/$', view_sdoc_revision, name='view_sdoc_revision'),
|
||||
re_path(r'^wiki/lib/(?P<repo_id>[-0-9a-f]{36})/(?P<path>.*)$', view_lib_as_wiki, name='view_lib_as_wiki'),
|
||||
re_path(r'^smart-link/(?P<dirent_uuid>[-0-9a-f]{36})/(?P<dirent_name>.*)$', view_lib_file_via_smart_link, name="view_lib_file_via_smart_link"),
|
||||
|
||||
|
@@ -76,7 +76,7 @@ from seahub.thumbnail.utils import extract_xmind_image, get_thumbnail_src, \
|
||||
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 SeadocDraft
|
||||
from seahub.seadoc.models import SeadocDraft, SeadocRevision
|
||||
|
||||
if HAS_OFFICE_CONVERTER:
|
||||
from seahub.utils import (
|
||||
@@ -2117,3 +2117,138 @@ def get_file_content_from_cache(file_id, repo_id, file_name):
|
||||
cache.set(cache_key, file_content, 24 * 60 * 60)
|
||||
|
||||
return err_msg, file_content
|
||||
|
||||
@login_required
|
||||
@repo_passwd_set_required
|
||||
def view_sdoc_revision(request, repo_id, revision_id):
|
||||
|
||||
# resource check
|
||||
repo = seafile_api.get_repo(repo_id)
|
||||
if not repo:
|
||||
raise Http404
|
||||
|
||||
revision = SeadocRevision.objects.get_by_revision_id(repo_id, revision_id)
|
||||
if not revision:
|
||||
return render_error(request, 'revision not found')
|
||||
uuid_map = FileUUIDMap.objects.filter(
|
||||
uuid=revision.doc_uuid).first()
|
||||
if not uuid_map:
|
||||
return render_error(request, _('File does not exist'))
|
||||
|
||||
path = posixpath.join(uuid_map.parent_path, uuid_map.filename)
|
||||
file_id = seafile_api.get_file_id_by_path(repo_id, path)
|
||||
if not file_id:
|
||||
return render_error(request, _('File does not exist'))
|
||||
|
||||
# permission check
|
||||
username = request.user.username
|
||||
parent_dir = uuid_map.parent_path
|
||||
filename = uuid_map.filename
|
||||
|
||||
permission = check_folder_permission(request, repo_id, parent_dir)
|
||||
if not permission:
|
||||
return convert_repo_path_when_can_not_view_file(request, repo_id, path)
|
||||
|
||||
org_id = request.user.org.org_id if is_org_context(request) else -1
|
||||
# basic file info
|
||||
return_dict = {
|
||||
'is_pro': is_pro_version(),
|
||||
'repo': repo,
|
||||
'file_id': file_id,
|
||||
'last_commit_id': repo.head_cmmt_id,
|
||||
'is_repo_owner': is_repo_owner(request, repo_id, username),
|
||||
'path': path,
|
||||
'parent_dir': parent_dir,
|
||||
'filename': filename,
|
||||
'file_perm': permission,
|
||||
'highlight_keyword': settings.HIGHLIGHT_KEYWORD,
|
||||
'enable_file_comment': settings.ENABLE_FILE_COMMENT,
|
||||
'enable_watermark': ENABLE_WATERMARK,
|
||||
'share_link_force_use_password': SHARE_LINK_FORCE_USE_PASSWORD,
|
||||
'share_link_password_min_length': SHARE_LINK_PASSWORD_MIN_LENGTH,
|
||||
'share_link_password_strength_level': SHARE_LINK_PASSWORD_STRENGTH_LEVEL,
|
||||
'share_link_expire_days_default': SHARE_LINK_EXPIRE_DAYS_DEFAULT,
|
||||
'share_link_expire_days_min': SHARE_LINK_EXPIRE_DAYS_MIN,
|
||||
'share_link_expire_days_max': SHARE_LINK_EXPIRE_DAYS_MAX,
|
||||
'can_download_file': parse_repo_perm(permission).can_download,
|
||||
'seafile_collab_server': SEAFILE_COLLAB_SERVER,
|
||||
}
|
||||
|
||||
# check whether file is starred
|
||||
is_starred = is_file_starred(username, repo_id, path, org_id)
|
||||
return_dict['is_starred'] = is_starred
|
||||
|
||||
# check file lock info
|
||||
try:
|
||||
is_locked, locked_by_me = check_file_lock(repo_id, path, username)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
is_locked = False
|
||||
locked_by_me = False
|
||||
|
||||
if is_pro_version() and permission == 'rw':
|
||||
can_lock_unlock_file = True
|
||||
else:
|
||||
can_lock_unlock_file = False
|
||||
|
||||
return_dict['file_locked'] = is_locked
|
||||
return_dict['locked_by_me'] = locked_by_me
|
||||
return_dict['can_lock_unlock_file'] = can_lock_unlock_file
|
||||
|
||||
# file shared link
|
||||
l = FileShare.objects.filter(repo_id=repo_id).filter(
|
||||
username=username).filter(path=path)
|
||||
fileshare = l[0] if len(l) > 0 else None
|
||||
file_shared_link = gen_file_share_link(fileshare.token) if fileshare else ''
|
||||
|
||||
return_dict['fileshare'] = fileshare,
|
||||
return_dict['file_shared_link'] = file_shared_link
|
||||
|
||||
if parse_repo_perm(permission).can_download and \
|
||||
request.user.permissions.can_generate_share_link():
|
||||
return_dict['can_share_file'] = True
|
||||
else:
|
||||
return_dict['can_share_file'] = False
|
||||
|
||||
# fetch file contributors and latest contributor
|
||||
try:
|
||||
# get real path for sub repo
|
||||
real_path = repo.origin_path + path if repo.origin_path else path
|
||||
dirent = seafile_api.get_dirent_by_path(repo.store_id, real_path)
|
||||
if dirent:
|
||||
latest_contributor, last_modified = dirent.modifier, dirent.mtime
|
||||
else:
|
||||
latest_contributor, last_modified = None, 0
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
latest_contributor, last_modified = None, 0
|
||||
|
||||
return_dict['latest_contributor'] = latest_contributor
|
||||
return_dict['last_modified'] = last_modified
|
||||
|
||||
# get file type and extention
|
||||
filetype, fileext = get_file_type_and_ext(filename)
|
||||
return_dict['fileext'] = fileext
|
||||
return_dict['filetype'] = filetype
|
||||
|
||||
file_uuid = str(uuid_map.uuid)
|
||||
return_dict['file_uuid'] = file_uuid
|
||||
return_dict['assets_url'] = '/api/v2.1/seadoc/download-image/' + file_uuid
|
||||
return_dict['seadoc_server_url'] = SEADOC_SERVER_URL
|
||||
|
||||
can_edit_file = True
|
||||
if parse_repo_perm(permission).can_edit_on_web is False:
|
||||
can_edit_file = False
|
||||
elif is_locked and not locked_by_me:
|
||||
can_edit_file = False
|
||||
|
||||
seadoc_perm = 'rw' if can_edit_file else 'r'
|
||||
return_dict['can_edit_file'] = can_edit_file
|
||||
return_dict['seadoc_access_token'] = gen_seadoc_access_token(file_uuid, filename, username, permission=seadoc_perm)
|
||||
|
||||
# revision
|
||||
revision_info = is_seadoc_revision(file_uuid, revision)
|
||||
return_dict.update(revision_info)
|
||||
|
||||
send_file_access_msg(request, repo, path, 'web')
|
||||
return render(request, 'sdoc_file_view_react.html', return_dict)
|
||||
|
@@ -1401,6 +1401,7 @@ CREATE TABLE `sdoc_draft` (
|
||||
CREATE TABLE `sdoc_revision` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`repo_id` varchar(36) NOT NULL,
|
||||
`revision_id` int(11) NOT NULL,
|
||||
`doc_uuid` varchar(36) NOT NULL,
|
||||
`origin_doc_uuid` varchar(36) NOT NULL,
|
||||
`origin_doc_path` longtext NOT NULL,
|
||||
@@ -1413,6 +1414,7 @@ CREATE TABLE `sdoc_revision` (
|
||||
`updated_at` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `sdoc_revise_doc_uuid` (`doc_uuid`),
|
||||
UNIQUE KEY `sdoc_revision_repo_id_revision_id` (`repo_id`, `revision_id`),
|
||||
KEY `sdoc_revision_repo_id` (`repo_id`),
|
||||
KEY `sdoc_revision_origin_doc_uuid` (`origin_doc_uuid`),
|
||||
KEY `sdoc_revision_username` (`username`),
|
||||
|
Reference in New Issue
Block a user