diff --git a/frontend/config/webpack.entry.js b/frontend/config/webpack.entry.js index 575b9281da..7e46e2ce6a 100644 --- a/frontend/config/webpack.entry.js +++ b/frontend/config/webpack.entry.js @@ -9,6 +9,7 @@ const entryFiles = { fileHistory: "/file-history.js", fileHistoryOld: "/file-history-old.js", sdocFileHistory: "/pages/sdoc-file-history/index.js", + sdocRevision: "/pages/sdoc-revision/index.js", app: "/app.js", draft: "/draft.js", sharedDirView: "/shared-dir-view.js", diff --git a/frontend/src/css/sdoc-revision.css b/frontend/src/css/sdoc-revision.css new file mode 100644 index 0000000000..ac46fffb7d --- /dev/null +++ b/frontend/src/css/sdoc-revision.css @@ -0,0 +1,51 @@ +.sdoc-revision .sdoc-revision-container { + flex: 1; + overflow-x: hidden; +} + +.sdoc-revision .sdoc-revision-header { + height: 50px; + border-bottom: 1px solid #e5e5e5; + background-color: #fff; +} + +.sdoc-revision .sdoc-revision-header .sdoc-revision-header-left { + font-size: 1.25rem; + flex: 1; +} + +.sdoc-revision .sdoc-revision-header .file-name { + flex: 1; +} + +.sdoc-revision .sdoc-revision-header .sdoc-revision-header-right { + height: 100%; + min-width: 100px; +} + +.sdoc-revision .sdoc-revision-content { + flex: 1; + min-height: 0; + padding: 20px 40px; + background-color: #F5F5F5; + overflow-y: scroll; +} + +.sdoc-revision .sdoc-revision-content .sdoc-revision-viewer { + width: 100%; + min-height: 120px; + flex: 1; + background-color: #fff; + word-break: break-word; + border: 1px solid #e6e6dd; +} + +.sdoc-revision .sdoc-revision-content .sdoc-editor-content { + background-color: #fff; +} + +.sdoc-revision .sdoc-revision-content .article { + width: 100%; + margin: 0; +} + diff --git a/frontend/src/pages/sdoc-revision/index.js b/frontend/src/pages/sdoc-revision/index.js new file mode 100644 index 0000000000..0b6f3fc28a --- /dev/null +++ b/frontend/src/pages/sdoc-revision/index.js @@ -0,0 +1,124 @@ +import React from 'react'; +import ReactDom from 'react-dom'; +import classnames from 'classnames'; +import { Button } from 'reactstrap'; +import { DiffViewer } from '@seafile/sdoc-editor'; +import { gettext } from '../../utils/constants'; +import Loading from '../../components/loading'; +import GoBack from '../../components/common/go-back'; +import { Utils } from '../../utils/utils'; +import { seafileAPI } from '../../utils/seafile-api'; + +import '../../css/layout.css'; +import '../../css/sdoc-revision.css'; + +const { serviceURL, avatarURL, siteRoot } = window.app.config; +const { username, name } = window.app.pageOptions; +const { repoID, fileName, filePath, docUuid, assetsUrl, fileDownloadLink, originFileDownloadLink, isPublished } = window.sdocRevision; + +window.seafile = { + repoID, + docPath: filePath, + docName: fileName, + docUuid, + isOpenSocket: false, + serviceUrl: serviceURL, + name, + username, + avatarURL, + siteRoot, + assetsUrl, +}; + +class SdocRevision extends React.Component { + + constructor(props) { + super(props); + this.state = { + isLoading: true, + errorMessage: '', + revisionContent: '', + originContent: '', + }; + } + + componentDidMount() { + fetch(fileDownloadLink).then(res => { + return res.json(); + }).then(revisionContent => { + fetch(originFileDownloadLink).then(res => { + return res.json(); + }).then(originContent => { + this.setState({ revisionContent, originContent, isLoading: false, errorMessage: '' }); + }).catch(error => { + const errorMessage = Utils.getErrorMsg(error, true); + this.setState({ isLoading: false, errorMessage }); + }); + }).catch(error => { + const errorMessage = Utils.getErrorMsg(error, true); + this.setState({ isLoading: false, errorMessage }); + }); + } + + publishRevision = (event) => { + event.stopPropagation(); + event.nativeEvent.stopImmediatePropagation(); + seafileAPI.sdocPublishRevision(docUuid).then(res => { + console.log(res) + }).catch(error => { + console.log(error); + }); + } + + renderContent = () => { + const { isLoading, errorMessage, revisionContent, originContent } = this.state; + if (isLoading) { + return ( +
+ +
+ ); + } + + if (errorMessage) { + return ( +
+ {gettext(errorMessage)} +
+ ); + } + + return ( + + ); + } + + render() { + return ( +
+
+
+
+ +
{fileName}
+
+
+ + {!isPublished && ( + + )} +
+
+
+ {this.renderContent()} +
+
+
+ ); + } +} + +ReactDom.render(, document.getElementById('wrapper')); diff --git a/frontend/src/utils/utils.js b/frontend/src/utils/utils.js index f63d6c440e..d680eee91d 100644 --- a/frontend/src/utils/utils.js +++ b/frontend/src/utils/utils.js @@ -1543,6 +1543,11 @@ export const Utils = { generateHistoryURL: function(siteRoot, repoID, path) { if (!siteRoot || !repoID || !path) return ''; return siteRoot + 'repo/file_revisions/' + repoID + '/?p=' + this.encodePath(path); + }, + + generateRevisionURL: function(siteRoot, repoID, path) { + if (!siteRoot || !repoID || !path) return ''; + return siteRoot + 'repo/sdoc_revision/' + repoID + '/?p=' + this.encodePath(path); } }; diff --git a/frontend/src/view-file-sdoc.js b/frontend/src/view-file-sdoc.js index 48bf8bd91a..f81c3a88ea 100644 --- a/frontend/src/view-file-sdoc.js +++ b/frontend/src/view-file-sdoc.js @@ -10,7 +10,7 @@ const { serviceURL, avatarURL, siteRoot } = window.app.config; const { username, name } = window.app.userInfo; const { repoID, repoName, parentDir, filePerm, - docPath, docName, docUuid, seadocAccessToken, seadocServerUrl, assetsUrl + docPath, docName, docUuid, seadocAccessToken, seadocServerUrl, assetsUrl, } = window.app.pageOptions; window.seafile = { @@ -31,7 +31,8 @@ window.seafile = { parentFolderURL: `${siteRoot}library/${repoID}/${Utils.encodePath(repoName + parentDir)}`, assetsUrl, isShowInternalLink: true, - isStarIconShown: true // for star/unstar + isStarIconShown: true, // for star/unstar + revisionURL: Utils.generateRevisionURL(siteRoot, repoID, docPath), }; ReactDom.render( diff --git a/seahub/seadoc/urls.py b/seahub/seadoc/urls.py index e9727e9276..e881488e60 100644 --- a/seahub/seadoc/urls.py +++ b/seahub/seadoc/urls.py @@ -3,6 +3,8 @@ from .apis import SeadocAccessToken, SeadocUploadLink, SeadocDownloadLink, Seado SeadocUploadImage, SeadocDownloadImage, SeadocCopyHistoryFile, SeadocHistory, SeadocDrafts, SeadocMaskAsDraft, \ SeadocCommentsView, SeadocCommentView, SeadocRevisions, SeadocPublishRevision +from .views import sdoc_revision + urlpatterns = [ re_path(r'^access-token/(?P[-0-9a-f]{36})/$', SeadocAccessToken.as_view(), name='seadoc_access_token'), re_path(r'^upload-file/(?P[-0-9a-f]{36})/$', SeadocUploadFile.as_view(), name='seadoc_upload_file'), diff --git a/seahub/seadoc/views.py b/seahub/seadoc/views.py new file mode 100644 index 0000000000..8b4530dda2 --- /dev/null +++ b/seahub/seadoc/views.py @@ -0,0 +1,65 @@ +import os +from django.shortcuts import render +from django.utils.translation import gettext as _ +from seaserv import get_repo +from seahub.auth.decorators import login_required +from seahub.utils import render_error +from seahub.views import check_folder_permission, validate_owner, get_seadoc_file_uuid +from seahub.tags.models import FileUUIDMap + +from .utils import is_seadoc_revision, get_seadoc_download_link + + +@login_required +def sdoc_revision(request, repo_id): + """List file revisions in file version history page. + """ + repo = get_repo(repo_id) + if not repo: + error_msg = _("Library does not exist") + return render_error(request, error_msg) + + # perm check + if not check_folder_permission(request, repo_id, '/'): + error_msg = _("Permission denied.") + return render_error(request, error_msg) + + path = request.GET.get('p', '/') + if not path: + return render_error(request) + + if path[-1] == '/': + path = path[:-1] + + u_filename = os.path.basename(path) + + # Check whether user is repo owner + if validate_owner(request, repo_id): + is_owner = True + else: + is_owner = False + + file_uuid = get_seadoc_file_uuid(repo, path) + uuid_map = FileUUIDMap.objects.get_fileuuidmap_by_uuid(file_uuid) + return_dict = { + 'repo': repo, + 'path': path, + 'u_filename': u_filename, + 'file_uuid': file_uuid, + 'is_owner': is_owner, + 'can_compare': True, + 'assets_url': '/api/v2.1/seadoc/download-image/' + file_uuid, + 'file_download_link': get_seadoc_download_link(uuid_map) + } + + revision_info = is_seadoc_revision(file_uuid) + return_dict.update(revision_info) + + origin_doc_uuid = return_dict.get('origin_doc_uuid', '') + is_published = return_dict.get('is_published', False) + if (origin_doc_uuid and not is_published): + uuid_map = FileUUIDMap.objects.get_fileuuidmap_by_uuid(origin_doc_uuid) + return_dict['origin_file_download_link'] = get_seadoc_download_link(uuid_map) + + return render(request, 'sdoc_revision.html', return_dict) + diff --git a/seahub/templates/sdoc_revision.html b/seahub/templates/sdoc_revision.html new file mode 100644 index 0000000000..f11c8d6fc1 --- /dev/null +++ b/seahub/templates/sdoc_revision.html @@ -0,0 +1,37 @@ +{% extends "base_for_react.html" %} +{% load render_bundle from webpack_loader %} + +{% block extra_style %} +{% render_bundle 'sdocRevision' 'css'%} +{% endblock %} + +{% block extra_script %} + + {% render_bundle 'sdocRevision' 'js'%} +{% endblock %} diff --git a/seahub/urls.py b/seahub/urls.py index 61b148e473..e3b61d4412 100644 --- a/seahub/urls.py +++ b/seahub/urls.py @@ -194,6 +194,7 @@ from seahub.api2.endpoints.admin.virus_scan_records import AdminVirusFilesView, from seahub.api2.endpoints.file_participants import FileParticipantsView, FileParticipantView from seahub.api2.endpoints.repo_related_users import RepoRelatedUsersView from seahub.api2.endpoints.repo_auto_delete import RepoAutoDeleteView +from seahub.seadoc.views import sdoc_revision from seahub.ocm.settings import OCM_ENDPOINT @@ -220,6 +221,7 @@ urlpatterns = [ path('repo/upload_check/', validate_filename), re_path(r'^repo/download_dir/(?P[-0-9a-f]{36})/$', repo_download_dir, name='repo_download_dir'), re_path(r'^repo/file_revisions/(?P[-0-9a-f]{36})/$', file_revisions, name='file_revisions'), + re_path(r'^repo/sdoc_revision/(?P[-0-9a-f]{36})/$', sdoc_revision, name='sdoc_revision'), re_path(r'^repo/file-access/(?P[-0-9a-f]{36})/$', file_access, name='file_access'), re_path(r'^repo/text_diff/(?P[-0-9a-f]{36})/$', text_diff, name='text_diff'), re_path(r'^repo/history/(?P[-0-9a-f]{36})/$', repo_history, name='repo_history'),