diff --git a/frontend/src/components/search/search.js b/frontend/src/components/search/search.js index 6e9674b5c7..dc25bb47fd 100644 --- a/frontend/src/components/search/search.js +++ b/frontend/src/components/search/search.js @@ -1,12 +1,14 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import MediaQuery from 'react-responsive'; +import { seafileAPI } from '../../utils/seafile-api'; import { gettext, siteRoot } from '../../utils/constants'; import SearchResultItem from './search-result-item'; import editorUtilities from '../../utils/editor-utilties'; import More from '../more'; const propTypes = { + isPublic: PropTypes.bool, repoID: PropTypes.string, placeholder: PropTypes.string, onSearchedClick: PropTypes.func.isRequired, @@ -93,27 +95,53 @@ class Search extends Component { sendRequest(queryData, cancelToken) { var _this = this; - editorUtilities.searchFiles(queryData,cancelToken).then(res => { - if (!res.data.total) { + let isPublic = this.props.isPublic; + + if (isPublic) { + seafileAPI.searchPublicFiles(queryData.q, queryData.search_repo).then(res => { + if (!res.data.total) { + _this.setState({ + resultItems: [], + isResultGetted: true + }); + _this.source = null; + return; + } + + let items = _this.formatResultItems(res.data.results); _this.setState({ - resultItems: [], + resultItems: items, isResultGetted: true }); _this.source = null; - return; - } - - let items = _this.formatResultItems(res.data.results); - _this.setState({ - resultItems: items, - isResultGetted: true + }).catch(res => { + /* eslint-disable */ + console.log(res); + /* eslint-enable */ }); - _this.source = null; - }).catch(res => { - /* eslint-disable */ - console.log(res); - /* eslint-enable */ - }); + } else { + editorUtilities.searchFiles(queryData,cancelToken).then(res => { + if (!res.data.total) { + _this.setState({ + resultItems: [], + isResultGetted: true + }); + _this.source = null; + return; + } + + let items = _this.formatResultItems(res.data.results); + _this.setState({ + resultItems: items, + isResultGetted: true + }); + _this.source = null; + }).catch(res => { + /* eslint-disable */ + console.log(res); + /* eslint-enable */ + }); + } } cancelRequest() { diff --git a/frontend/src/pages/wiki/main-panel.js b/frontend/src/pages/wiki/main-panel.js index d53a83c9db..2e66391356 100644 --- a/frontend/src/pages/wiki/main-panel.js +++ b/frontend/src/pages/wiki/main-panel.js @@ -7,6 +7,7 @@ import WikiMarkdownViewer from '../../components/wiki-markdown-viewer'; import WikiDirListView from '../../components/wiki-dir-list-view/wiki-dir-list-view'; import Loading from '../../components/loading'; import { Utils } from '../../utils/utils'; +import Search from '../../components/search/search'; const propTypes = { path: PropTypes.string.isRequired, @@ -77,6 +78,21 @@ class MainPanel extends Component { return (
+ {!username && + +
+ +
+
+ +
+
+ } {username && (
diff --git a/seahub/api2/endpoints/public_repos_search.py b/seahub/api2/endpoints/public_repos_search.py new file mode 100644 index 0000000000..427a3db229 --- /dev/null +++ b/seahub/api2/endpoints/public_repos_search.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- +import logging + +from rest_framework.views import APIView +from rest_framework.authentication import SessionAuthentication +from rest_framework.permissions import IsAuthenticatedOrReadOnly +from rest_framework.response import Response +from rest_framework import status +from seaserv import seafile_api + +from seahub.api2.authentication import TokenAuthentication +from seahub.api2.throttling import UserRateThrottle +from seahub.api2.utils import api_error +from seahub.utils.repo import is_valid_repo_id_format +from seahub.utils import HAS_FILE_SEARCH +from seahub.wiki.models import Wiki +if HAS_FILE_SEARCH: + from seahub_extra.search.utils import search_files + + +logger = logging.getLogger('seafes') + + +class PublicReposSearchView(APIView): + """ Search public repos + """ + authentication_classes = (TokenAuthentication, SessionAuthentication) + permission_classes = (IsAuthenticatedOrReadOnly,) + throttle_classes = (UserRateThrottle, ) + + def get(self, request): + # is search supported + if not HAS_FILE_SEARCH: + error_msg = 'Search not supported.' + return api_error(status.HTTP_404_NOT_FOUND, error_msg) + + # argument check + keyword = request.GET.get('q', None) + if not keyword: + error_msg = 'q invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + search_repo = request.GET.get('search_repo', None) + if not is_valid_repo_id_format(search_repo): + error_msg = 'search_repo invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + # recourse check + repo = seafile_api.get_repo(search_repo) + if not repo: + error_msg = 'Library %s not found.' % search_repo + return api_error(status.HTTP_404_NOT_FOUND, error_msg) + + # permission check + wiki = Wiki.objects.filter(repo_id=search_repo)[0] + if not wiki.has_read_perm(request): + error_msg = 'Permission denied.' + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + + try: + current_page = int(request.GET.get('page', '1')) + per_page = int(request.GET.get('per_page', '10')) + if per_page > 100: + per_page = 100 + except ValueError: + current_page = 1 + per_page = 10 + + start = (current_page - 1) * per_page + size = per_page + if start < 0 or size < 0: + error_msg = 'page or per_page invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + repo_id_map = {} + map_id = repo.origin_repo_id if repo.origin_repo_id else search_repo + repo_id_map[map_id] = repo + # search file + try: + results, total = search_files( + repo_id_map, None, keyword, None, start, size, org_id=None + ) + except Exception as e: + logger.error(e) + error_msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + + for result in results: + result.pop('repo', None) + result.pop('exists', None) + result.pop('last_modified_by', None) + result.pop('name_highlight', None) + result.pop('score', None) + result['repo_type'] = 'public' + + has_more = True if total > current_page * per_page else False + + return Response({ + "total": total, + "results": results, + "has_more": has_more + }) diff --git a/seahub/urls.py b/seahub/urls.py index 3264e1eb71..d5bc3275a5 100644 --- a/seahub/urls.py +++ b/seahub/urls.py @@ -89,6 +89,7 @@ from seahub.api2.endpoints.related_files import RelatedFilesView, RelatedFileVie from seahub.api2.endpoints.webdav_secret import WebdavSecretView from seahub.api2.endpoints.starred_items import StarredItems from seahub.api2.endpoints.markdown_lint import MarkdownLintView +from seahub.api2.endpoints.public_repos_search import PublicReposSearchView # Admin from seahub.api2.endpoints.admin.revision_tag import AdminTaggedItemsView @@ -359,6 +360,9 @@ urlpatterns = [ # user: markdown-lint url(r'^api/v2.1/markdown-lint/$', MarkdownLintView.as_view(), name='api-v2.1-markdown-lint'), + # public repos search + url(r'^api/v2.1/public-repos-search/$', PublicReposSearchView.as_view(), name='api-v2.1-public-repos-search'), + # Deprecated url(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/tags/$', FileTagsView.as_view(), name="api-v2.1-filetags-view"), url(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/tags/(?P.*?)/$', FileTagView.as_view(), name="api-v2.1-filetag-view"),