diff --git a/frontend/src/components/wiki-markdown-viewer.js b/frontend/src/components/wiki-markdown-viewer.js
index 602b1a49cd..9c3da3d8b3 100644
--- a/frontend/src/components/wiki-markdown-viewer.js
+++ b/frontend/src/components/wiki-markdown-viewer.js
@@ -1,8 +1,9 @@
import React from 'react';
import PropTypes from 'prop-types';
import MarkdownViewer from '@seafile/seafile-editor/dist/viewer/markdown-viewer';
-import { gettext } from '../utils/constants';
+import { gettext, repoID, slug, serviceURL, isPublicWiki } from '../utils/constants';
import Loading from './loading';
+import { Utils } from '../utils/utils';
const propTypes = {
children: PropTypes.object,
@@ -10,7 +11,8 @@ const propTypes = {
markdownContent: PropTypes.string.isRequired,
latestContributor: PropTypes.string.isRequired,
lastModified: PropTypes.string.isRequired,
- onLinkClick: PropTypes.func.isRequired
+ onLinkClick: PropTypes.func.isRequired,
+ isWiki: PropTypes.bool
};
const contentClass = 'wiki-page-content';
@@ -102,6 +104,76 @@ class WikiMarkdownViewer extends React.Component {
this.setState({activeTitleIndex: activeTitleIndex});
}
+ changeInlineNode = (item) => {
+ if (item.object == 'inline') {
+ let url;
+
+ // change image url
+ if (item.type == 'image' && isPublicWiki) {
+ url = item.data.src;
+ const re = new RegExp(serviceURL + '/lib/' + repoID +'/file.*raw=1');
+ // different repo
+ if (!re.test(url)) {
+ return;
+ }
+ // get image path
+ let index = url.indexOf('/file');
+ let index2 = url.indexOf('?');
+ const imagePath = url.substring(index + 5, index2);
+ // replace url
+ item.data.src = serviceURL + '/view-image-via-public-wiki/?slug=' + slug + '&path=' + imagePath;
+ }
+
+ else if (item.type == 'link') {
+ url = item.data.href;
+ // change file url
+ if (Utils.isInternalMarkdownLink(url, repoID)) {
+ let path = Utils.getPathFromInternalMarkdownLink(url, repoID);
+ // replace url
+ item.data.href = serviceURL + '/wikis/' + slug + path;
+ }
+ // change dir url
+ else if (Utils.isInternalDirLink(url, repoID)) {
+ let path = Utils.getPathFromInternalDirLink(url, repoID, slug);
+ // replace url
+ item.data.href = serviceURL + '/wikis/' + slug + path;
+ }
+ }
+ }
+
+ return item;
+ }
+
+ modifyValueBeforeRender = (value) => {
+ let nodes = value.document.nodes;
+ let newNodes = Utils.changeMarkdownNodes(nodes, this.changeInlineNode);
+ value.document.nodes = newNodes;
+ return value;
+ }
+
+ renderMarkdown = () => {
+ if (this.props.isWiki) {
+ return (
+
+ )
+ }
+
+ return (
+
+ )
+ }
+
render() {
if (this.props.isFileLoading) {
return
@@ -110,12 +182,7 @@ class WikiMarkdownViewer extends React.Component {
{this.props.children}
-
+ {this.renderMarkdown()}
{gettext('Last modified by')} {this.props.latestContributor}, {this.props.lastModified}
@@ -123,6 +190,11 @@ class WikiMarkdownViewer extends React.Component {
}
}
+const defaultProps = {
+ isWiki: false,
+}
+
WikiMarkdownViewer.propTypes = propTypes;
+MarkdownViewer.defaultProps = defaultProps;
export default WikiMarkdownViewer;
diff --git a/frontend/src/pages/wiki/main-panel.js b/frontend/src/pages/wiki/main-panel.js
index 3408d721fd..fc9808b60d 100644
--- a/frontend/src/pages/wiki/main-panel.js
+++ b/frontend/src/pages/wiki/main-panel.js
@@ -117,6 +117,7 @@ class MainPanel extends Component {
lastModified = {this.props.lastModified}
latestContributor={this.props.latestContributor}
onLinkClick={this.props.onLinkClick}
+ isWiki={true}
/>
}
{!this.props.isViewFileState &&
diff --git a/frontend/src/shared-file-view-markdown.js b/frontend/src/shared-file-view-markdown.js
index cb718f8e15..23c94ef995 100644
--- a/frontend/src/shared-file-view-markdown.js
+++ b/frontend/src/shared-file-view-markdown.js
@@ -1,7 +1,7 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Account from './components/common/account';
-import { gettext, siteRoot, mediaUrl, logoPath, logoWidth, logoHeight, siteTitle } from './utils/constants';
+import { serviceURL, gettext, siteRoot, mediaUrl, logoPath, logoWidth, logoHeight, siteTitle } from './utils/constants';
import { Button } from 'reactstrap';
import { seafileAPI } from './utils/seafile-api';
import { Utils } from './utils/utils';
@@ -17,7 +17,7 @@ import './assets/css/fa-regular.css';
import './assets/css/fontawesome.css';
let loginUser = window.app.pageOptions.name;
-const { serviceURL, repoID, sharedToken, trafficOverLimit, fileName, fileSize, rawPath, sharedBy, siteName, enableWatermark, download } = window.shared.pageOptions;
+const { repoID, sharedToken, trafficOverLimit, fileName, fileSize, rawPath, sharedBy, siteName, enableWatermark, download } = window.shared.pageOptions;
class SharedFileViewMarkdown extends React.Component {
@@ -62,6 +62,33 @@ class SharedFileViewMarkdown extends React.Component {
}
}
+ changeImageURL = (innerNode) => {
+ if (innerNode.type == 'image') {
+ let imageUrl = innerNode.data.src;
+
+ const re = new RegExp(serviceURL + '/lib/' + repoID +'/file.*raw=1');
+
+ // different repo
+ if (!re.test(imageUrl)) {
+ return;
+ }
+ // get image path
+ let index = imageUrl.indexOf('/file');
+ let index2 = imageUrl.indexOf('?');
+ const imagePath = imageUrl.substring(index + 5, index2);
+ // change image url
+ innerNode.data.src = serviceURL + '/view-image-via-share-link/?token=' + sharedToken + '&path=' + imagePath;
+ }
+ return innerNode;
+ }
+
+ modifyValueBeforeRender = (value) => {
+ let nodes = value.document.nodes;
+ let newNodes = Utils.changeMarkdownNodes(nodes, this.changeImageURL);
+ value.document.nodes = newNodes;
+ return value;
+ }
+
render() {
if (this.state.loading) {
return
@@ -102,9 +129,9 @@ class SharedFileViewMarkdown extends React.Component {
diff --git a/frontend/src/utils/constants.js b/frontend/src/utils/constants.js
index f735ef0c2d..f9744d1a04 100644
--- a/frontend/src/utils/constants.js
+++ b/frontend/src/utils/constants.js
@@ -13,6 +13,7 @@ export const isPro = window.app.config.isPro === 'True';
export const lang = window.app.config.lang;
export const fileServerRoot = window.app.config.fileServerRoot;
export const seafileVersion = window.app.config.seafileVersion;
+export const serviceURL = window.app.config.serviceURL;
//pageOptions
export const seafileCollabServer = window.app.pageOptions.seafileCollabServer;
@@ -46,6 +47,7 @@ export const initialPath = window.wiki ? window.wiki.config.initial_path : '';
export const permission = window.wiki ? window.wiki.config.permission === 'True' : '';
export const isDir = window.wiki ? window.wiki.config.isDir : '';
export const serviceUrl = window.wiki ? window.wiki.config.serviceUrl : '';
+export const isPublicWiki = window.wiki ? window.wiki.config.isPublicWiki === 'True': '';
// file history
export const PER_PAGE = 25;
diff --git a/frontend/src/utils/utils.js b/frontend/src/utils/utils.js
index 53a4282e66..42a0ae7e9e 100644
--- a/frontend/src/utils/utils.js
+++ b/frontend/src/utils/utils.js
@@ -1,4 +1,4 @@
-import { mediaUrl, gettext, siteRoot } from './constants';
+import { mediaUrl, gettext, serviceURL } from './constants';
import { strChineseFirstPY } from './pinyin-by-unicode';
export const Utils = {
@@ -404,30 +404,59 @@ export const Utils = {
},
isInternalMarkdownLink: function(url, repoID) {
- var re = new RegExp(siteRoot + 'lib/' + repoID + '.*\.md$');
+ var re = new RegExp(serviceURL + '/lib/' + repoID + '.*\.md$');
return re.test(url);
},
isInternalDirLink: function(url, repoID) {
- var re = new RegExp(siteRoot + 'library/' + repoID + '.*');
+ var re = new RegExp(serviceURL + '/library/' + repoID + '.*');
return re.test(url);
},
getPathFromInternalMarkdownLink: function(url, repoID) {
- var re = new RegExp(siteRoot + 'lib/' + repoID + '/file' + '(.*\.md)');
+ var re = new RegExp(serviceURL + '/lib/' + repoID + '/file' + '(.*\.md)');
var array = re.exec(url);
var path = decodeURIComponent(array[1]);
return path;
},
getPathFromInternalDirLink: function(url, repoID, repoName) {
- var re = new RegExp(siteRoot + 'library/' + repoID + '/' + repoName + '(/.*)');
+ var repoName = encodeURIComponent(repoName);
+ var re = new RegExp(serviceURL + '/library/' + repoID + '/' + repoName + '(/.*)');
var array = re.exec(url);
var path = decodeURIComponent(array[1]);
return path;
},
+ isWikiInternalMarkdownLink: function(url, slug) {
+ var slug = encodeURIComponent(slug);
+ var re = new RegExp(serviceURL + '/wikis/' + slug + '.*\.md$');
+ return re.test(url);
+ },
+
+ isWikiInternalDirLink: function(url, slug) {
+ var slug = encodeURIComponent(slug);
+ var re = new RegExp(serviceURL + '/wikis/' + slug + '.*');
+ return re.test(url);
+ },
+
+ getPathFromWikiInternalMarkdownLink: function(url, slug) {
+ var slug = encodeURIComponent(slug);
+ var re = new RegExp(serviceURL + '/wikis/' + slug + '(.*\.md)');
+ var array = re.exec(url);
+ var path = decodeURIComponent(array[1]);
+ return path;
+ },
+
+ getPathFromWikiInternalDirLink: function(url, slug) {
+ var slug = encodeURIComponent(slug);
+ var re = new RegExp(serviceURL + '/wikis/' + slug+ '(/.*)');
+ var array = re.exec(url);
+ var path = decodeURIComponent(array[1]);
+ return path;
+ },
+
compareTwoWord: function(wordA, wordB) {
// compare wordA and wordB at lower case
// if wordA >= wordB, return 1
@@ -577,6 +606,17 @@ export const Utils = {
}
});
return items;
- }
+ },
+
+ changeMarkdownNodes: function(nodes, fn) {
+ nodes.map((item) => {
+ fn(item);
+ if (item.nodes && item.nodes.length > 0){
+ Utils.changeMarkdownNodes(item.nodes, fn);
+ }
+ });
+
+ return nodes;
+ },
};
diff --git a/frontend/src/wiki.js b/frontend/src/wiki.js
index 34010363e3..4413fbaf17 100644
--- a/frontend/src/wiki.js
+++ b/frontend/src/wiki.js
@@ -119,11 +119,11 @@ class Wiki extends Component {
onLinkClick = (link) => {
const url = link;
- if (Utils.isInternalMarkdownLink(url, repoID)) {
- let path = Utils.getPathFromInternalMarkdownLink(url, repoID);
+ if (Utils.isWikiInternalMarkdownLink(url, slug)) {
+ let path = Utils.getPathFromWikiInternalMarkdownLink(url, slug);
this.initMainPanelData(path);
- } else if (Utils.isInternalDirLink(url, repoID)) {
- let path = Utils.getPathFromInternalDirLink(url, repoID, slug);
+ } else if (Utils.isWikiInternalDirLink(url, slug)) {
+ let path = Utils.getPathFromWikiInternalDirLink(url, slug);
this.initWikiData(path);
} else {
window.location.href = url;
diff --git a/seahub/base/context_processors.py b/seahub/base/context_processors.py
index e6767d58e8..afc8fa88dd 100644
--- a/seahub/base/context_processors.py
+++ b/seahub/base/context_processors.py
@@ -22,7 +22,7 @@ from seahub.settings import SEAFILE_VERSION, SITE_TITLE, SITE_NAME, \
MEDIA_ROOT, SHOW_LOGOUT_ICON, CUSTOM_LOGO_PATH, CUSTOM_FAVICON_PATH
from seahub.constants import DEFAULT_ADMIN
-from seahub.utils import get_site_name
+from seahub.utils import get_site_name, get_service_url
try:
from seahub.settings import SEACLOUD_MODE
@@ -118,7 +118,8 @@ def base(request):
'is_pro': True if is_pro_version() else False,
'enable_repo_wiki_mode': dj_settings.ENABLE_REPO_WIKI_MODE,
'enable_upload_folder': dj_settings.ENABLE_UPLOAD_FOLDER,
- 'enable_resumable_fileupload': dj_settings.ENABLE_RESUMABLE_FILEUPLOAD
+ 'enable_resumable_fileupload': dj_settings.ENABLE_RESUMABLE_FILEUPLOAD,
+ 'service_url': get_service_url().rstrip('/'),
}
if request.user.is_staff:
diff --git a/seahub/templates/base_for_react.html b/seahub/templates/base_for_react.html
index 9f1abf6fc2..94348046fd 100644
--- a/seahub/templates/base_for_react.html
+++ b/seahub/templates/base_for_react.html
@@ -35,6 +35,7 @@
isPro: '{{ is_pro }}',
lang: '{{ LANGUAGE_CODE }}',
fileServerRoot: '{{ FILE_SERVER_ROOT }}',
+ serviceURL: '{{ service_url }}',
seafileVersion: '{{ seafile_version }}',
},
pageOptions: {
diff --git a/seahub/templates/shared_file_view_react_markdown.html b/seahub/templates/shared_file_view_react_markdown.html
index 569afe843d..7cda36f20c 100644
--- a/seahub/templates/shared_file_view_react_markdown.html
+++ b/seahub/templates/shared_file_view_react_markdown.html
@@ -17,7 +17,6 @@
siteName: '{{ site_name }}',
enableWatermark: '{{ enable_watermark }}' == 'True',
download: '{{ permissions.can_download}}' == 'True',
- serviceURL: '{{ serviceUrl }}',
}
};
diff --git a/seahub/templates/wiki/wiki.html b/seahub/templates/wiki/wiki.html
index e4f824cd42..43fb099ba4 100644
--- a/seahub/templates/wiki/wiki.html
+++ b/seahub/templates/wiki/wiki.html
@@ -11,7 +11,7 @@
slug: "{{ wiki.slug }}",
repoId: "{{ wiki.repo_id }}",
initial_path: "{{ file_path }}",
- permission: "{{ user_can_write }}",
+ isPublicWiki: "{{ is_public_wiki }}",
}
};
diff --git a/seahub/urls.py b/seahub/urls.py
index b5967effd9..80fbd4c875 100644
--- a/seahub/urls.py
+++ b/seahub/urls.py
@@ -12,7 +12,8 @@ from seahub.views.sso import *
from seahub.views.file import view_history_file, view_trash_file,\
view_snapshot_file, file_edit, 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
+ file_access, view_lib_file_via_smart_link, view_media_file_via_share_link, \
+ view_media_file_via_public_wiki
from seahub.views.repo import repo_history_view, view_shared_dir, \
view_shared_upload_link, view_lib_as_wiki
from notifications.views import notification_list
@@ -362,6 +363,7 @@ urlpatterns = [
url(r'^api/v2.1/wikis/(?P[^/]+)/dir/$', WikiPagesDirView.as_view(), name='api-v2.1-wiki-pages-dir'),
url(r'^api/v2.1/wikis/(?P[^/]+)/content/$', WikiPageContentView.as_view(), name='api-v2.1-wiki-pages-content'),
url(r'^api/v2.1/wikis/(?P[^/]+)/pages/(?P[^/]+)/$', WikiPageView.as_view(), name='api-v2.1-wiki-page'),
+ url(r'^view-image-via-public-wiki/$', view_media_file_via_public_wiki, name='view_media_file_via_public_wiki'),
## user::drafts
url(r'^api/v2.1/drafts/$', DraftsView.as_view(), name='api-v2.1-drafts'),
diff --git a/seahub/views/file.py b/seahub/views/file.py
index 828a6927a2..61b3f74804 100644
--- a/seahub/views/file.py
+++ b/seahub/views/file.py
@@ -48,7 +48,7 @@ from seahub.base.accounts import ANONYMOUS_EMAIL
from seahub.share.models import FileShare, check_share_link_common
from seahub.share.decorators import share_link_audit, share_link_login_required
from seahub.wiki.utils import get_wiki_dirent
-from seahub.wiki.models import WikiDoesNotExist, WikiPageMissing
+from seahub.wiki.models import Wiki, WikiDoesNotExist, WikiPageMissing
from seahub.utils import render_error, is_org_context, \
get_file_type_and_ext, gen_file_get_url, gen_file_share_link, \
render_permission_error, is_pro_version, is_textual_file, \
@@ -1213,7 +1213,6 @@ def view_shared_file(request, fileshare):
'traffic_over_limit': traffic_over_limit,
'permissions': permissions,
'enable_watermark': ENABLE_WATERMARK,
- 'serviceUrl': get_service_url().rstrip('/'),
})
@share_link_audit
@@ -2041,21 +2040,10 @@ def view_media_file_via_share_link(request):
return render_error(request, 'File does not exist')
# read file from cache, if hit
- cache_key = normalize_cache_key(file_id, token=token)
- file_content = cache.get(cache_key)
- if not file_content:
- # otherwise, read file from database and update cache
- access_token = seafile_api.get_fileserver_access_token(repo_id,
- file_id, 'view', '', use_onetime=False)
+ err_msg, file_content = get_file_content_from_cache(file_id, repo_id, shared_file_name)
- if not access_token:
- err_msg = 'Unable to view file'
- return render_error(request, err_msg)
-
- shared_file_raw_path = gen_inner_file_get_url(access_token, shared_file_name)
-
- err, file_content, encode = repo_file_get(shared_file_raw_path, 'auto')
- cache.set(cache_key, file_content, 24 * 60 * 60)
+ if err_msg:
+ return render_error(request, err_msg)
# If the image does not exist in markdown
serviceURL = get_service_url().rstrip('/')
@@ -2077,3 +2065,69 @@ def view_media_file_via_share_link(request):
dl_or_raw_url = gen_file_get_url(access_token, image_file_name)
return HttpResponseRedirect(dl_or_raw_url)
+
+
+def view_media_file_via_public_wiki(request):
+ image_path = request.GET.get('path', '')
+ slug = request.GET.get('slug', '')
+ if not image_path or not slug:
+ return HttpResponseBadRequest('invalid params')
+
+ # check file type
+ image_file_name = os.path.basename(image_path)
+ file_type, file_ext = get_file_type_and_ext(image_file_name)
+ if file_type != IMAGE:
+ err_msg = 'Invalid file type'
+ return render_error(request, err_msg)
+
+ # get wiki object or 404
+ try:
+ wiki = Wiki.objects.get(slug=slug)
+ except Wiki.DoesNotExist:
+ err_msg = "Wiki not found."
+ return render_error(request, err_msg)
+
+ if wiki.permission != 'public':
+ return render_permission_error(request, 'Permission denied')
+
+ # recourse check
+ repo_id = wiki.repo_id
+ repo = seafile_api.get_repo(repo_id)
+ if not repo:
+ return render_error(request, 'Repo does not exist')
+
+ # get image
+ obj_id = seafile_api.get_file_id_by_path(repo_id, image_path)
+ if not obj_id:
+ return render_error(request, 'Image does not exist')
+
+ access_token = seafile_api.get_fileserver_access_token(repo_id,
+ obj_id, 'view', '', use_onetime=False)
+
+ dl_or_raw_url = gen_file_get_url(access_token, image_file_name)
+
+ return HttpResponseRedirect(dl_or_raw_url)
+
+
+def get_file_content_from_cache(file_id, repo_id, file_name):
+ err_msg = ''
+ file_content = ''
+
+ cache_key = normalize_cache_key(file_id)
+ # read file from cache, if hit
+ file_content = cache.get(cache_key)
+ if not file_content:
+ # otherwise, read file from database and update cache
+ access_token = seafile_api.get_fileserver_access_token(repo_id,
+ file_id, 'view', '', use_onetime=False)
+
+ if not access_token:
+ err_msg = 'Unable to view file'
+ return err_msg, file_content
+
+ file_raw_path = gen_inner_file_get_url(access_token, file_name)
+
+ err_msg, file_content, encode = repo_file_get(file_raw_path, 'auto')
+ cache.set(cache_key, file_content, 24 * 60 * 60)
+
+ return err_msg, file_content
diff --git a/seahub/wiki/views.py b/seahub/wiki/views.py
index 6fe9b976a8..1031087d8e 100644
--- a/seahub/wiki/views.py
+++ b/seahub/wiki/views.py
@@ -65,22 +65,18 @@ def slug(request, slug, file_path="home.md"):
file_url = reverse('view_lib_file', args=[wiki.repo_id, file_path])
return HttpResponseRedirect(file_url + "?raw=1")
- if not req_user:
- user_can_write = False
- elif req_user == wiki.username or check_folder_permission(
- request, wiki.repo_id, '/') == 'rw':
- user_can_write = True
- else:
- user_can_write = False
+ is_public_wiki = False
+ if wiki.permission == 'public':
+ is_public_wiki = True
return render(request, "wiki/wiki.html", {
"wiki": wiki,
"page_name": file_path,
- "user_can_write": user_can_write,
"file_path": file_path,
"repo_id": wiki.repo_id,
"search_repo_id": wiki.repo_id,
"search_wiki": True,
+ "is_public_wiki": is_public_wiki,
})