mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-12 21:30:39 +00:00
@@ -4,7 +4,7 @@ import isHotkey from 'is-hotkey';
|
|||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import MediaQuery from 'react-responsive';
|
import MediaQuery from 'react-responsive';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { gettext, siteRoot } from '../../utils/constants';
|
import { gettext, siteRoot, username } from '../../utils/constants';
|
||||||
import SearchResultItem from './search-result-item';
|
import SearchResultItem from './search-result-item';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import { isMac } from '../../utils/extra-attributes';
|
import { isMac } from '../../utils/extra-attributes';
|
||||||
@@ -35,6 +35,7 @@ export default class AISearch extends Component {
|
|||||||
placeholder: PropTypes.string,
|
placeholder: PropTypes.string,
|
||||||
onSearchedClick: PropTypes.func.isRequired,
|
onSearchedClick: PropTypes.func.isRequired,
|
||||||
repoName: PropTypes.string,
|
repoName: PropTypes.string,
|
||||||
|
currentRepoInfo: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -66,6 +67,8 @@ export default class AISearch extends Component {
|
|||||||
this.indexStateTimer = null;
|
this.indexStateTimer = null;
|
||||||
this.timer = null;
|
this.timer = null;
|
||||||
this.isChineseInput = false;
|
this.isChineseInput = false;
|
||||||
|
this.isRepoOwner = props.currentRepoInfo.owner_email === username;
|
||||||
|
this.isAdmin = props.currentRepoInfo.is_admin;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@@ -517,7 +520,7 @@ export default class AISearch extends Component {
|
|||||||
this.setState({ indexState: INDEX_STATE.RUNNING });
|
this.setState({ indexState: INDEX_STATE.RUNNING });
|
||||||
seafileAPI.createLibraryIndex(this.props.repoID).then(res => {
|
seafileAPI.createLibraryIndex(this.props.repoID).then(res => {
|
||||||
const taskId = res.data.task_id;
|
const taskId = res.data.task_id;
|
||||||
toaster.notify(gettext('Indexing the library. Semantic search will be available within a few minutes.'))
|
toaster.notify(gettext('Indexing the library. Semantic search will be available within a few minutes.'));
|
||||||
this.queryIndexTaskStatus(taskId);
|
this.queryIndexTaskStatus(taskId);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
const errorMsg = Utils.getErrorMsg(error);
|
const errorMsg = Utils.getErrorMsg(error);
|
||||||
@@ -526,9 +529,19 @@ export default class AISearch extends Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onDeleteIndex = () => {
|
||||||
|
seafileAPI.deleteLibraryIndex(this.props.repoID).then(res => {
|
||||||
|
toaster.notify(gettext('Successfully turned off'));
|
||||||
|
this.setState({ indexState: INDEX_STATE.UNCREATED });
|
||||||
|
}).catch(error => {
|
||||||
|
const errorMsg = Utils.getErrorMsg(error);
|
||||||
|
toaster.danger(errorMsg);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
renderSwitch = () => {
|
renderSwitch = () => {
|
||||||
const { indexState } = this.state;
|
const { indexState } = this.state;
|
||||||
if (indexState === INDEX_STATE.FINISHED || indexState === INDEX_STATE.RUNNING) {
|
if (indexState === INDEX_STATE.RUNNING) {
|
||||||
return (
|
return (
|
||||||
<Switch
|
<Switch
|
||||||
checked={true}
|
checked={true}
|
||||||
@@ -539,6 +552,17 @@ export default class AISearch extends Component {
|
|||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
} else if (indexState === INDEX_STATE.FINISHED) {
|
||||||
|
return (
|
||||||
|
<Switch
|
||||||
|
checked={true}
|
||||||
|
placeholder={gettext('Turn off semantic search for this library')}
|
||||||
|
className="w-100 mt-1"
|
||||||
|
size="small"
|
||||||
|
onChange={this.onDeleteIndex}
|
||||||
|
textPosition='right'
|
||||||
|
/>
|
||||||
|
);
|
||||||
} else if (indexState === '' || indexState === INDEX_STATE.UNCREATED) {
|
} else if (indexState === '' || indexState === INDEX_STATE.UNCREATED) {
|
||||||
return (
|
return (
|
||||||
<Switch
|
<Switch
|
||||||
@@ -603,7 +627,7 @@ export default class AISearch extends Component {
|
|||||||
onScroll={this.onResultListScroll}
|
onScroll={this.onResultListScroll}
|
||||||
ref={this.searchContainer}
|
ref={this.searchContainer}
|
||||||
>
|
>
|
||||||
{isCloseShow && this.renderSwitch()}
|
{isCloseShow && (this.isRepoOwner || this.isAdmin) && this.renderSwitch()}
|
||||||
{this.renderSearchResult()}
|
{this.renderSearchResult()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -13,7 +13,8 @@ const propTypes = {
|
|||||||
repoName: PropTypes.string,
|
repoName: PropTypes.string,
|
||||||
isLibView: PropTypes.bool,
|
isLibView: PropTypes.bool,
|
||||||
onSearchedClick: PropTypes.func.isRequired,
|
onSearchedClick: PropTypes.func.isRequired,
|
||||||
searchPlaceholder: PropTypes.string
|
searchPlaceholder: PropTypes.string,
|
||||||
|
currentRepoInfo: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
class CommonToolbar extends React.Component {
|
class CommonToolbar extends React.Component {
|
||||||
@@ -30,6 +31,7 @@ class CommonToolbar extends React.Component {
|
|||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
onSearchedClick={this.props.onSearchedClick}
|
onSearchedClick={this.props.onSearchedClick}
|
||||||
repoName={repoName}
|
repoName={repoName}
|
||||||
|
currentRepoInfo={this.props.currentRepoInfo}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@@ -142,6 +142,7 @@ class LibContentToolbar extends React.Component {
|
|||||||
isLibView={true}
|
isLibView={true}
|
||||||
repoID={this.props.repoID}
|
repoID={this.props.repoID}
|
||||||
repoName={this.props.repoName}
|
repoName={this.props.repoName}
|
||||||
|
currentRepoInfo={this.props.currentRepoInfo}
|
||||||
onSearchedClick={this.props.onSearchedClick}
|
onSearchedClick={this.props.onSearchedClick}
|
||||||
searchPlaceholder={gettext('Search files')}
|
searchPlaceholder={gettext('Search files')}
|
||||||
/>
|
/>
|
||||||
|
@@ -14,8 +14,7 @@ from seahub.api2.throttling import UserRateThrottle
|
|||||||
from seahub.api2.authentication import TokenAuthentication, SeafileAiAuthentication
|
from seahub.api2.authentication import TokenAuthentication, SeafileAiAuthentication
|
||||||
from seahub.api2.utils import api_error
|
from seahub.api2.utils import api_error
|
||||||
|
|
||||||
from seahub.views import check_folder_permission
|
from seahub.utils.repo import is_valid_repo_id_format, is_repo_admin
|
||||||
from seahub.utils.repo import parse_repo_perm, is_valid_repo_id_format
|
|
||||||
from seahub.ai.utils import create_library_sdoc_index, search, update_library_sdoc_index, \
|
from seahub.ai.utils import create_library_sdoc_index, search, update_library_sdoc_index, \
|
||||||
delete_library_index, query_task_status, query_library_index_state, question_answering_search_in_library,\
|
delete_library_index, query_task_status, query_library_index_state, question_answering_search_in_library,\
|
||||||
get_file_download_token, get_search_repos, RELATED_REPOS_PREFIX, RELATED_REPOS_CACHE_TIMEOUT, SEARCH_REPOS_LIMIT, \
|
get_file_download_token, get_search_repos, RELATED_REPOS_PREFIX, RELATED_REPOS_CACHE_TIMEOUT, SEARCH_REPOS_LIMIT, \
|
||||||
@@ -43,10 +42,7 @@ class LibrarySdocIndexes(APIView):
|
|||||||
error_msg = 'Library %s not found.' % repo_id
|
error_msg = 'Library %s not found.' % repo_id
|
||||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
parent_dir = '/'
|
if not is_repo_admin(request.user.username, repo_id):
|
||||||
|
|
||||||
# permission check
|
|
||||||
if parse_repo_perm(check_folder_permission(request, repo_id, parent_dir)).can_download is False:
|
|
||||||
error_msg = 'Permission denied.'
|
error_msg = 'Permission denied.'
|
||||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
|
||||||
@@ -216,10 +212,7 @@ class LibrarySdocIndex(APIView):
|
|||||||
error_msg = 'Library %s not found.' % repo_id
|
error_msg = 'Library %s not found.' % repo_id
|
||||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
parent_dir = '/'
|
if not is_repo_admin(request.user.username, repo_id):
|
||||||
|
|
||||||
# permission check
|
|
||||||
if parse_repo_perm(check_folder_permission(request, repo_id, parent_dir)).can_download is False:
|
|
||||||
error_msg = 'Permission denied.'
|
error_msg = 'Permission denied.'
|
||||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
|
||||||
@@ -244,6 +237,10 @@ class LibrarySdocIndex(APIView):
|
|||||||
if not repo_id:
|
if not repo_id:
|
||||||
return api_error(status.HTTP_400_BAD_REQUEST, 'repo_id invalid')
|
return api_error(status.HTTP_400_BAD_REQUEST, 'repo_id invalid')
|
||||||
|
|
||||||
|
if not is_repo_admin(request.user.username, repo_id):
|
||||||
|
error_msg = 'Permission denied.'
|
||||||
|
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
resp = delete_library_index(repo_id)
|
resp = delete_library_index(repo_id)
|
||||||
if resp.status_code == 500:
|
if resp.status_code == 500:
|
||||||
|
Reference in New Issue
Block a user