mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-07 18:03:48 +00:00
Merge branch '11.0'
Conflicts: frontend/src/components/search/search.js frontend/src/css/search.css
This commit is contained in:
@@ -13,6 +13,7 @@ import toaster from '../toast';
|
|||||||
import Loading from '../loading';
|
import Loading from '../loading';
|
||||||
import { SEARCH_MASK, SEARCH_CONTAINER } from '../../constants/zIndexes';
|
import { SEARCH_MASK, SEARCH_CONTAINER } from '../../constants/zIndexes';
|
||||||
import { PRIVATE_FILE_TYPE } from '../../constants';
|
import { PRIVATE_FILE_TYPE } from '../../constants';
|
||||||
|
import Icon from '../icon';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
repoID: PropTypes.string,
|
repoID: PropTypes.string,
|
||||||
@@ -23,7 +24,7 @@ const propTypes = {
|
|||||||
isViewFile: PropTypes.bool,
|
isViewFile: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
const PER_PAGE = 10;
|
const PER_PAGE = 20;
|
||||||
const controlKey = Utils.isMac() ? '⌘' : 'Ctrl';
|
const controlKey = Utils.isMac() ? '⌘' : 'Ctrl';
|
||||||
|
|
||||||
const isEnter = isHotkey('enter');
|
const isEnter = isHotkey('enter');
|
||||||
@@ -478,20 +479,6 @@ class Search extends Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onResultListScroll = (e) => {
|
|
||||||
// Load less than 100 results
|
|
||||||
if (!this.state.hasMore || this.state.isLoading || this.state.resultItems.length > 100) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const listPadding = 20;
|
|
||||||
if (e.target.scrollTop + e.target.clientHeight + listPadding > this.searchResultListRef.current.clientHeight - 10) {
|
|
||||||
this.setState({isLoading: true}, () => {
|
|
||||||
this.source = seafileAPI.getSource();
|
|
||||||
this.sendRequest(this.queryData, this.source.token, this.state.page);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
updateSearchPageURL(queryData) {
|
updateSearchPageURL(queryData) {
|
||||||
let params = '';
|
let params = '';
|
||||||
for (let key in queryData) {
|
for (let key in queryData) {
|
||||||
@@ -683,7 +670,8 @@ class Search extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
renderResults = (resultItems, isVisited) => {
|
renderResults = (resultItems, isVisited) => {
|
||||||
const { highlightIndex } = this.state;
|
const { highlightIndex, hasMore, searchPageUrl } = this.state;
|
||||||
|
|
||||||
const results = (
|
const results = (
|
||||||
<>
|
<>
|
||||||
{isVisited && <h4 className="visited-search-results-title">{gettext('Search results visited recently')}</h4>}
|
{isVisited && <h4 className="visited-search-results-title">{gettext('Search results visited recently')}</h4>}
|
||||||
@@ -701,6 +689,12 @@ class Search extends Component {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
|
{(!this.props.isPublic && hasMore) &&
|
||||||
|
<div className="more-search-result mb-1 pl-2 d-flex align-items-center">
|
||||||
|
<Icon symbol="more-level" className="more-search-result-icon" />
|
||||||
|
<a href={searchPageUrl} className="more-search-result-text ml-1">{gettext('More')}</a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -754,7 +748,6 @@ class Search extends Component {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="search-result-container dropdown-search-result-container"
|
className="search-result-container dropdown-search-result-container"
|
||||||
onScroll={this.onResultListScroll}
|
|
||||||
ref={this.searchContainer}
|
ref={this.searchContainer}
|
||||||
>
|
>
|
||||||
{this.renderSearchResult()}
|
{this.renderSearchResult()}
|
||||||
@@ -787,7 +780,7 @@ class Search extends Component {
|
|||||||
<button type="button" className="search-icon-right input-icon-addon sf3-font sf3-font-x-01 border-0 bg-transparent" onClick={this.onCloseHandler} aria-label={gettext('Close')}></button>
|
<button type="button" className="search-icon-right input-icon-addon sf3-font sf3-font-x-01 border-0 bg-transparent" onClick={this.onCloseHandler} aria-label={gettext('Close')}></button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className="search-result-container dropdown-search-result-container" onScroll={this.onResultListScroll}>
|
<div className="search-result-container dropdown-search-result-container">
|
||||||
{this.renderSearchResult()}
|
{this.renderSearchResult()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -416,3 +416,18 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-result-container .more-search-result {
|
||||||
|
margin-top: -4px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-container .more-search-result-icon {
|
||||||
|
width: 1rem;
|
||||||
|
color: #ec8000;
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-container .more-search-result-text {
|
||||||
|
font-size: .875rem;
|
||||||
|
}
|
||||||
|
@@ -36,6 +36,8 @@ logger = logging.getLogger(__name__)
|
|||||||
SAML_PROVIDER_IDENTIFIER = getattr(settings, 'SAML_PROVIDER_IDENTIFIER', 'saml')
|
SAML_PROVIDER_IDENTIFIER = getattr(settings, 'SAML_PROVIDER_IDENTIFIER', 'saml')
|
||||||
SHIBBOLETH_AFFILIATION_ROLE_MAP = getattr(settings, 'SHIBBOLETH_AFFILIATION_ROLE_MAP', {})
|
SHIBBOLETH_AFFILIATION_ROLE_MAP = getattr(settings, 'SHIBBOLETH_AFFILIATION_ROLE_MAP', {})
|
||||||
CACHE_KEY_GROUPS = "all_groups_cache"
|
CACHE_KEY_GROUPS = "all_groups_cache"
|
||||||
|
LDAP_PROVIDER = getattr(settings, 'LDAP_PROVIDER', 'ldap')
|
||||||
|
SSO_LDAP_USE_SAME_UID = getattr(settings, 'SSO_LDAP_USE_SAME_UID', False)
|
||||||
|
|
||||||
|
|
||||||
class Saml2Backend(ModelBackend):
|
class Saml2Backend(ModelBackend):
|
||||||
@@ -58,6 +60,8 @@ class Saml2Backend(ModelBackend):
|
|||||||
name_id = name_id.text
|
name_id = name_id.text
|
||||||
|
|
||||||
saml_user = SocialAuthUser.objects.get_by_provider_and_uid(SAML_PROVIDER_IDENTIFIER, name_id)
|
saml_user = SocialAuthUser.objects.get_by_provider_and_uid(SAML_PROVIDER_IDENTIFIER, name_id)
|
||||||
|
if not saml_user and SSO_LDAP_USE_SAME_UID:
|
||||||
|
saml_user = SocialAuthUser.objects.get_by_provider_and_uid(LDAP_PROVIDER, name_id)
|
||||||
if saml_user:
|
if saml_user:
|
||||||
user = self.get_user(saml_user.username)
|
user = self.get_user(saml_user.username)
|
||||||
if not user:
|
if not user:
|
||||||
|
@@ -737,6 +737,9 @@ class AdminUsers(APIView):
|
|||||||
users = all_ldap_users[start: start + per_page]
|
users = all_ldap_users[start: start + per_page]
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
|
email_list = [user.email for user in users]
|
||||||
|
social_auth_user_queryset = SocialAuthUser.objects.filter(username__in=email_list)
|
||||||
|
|
||||||
for user in users:
|
for user in users:
|
||||||
profile = Profile.objects.get_profile_by_user(user.email)
|
profile = Profile.objects.get_profile_by_user(user.email)
|
||||||
|
|
||||||
@@ -785,6 +788,9 @@ class AdminUsers(APIView):
|
|||||||
else:
|
else:
|
||||||
info['institution'] = ''
|
info['institution'] = ''
|
||||||
|
|
||||||
|
social_auth_user = social_auth_user_queryset.filter(username=user.email)
|
||||||
|
info['social_auth'] = [{'provider': item.provider, 'uid': item.uid} for item in social_auth_user]
|
||||||
|
|
||||||
data.append(info)
|
data.append(info)
|
||||||
|
|
||||||
result = {'data': data, 'total_count': total_count}
|
result = {'data': data, 'total_count': total_count}
|
||||||
@@ -1429,7 +1435,7 @@ class AdminUser(APIView):
|
|||||||
try:
|
try:
|
||||||
send_html_email(_(u'Your account on %s is activated') % get_site_name(),
|
send_html_email(_(u'Your account on %s is activated') % get_site_name(),
|
||||||
'sysadmin/user_activation_email.html',
|
'sysadmin/user_activation_email.html',
|
||||||
{'username': user_obj.email},
|
{'username': email2contact_email(user_obj.email)},
|
||||||
None,
|
None,
|
||||||
[email2contact_email(user_obj.email)])
|
[email2contact_email(user_obj.email)])
|
||||||
update_status_tip = _('Edit succeeded, an email has been sent.')
|
update_status_tip = _('Edit succeeded, an email has been sent.')
|
||||||
|
@@ -20,6 +20,9 @@ import seahub.settings as settings
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
LDAP_PROVIDER = getattr(settings, 'LDAP_PROVIDER', 'ldap')
|
||||||
|
SSO_LDAP_USE_SAME_UID = getattr(settings, 'SSO_LDAP_USE_SAME_UID', False)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
current_path = os.path.dirname(os.path.abspath(__file__))
|
current_path = os.path.dirname(os.path.abspath(__file__))
|
||||||
seafile_conf_dir = os.path.join(current_path, '../../../../conf')
|
seafile_conf_dir = os.path.join(current_path, '../../../../conf')
|
||||||
@@ -176,6 +179,8 @@ def oauth_callback(request):
|
|||||||
old_email = oauth_user_info.get('email', '')
|
old_email = oauth_user_info.get('email', '')
|
||||||
|
|
||||||
oauth_user = SocialAuthUser.objects.get_by_provider_and_uid(OAUTH_PROVIDER, uid)
|
oauth_user = SocialAuthUser.objects.get_by_provider_and_uid(OAUTH_PROVIDER, uid)
|
||||||
|
if not oauth_user and SSO_LDAP_USE_SAME_UID:
|
||||||
|
oauth_user = SocialAuthUser.objects.get_by_provider_and_uid(LDAP_PROVIDER, uid)
|
||||||
if oauth_user:
|
if oauth_user:
|
||||||
email = oauth_user.username
|
email = oauth_user.username
|
||||||
is_new_user = False
|
is_new_user = False
|
||||||
|
@@ -340,6 +340,8 @@ LDAP_CONTACT_EMAIL_ATTR = ''
|
|||||||
LDAP_USER_ROLE_ATTR = ''
|
LDAP_USER_ROLE_ATTR = ''
|
||||||
ACTIVATE_USER_WHEN_IMPORT = True
|
ACTIVATE_USER_WHEN_IMPORT = True
|
||||||
|
|
||||||
|
SSO_LDAP_USE_SAME_UID = False
|
||||||
|
|
||||||
# enable ldap sasl auth
|
# enable ldap sasl auth
|
||||||
ENABLE_SASL = False
|
ENABLE_SASL = False
|
||||||
SASL_MECHANISM = ''
|
SASL_MECHANISM = ''
|
||||||
|
Reference in New Issue
Block a user