1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-08-02 07:47:32 +00:00

update search user web api (#6928)

only return active users
This commit is contained in:
lian 2024-11-09 16:34:11 +08:00 committed by GitHub
parent 3235466eb3
commit f316cbd2a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 114 additions and 136 deletions

View File

@ -1,7 +1,6 @@
# Copyright (c) 2012-2016 Seafile Ltd.
import os
import sys
import json
import logging
from django.db.models import Q
@ -18,12 +17,13 @@ from seaserv import ccnet_api
from seahub.api2.authentication import TokenAuthentication
from seahub.api2.throttling import UserRateThrottle
from seahub.api2.utils import api_error
from seahub.utils import is_valid_email, is_org_context
from seahub.utils.ccnet_db import CcnetDB
from seahub.base.accounts import User
from seahub.base.templatetags.seahub_tags import email2nickname, \
email2contact_email
from seahub.profile.models import Profile
from seahub.contacts.models import Contact
from seahub.avatar.templatetags.avatar_tags import api_avatar_url
from seahub.settings import ENABLE_GLOBAL_ADDRESSBOOK, \
@ -38,12 +38,11 @@ except ImportError:
try:
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')
sys.path.append(seafile_conf_dir)
from seahub_custom_functions import custom_search_user
CUSTOM_SEARCH_USER = True
except ImportError as e:
except ImportError:
CUSTOM_SEARCH_USER = False
@ -84,6 +83,10 @@ class SearchUser(APIView):
limited_emails = []
for org_user in all_org_users:
if not org_user.is_active:
continue
# prepare limited emails for search from profile
limited_emails.append(org_user.email)
@ -121,18 +124,7 @@ class SearchUser(APIView):
# remove duplicate emails
# get_emailusers_in_list can only accept 20 users at most
email_list = list({}.fromkeys(email_list).keys())[:20]
email_result = []
# remove nonexistent or inactive user
email_list_json = json.dumps(email_list)
user_obj_list = ccnet_api.get_emailusers_in_list('DB', email_list_json) + \
ccnet_api.get_emailusers_in_list('LDAP', email_list_json)
for user_obj in user_obj_list:
if user_obj.is_active:
email_result.append(user_obj.email)
email_result = list({}.fromkeys(email_list).keys())[:20]
# specific search `q`
user_q_obj = ccnet_api.get_emailuser(q)
@ -194,21 +186,16 @@ def format_searched_user_result(request, users, size):
return results
def search_user_from_ccnet(q):
def search_user_from_ccnet(q, offset=0, limit=10):
""" Return 10 items at most.
"""
users = []
db_users = ccnet_api.search_emailusers('DB', q, 0, 10)
users.extend(db_users)
ccnet_db = CcnetDB()
users, count = ccnet_db.list_eligible_users(offset, limit,
is_active=True, q=q)
count = len(users)
if count < 10:
ldap_imported_users = ccnet_api.search_emailusers('LDAP', q, 0, 10 - count)
users.extend(ldap_imported_users)
count = len(users)
if count < 10 and ENABLE_SEARCH_FROM_LDAP_DIRECTLY:
all_ldap_users = ccnet_api.search_ldapusers(q, 0, 10 - count)
users.extend(all_ldap_users)
@ -221,29 +208,44 @@ def search_user_from_ccnet(q):
return email_list
def search_user_from_profile(q):
""" Return 10 items at most.
def search_user_from_profile(q, offset=0, limit=10, max_attempts=10):
"""Return a list of email addresses, with a length of at least 10.
If not enough results are found, continue searching up to max_attempts times.
"""
# 'nickname__icontains' for search by nickname
# 'contact_email__icontains' for search by contact email
users = Profile.objects.filter(Q(nickname__icontains=q) | \
Q(contact_email__icontains=q) | \
Q(login_id__icontains=q)).values('user')[:10]
email_list = []
for user in users:
email_list.append(user['user'])
attempts = 0
return email_list
ccnet_db = CcnetDB()
while len(email_list) < 10 and attempts < max_attempts:
# Search by nickname, contact email, or login ID
users = Profile.objects.filter(
Q(nickname__icontains=q) |
Q(contact_email__icontains=q) |
Q(login_id__icontains=q)
).values('user')[offset:offset + limit]
new_emails = ccnet_db.get_active_users_by_user_list([user['user'] for user in users])
email_list.extend([email for email in new_emails if email not in email_list])
offset += limit
attempts += 1
return email_list[:10]
def search_user_from_profile_with_limits(q, limited_emails):
""" Return 10 items at most.
"""
# search within limited_emails
users = Profile.objects.filter(Q(user__in=limited_emails) & (Q(nickname__icontains=q) | \
Q(contact_email__icontains=q) | \
Q(login_id__icontains=q))).values('user')[:10]
users = Profile.objects.filter(
Q(user__in=limited_emails) & (
Q(nickname__icontains=q) |
Q(contact_email__icontains=q) |
Q(login_id__icontains=q)
)
).values('user')[:10]
email_list = []
for user in users:
@ -259,23 +261,6 @@ def search_user_when_global_address_book_disabled(request, q):
email_list = []
username = request.user.username
# search from contact
# get user's contact list
contacts = Contact.objects.get_contacts_by_user(username)
for contact in contacts:
# search user from contact list
if q in contact.contact_email:
email_list.append(contact.contact_email)
# search from profile, limit search range in user's contacts
limited_emails = []
for contact in contacts:
limited_emails.append(contact.contact_email)
email_list += search_user_from_profile_with_limits(q, limited_emails)
current_user = User.objects.get(email=username)
if current_user.role.lower() != 'guest':

View File

@ -27,12 +27,12 @@ MANAGERS = ADMINS
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': '%s/seahub/seahub.db' % PROJECT_ROOT, # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
'ENGINE': 'django.db.backends.mysql',
'NAME': 'seahub',
'USER': 'root',
'PASSWORD': 'root',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import os
import configparser
from django.db import connection
def get_ccnet_db_name():
@ -24,11 +25,6 @@ def get_ccnet_db_name():
return db_name, None
import os
import configparser
from django.db import connection
class CcnetGroup(object):
def __init__(self, **kwargs):
@ -89,22 +85,28 @@ class CcnetDB:
groups.append(group_obj)
return groups
def list_eligible_users(self, start, limit, is_active=None, role=None):
def list_eligible_users(self, start, limit,
is_active=None, role=None, q=None):
def status(is_active):
return 'AND t1.is_active=%s ' % is_active
return f'AND t1.is_active={is_active} '
def is_role(role):
if role == 'default':
return 'AND (t2.role is null or t2.role = "default") '
else:
return 'AND t2.role = "%s"' % role
return f'AND t2.role = "{role}" '
def search(q):
return f'AND t1.email LIKE "%{q}%" '
search_clause = ''
if is_active:
search_clause += status(is_active)
if role:
search_clause += is_role(role)
if q:
search_clause += search(q)
count_sql = f"""
SELECT count(1)
@ -130,11 +132,10 @@ class CcnetDB:
WHERE
t1.email NOT LIKE '%%@seafile_group' %s
ORDER BY t1.id
LIMIT {limit} OFFSET {start}
LIMIT {limit} OFFSET {start};
""" % search_clause
users = []
total = 0
with connection.cursor() as cursor:
cursor.execute(count_sql)
cursor.execute(count_sql)
@ -216,4 +217,5 @@ class CcnetDB:
cursor.execute(sql)
for user in cursor.fetchall():
active_users.append(user[0])
return active_users

View File

@ -331,7 +331,6 @@ class SeafileDB:
""" % self.db_name
cursor.execute(del_trash_sql, (repo_ids,))
sql_list_repo_id = f"""
SELECT
t.repo_id

View File

@ -4,13 +4,13 @@ from mock import patch
from django.urls import reverse
from django.test import override_settings
from seahub.contacts.models import Contact
from seahub.profile.models import Profile
from seahub.profile.utils import refresh_cache
from seahub.api2.endpoints.search_user import SearchUser
from seahub.test_utils import BaseTestCase
from tests.common.utils import randstring
class SearchUserTest(BaseTestCase):
def setUp(self):
self.login_as(self.user)
@ -210,19 +210,10 @@ class SearchUserTest(BaseTestCase):
resp = self.client.get(self.endpoint + '?q=%s' % contact_email)
json_resp = json.loads(resp.content)
self.assertEqual(200, resp.status_code)
assert json_resp['users'][0]['email'] == self.admin.username
assert json_resp['users'][0]['email'] == contact_email
# search with invalid email & has no contacts
resp = self.client.get(self.endpoint + '?q=%s' % contact_email[:6])
json_resp = json.loads(resp.content)
self.assertEqual(200, resp.status_code)
assert len(json_resp['users']) == 0
# search with invalid email & has contact
nickname_of_admin = randstring(6)
Contact.objects.add_contact(self.user.username, self.admin.username)
Profile.objects.add_or_update(self.admin.username, nickname=nickname_of_admin)
resp = self.client.get(self.endpoint + '?q=%s' % nickname_of_admin)
json_resp = json.loads(resp.content)
self.assertEqual(200, resp.status_code)
assert json_resp['users'][0]['email'] == self.admin.username

View File

@ -1,5 +1,6 @@
from seahub.test_utils import BaseTestCase
from seahub.api2.models import TokenV2, TokenV2Manager
from seahub.api2.models import TokenV2
class TokenV2ManagerTest(BaseTestCase):
def setUp(self):
@ -37,7 +38,7 @@ class TokenV2ManagerTest(BaseTestCase):
self.admin.username, self.token.platform, self.token.device_id,
self.token.device_name, '1.1.1', '0.1.1', self.ip_v6)
assert len(TokenV2.objects.all()) == 2
assert TokenV2.objects.all()[1].user == self.admin.username
assert self.admin.username in [item.user for item in TokenV2.objects.all()]
def test_delete_device_token(self):
TokenV2.objects.delete_device_token(