mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-13 13:50:07 +00:00
public repo search (#3817)
* public repo search * remove print code * add permission check
This commit is contained in:
@@ -1,12 +1,14 @@
|
|||||||
import React, { Component, Fragment } from 'react';
|
import React, { Component, Fragment } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import MediaQuery from 'react-responsive';
|
import MediaQuery from 'react-responsive';
|
||||||
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { gettext, siteRoot } from '../../utils/constants';
|
import { gettext, siteRoot } from '../../utils/constants';
|
||||||
import SearchResultItem from './search-result-item';
|
import SearchResultItem from './search-result-item';
|
||||||
import editorUtilities from '../../utils/editor-utilties';
|
import editorUtilities from '../../utils/editor-utilties';
|
||||||
import More from '../more';
|
import More from '../more';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
|
isPublic: PropTypes.bool,
|
||||||
repoID: PropTypes.string,
|
repoID: PropTypes.string,
|
||||||
placeholder: PropTypes.string,
|
placeholder: PropTypes.string,
|
||||||
onSearchedClick: PropTypes.func.isRequired,
|
onSearchedClick: PropTypes.func.isRequired,
|
||||||
@@ -93,6 +95,31 @@ class Search extends Component {
|
|||||||
|
|
||||||
sendRequest(queryData, cancelToken) {
|
sendRequest(queryData, cancelToken) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
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: items,
|
||||||
|
isResultGetted: true
|
||||||
|
});
|
||||||
|
_this.source = null;
|
||||||
|
}).catch(res => {
|
||||||
|
/* eslint-disable */
|
||||||
|
console.log(res);
|
||||||
|
/* eslint-enable */
|
||||||
|
});
|
||||||
|
} else {
|
||||||
editorUtilities.searchFiles(queryData,cancelToken).then(res => {
|
editorUtilities.searchFiles(queryData,cancelToken).then(res => {
|
||||||
if (!res.data.total) {
|
if (!res.data.total) {
|
||||||
_this.setState({
|
_this.setState({
|
||||||
@@ -115,6 +142,7 @@ class Search extends Component {
|
|||||||
/* eslint-enable */
|
/* eslint-enable */
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cancelRequest() {
|
cancelRequest() {
|
||||||
this.source.cancel('prev request is cancelled');
|
this.source.cancel('prev request is cancelled');
|
||||||
|
@@ -7,6 +7,7 @@ import WikiMarkdownViewer from '../../components/wiki-markdown-viewer';
|
|||||||
import WikiDirListView from '../../components/wiki-dir-list-view/wiki-dir-list-view';
|
import WikiDirListView from '../../components/wiki-dir-list-view/wiki-dir-list-view';
|
||||||
import Loading from '../../components/loading';
|
import Loading from '../../components/loading';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
|
import Search from '../../components/search/search';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
path: PropTypes.string.isRequired,
|
path: PropTypes.string.isRequired,
|
||||||
@@ -77,6 +78,21 @@ class MainPanel extends Component {
|
|||||||
return (
|
return (
|
||||||
<div className="main-panel wiki-main-panel o-hidden">
|
<div className="main-panel wiki-main-panel o-hidden">
|
||||||
<div className="main-panel-north panel-top border-left-show">
|
<div className="main-panel-north panel-top border-left-show">
|
||||||
|
{!username &&
|
||||||
|
<Fragment>
|
||||||
|
<div className="cur-view-toolbar">
|
||||||
|
<span className="sf2-icon-menu hidden-md-up d-md-none side-nav-toggle" title="Side Nav Menu" onClick={this.onMenuClick}></span>
|
||||||
|
</div>
|
||||||
|
<div className="common-toolbar">
|
||||||
|
<Search
|
||||||
|
isPublic={true}
|
||||||
|
repoID={repoID}
|
||||||
|
onSearchedClick={this.props.onSearchedClick}
|
||||||
|
placeholder={gettext('Search files in this library')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
}
|
||||||
{username && (
|
{username && (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className="cur-view-toolbar">
|
<div className="cur-view-toolbar">
|
||||||
|
102
seahub/api2/endpoints/public_repos_search.py
Normal file
102
seahub/api2/endpoints/public_repos_search.py
Normal file
@@ -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
|
||||||
|
})
|
@@ -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.webdav_secret import WebdavSecretView
|
||||||
from seahub.api2.endpoints.starred_items import StarredItems
|
from seahub.api2.endpoints.starred_items import StarredItems
|
||||||
from seahub.api2.endpoints.markdown_lint import MarkdownLintView
|
from seahub.api2.endpoints.markdown_lint import MarkdownLintView
|
||||||
|
from seahub.api2.endpoints.public_repos_search import PublicReposSearchView
|
||||||
|
|
||||||
# Admin
|
# Admin
|
||||||
from seahub.api2.endpoints.admin.revision_tag import AdminTaggedItemsView
|
from seahub.api2.endpoints.admin.revision_tag import AdminTaggedItemsView
|
||||||
@@ -359,6 +360,9 @@ urlpatterns = [
|
|||||||
# user: markdown-lint
|
# user: markdown-lint
|
||||||
url(r'^api/v2.1/markdown-lint/$', MarkdownLintView.as_view(), name='api-v2.1-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
|
# Deprecated
|
||||||
url(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/tags/$', FileTagsView.as_view(), name="api-v2.1-filetags-view"),
|
url(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/tags/$', FileTagsView.as_view(), name="api-v2.1-filetags-view"),
|
||||||
url(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/tags/(?P<name>.*?)/$', FileTagView.as_view(), name="api-v2.1-filetag-view"),
|
url(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/tags/(?P<name>.*?)/$', FileTagView.as_view(), name="api-v2.1-filetag-view"),
|
||||||
|
Reference in New Issue
Block a user