1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-20 10:58:33 +00:00
Files
seahub/seahub/api2/endpoints/admin/users.py

900 lines
33 KiB
Python
Raw Normal View History

2017-08-28 14:52:28 +08:00
# Copyright (c) 2012-2016 Seafile Ltd.
2019-10-15 16:05:51 +08:00
import os
2017-08-28 14:52:28 +08:00
import logging
2019-10-15 16:05:51 +08:00
from types import FunctionType
from constance import config
2017-08-28 14:52:28 +08:00
from rest_framework import status
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAdminUser
from rest_framework.response import Response
from rest_framework.views import APIView
from django.core.cache import cache
2017-09-07 15:22:15 +08:00
from django.utils.translation import ugettext as _
2017-08-28 14:52:28 +08:00
from seaserv import seafile_api, ccnet_api
from seahub.api2.authentication import TokenAuthentication
from seahub.api2.throttling import UserRateThrottle
from seahub.api2.utils import api_error, to_python_boolean
import seahub.settings as settings
2019-10-15 16:05:51 +08:00
from seahub.settings import SEND_EMAIL_ON_ADDING_SYSTEM_MEMBER, INIT_PASSWD, \
SEND_EMAIL_ON_RESETTING_USER_PASSWD
from seahub.base.templatetags.seahub_tags import email2nickname, email2contact_email
2017-08-28 14:52:28 +08:00
from seahub.base.accounts import User
2019-10-15 16:05:51 +08:00
from seahub.base.models import UserLastLogin
from seahub.two_factor.models import default_device
2017-08-28 14:52:28 +08:00
from seahub.profile.models import Profile, DetailedProfile
from seahub.profile.settings import CONTACT_CACHE_TIMEOUT, CONTACT_CACHE_PREFIX
2017-08-28 14:52:28 +08:00
from seahub.utils import is_valid_username, is_org_context, \
is_pro_version, normalize_cache_key, is_valid_email, \
IS_EMAIL_CONFIGURED, send_html_email, get_site_name
2017-08-28 14:52:28 +08:00
from seahub.utils.file_size import get_file_size_unit
2019-10-15 16:05:51 +08:00
from seahub.utils.timeutils import timestamp_to_isoformat_timestr
from seahub.utils.user_permissions import get_user_role
2019-10-15 16:05:51 +08:00
from seahub.utils.repo import normalize_repo_status_code
from seahub.constants import DEFAULT_ADMIN
from seahub.role_permissions.models import AdminRole
2017-08-28 14:52:28 +08:00
from seahub.role_permissions.utils import get_available_roles
from seahub.utils.licenseparse import user_number_over_limit
2017-08-28 14:52:28 +08:00
2019-10-15 16:05:51 +08:00
from seahub.options.models import UserOptions
from seahub.share.models import FileShare, UploadLinkShare
2017-08-28 14:52:28 +08:00
logger = logging.getLogger(__name__)
json_content_type = 'application/json; charset=utf-8'
2019-10-15 16:05:51 +08:00
def get_user_upload_link_info(uls):
data = {}
repo_id = uls.repo_id
try:
repo = seafile_api.get_repo(repo_id)
except Exception as e:
logger.error(e)
repo = None
path = uls.path
if path:
obj_name = '/' if path == '/' else os.path.basename(path.rstrip('/'))
else:
obj_name = ''
data['repo_name'] = repo.repo_name if repo else ''
data['path'] = path
data['obj_name'] = obj_name
data['view_cnt'] = uls.view_cnt
return data
def get_user_share_link_info(fileshare):
data = {}
repo_id = fileshare.repo_id
try:
repo = seafile_api.get_repo(repo_id)
except Exception as e:
logger.error(e)
repo = None
path = fileshare.path
if path:
obj_name = '/' if path == '/' else os.path.basename(path.rstrip('/'))
else:
obj_name = ''
data['repo_name'] = repo.repo_name if repo else ''
data['path'] = path
data['obj_name'] = obj_name
data['is_dir'] = True if fileshare.s_type == 'd' else False
data['view_cnt'] = fileshare.view_cnt
if fileshare.s_type == 'f':
obj_id = seafile_api.get_file_id_by_path(repo_id, path)
data['size'] = seafile_api.get_file_size(repo.store_id,
repo.version, obj_id)
else:
data['size'] = ''
return data
def update_user_info(request, user):
2017-08-28 14:52:28 +08:00
# update basic user info
password = request.data.get("password")
if password:
user.set_password(password)
is_staff = request.data.get("is_staff")
if is_staff:
is_staff = to_python_boolean(is_staff)
user.is_staff = is_staff
is_active = request.data.get("is_active")
if is_active:
is_active = to_python_boolean(is_active)
user.is_active = is_active
2019-10-15 16:05:51 +08:00
if user.is_active:
try:
send_html_email(_(u'Your account on %s is activated') % get_site_name(),
'sysadmin/user_activation_email.html', {'username': user.email}, None, [user.email])
except Exception as e:
logger.error(e)
2017-08-28 14:52:28 +08:00
# update user
user.save()
email = user.username
2017-08-28 14:52:28 +08:00
# update additional user info
if is_pro_version():
role = request.data.get("role")
if role:
User.objects.update_role(email, role)
nickname = request.data.get("name", None)
if nickname is not None:
Profile.objects.add_or_update(email, nickname)
2017-08-28 14:52:28 +08:00
2017-09-07 15:22:15 +08:00
# update account login_id
login_id = request.data.get("login_id", None)
if login_id is not None:
Profile.objects.add_or_update(email, login_id=login_id)
# update account contact email
contact_email = request.data.get('contact_email', None)
if contact_email is not None:
Profile.objects.add_or_update(email, contact_email=contact_email)
key = normalize_cache_key(email, CONTACT_CACHE_PREFIX)
cache.set(key, contact_email, CONTACT_CACHE_TIMEOUT)
2017-09-07 15:22:15 +08:00
reference_id = request.data.get("reference_id", None)
if reference_id is not None:
2018-05-15 14:19:03 +08:00
if reference_id.strip():
ccnet_api.set_reference_id(email, reference_id.strip())
else:
# remove reference id
ccnet_api.set_reference_id(email, None)
2017-09-07 15:22:15 +08:00
2017-08-28 14:52:28 +08:00
department = request.data.get("department")
if department:
d_profile = DetailedProfile.objects.get_detailed_profile_by_user(email)
if d_profile is None:
d_profile = DetailedProfile(user=email)
d_profile.department = department
d_profile.save()
quota_total_mb = request.data.get("quota_total")
if quota_total_mb:
quota_total = int(quota_total_mb) * get_file_size_unit('MB')
if is_org_context(request):
org_id = request.user.org.org_id
seafile_api.set_org_user_quota(org_id, email, quota_total)
else:
seafile_api.set_user_quota(email, quota_total)
def get_user_info(email):
user = User.objects.get(email=email)
d_profile = DetailedProfile.objects.get_detailed_profile_by_user(email)
2017-09-07 15:22:15 +08:00
profile = Profile.objects.get_profile_by_user(email)
2017-08-28 14:52:28 +08:00
info = {}
info['email'] = email
info['name'] = email2nickname(email)
info['contact_email'] = profile.contact_email if profile and profile.contact_email else ''
2017-09-07 15:22:15 +08:00
info['login_id'] = profile.login_id if profile and profile.login_id else ''
2017-08-28 14:52:28 +08:00
info['is_staff'] = user.is_staff
info['is_active'] = user.is_active
2017-09-07 15:22:15 +08:00
info['reference_id'] = user.reference_id if user.reference_id else ''
2017-08-28 14:52:28 +08:00
info['department'] = d_profile.department if d_profile else ''
info['quota_total'] = seafile_api.get_user_quota(email)
info['quota_usage'] = seafile_api.get_user_self_usage(email)
info['create_time'] = timestamp_to_isoformat_timestr(user.ctime)
2019-10-15 16:05:51 +08:00
info['has_default_device'] = True if default_device(user) else False
info['is_force_2fa'] = UserOptions.objects.is_force_2fa(email)
2017-08-28 14:52:28 +08:00
if is_pro_version():
info['role'] = user.role
return info
2019-10-15 16:05:51 +08:00
class AdminAdminUsers(APIView):
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAdminUser, )
throttle_classes = (UserRateThrottle, )
def get(self, request):
"""List all admins from database and ldap imported
"""
try:
db_users = ccnet_api.get_emailusers('DB', -1, -1)
ldap_imported_users = ccnet_api.get_emailusers('LDAPImport', -1, -1)
except Exception as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
admin_users = []
for user in db_users + ldap_imported_users:
if user.is_staff is True:
admin_users.append(user)
admin_users_info = []
for user in admin_users:
user_info = {}
profile = Profile.objects.get_profile_by_user(user.email)
user_info['email'] = user.email
user_info['name'] = email2nickname(user.email)
user_info['contact_email'] = email2contact_email(user.email)
2019-10-15 16:05:51 +08:00
user_info['login_id'] = profile.login_id if profile and profile.login_id else ''
user_info['is_staff'] = user.is_staff
user_info['is_active'] = user.is_active
orgs = ccnet_api.get_orgs_by_user(user.email)
try:
if orgs:
org_id = orgs[0].org_id
user_info['org_id'] = org_id
user_info['org_name'] = orgs[0].org_name
user_info['quota_usage'] = seafile_api.get_org_user_quota_usage(org_id, user.email)
user_info['quota_total'] = seafile_api.get_org_user_quota(org_id, user.email)
else:
user_info['quota_usage'] = seafile_api.get_user_self_usage(user.email)
user_info['quota_total'] = seafile_api.get_user_quota(user.email)
except Exception as e:
logger.error(e)
user_info['quota_usage'] = -1
user_info['quota_total'] = -1
2019-10-15 16:05:51 +08:00
user_info['create_time'] = timestamp_to_isoformat_timestr(user.ctime)
user_info['last_login'] = UserLastLogin.objects.get_by_username(user.email).last_login if UserLastLogin.objects.get_by_username(user.email) else ''
try:
admin_role = AdminRole.objects.get_admin_role(user.email)
user_info['admin_role'] = admin_role.role
except AdminRole.DoesNotExist:
user_info['admin_role'] = DEFAULT_ADMIN
admin_users_info.append(user_info)
result = {
'admin_user_list': admin_users_info,
}
return Response(result)
2017-08-28 14:52:28 +08:00
class AdminUsers(APIView):
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAdminUser, )
throttle_classes = (UserRateThrottle, )
def get(self, request):
"""List all users in DB or LDAPImport
Permission checking:
1. only admin can perform this action.
"""
2017-08-28 14:52:28 +08:00
try:
page = int(request.GET.get('page', '1'))
per_page = int(request.GET.get('per_page', '25'))
except ValueError:
page = 1
per_page = 25
start = (page - 1) * per_page
# source: 'DB' or 'LDAPImport', default is 'DB'
source = request.GET.get('source', 'DB')
source = source.lower()
if source not in ['db', 'ldapimport']:
error_msg = 'source %s invalid.' % source
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
if source == 'db':
users = ccnet_api.get_emailusers('DB', start, per_page)
total_count = ccnet_api.count_emailusers('DB') + \
ccnet_api.count_inactive_emailusers('DB')
elif source == 'ldapimport':
users = ccnet_api.get_emailusers('LDAPImport', start, per_page)
# api param is 'LDAP', but actually get count of 'LDAPImport' users
total_count = ccnet_api.count_emailusers('LDAP') + \
ccnet_api.count_inactive_emailusers('LDAP')
2017-08-28 14:52:28 +08:00
data = []
for user in users:
2019-10-15 16:05:51 +08:00
profile = Profile.objects.get_profile_by_user(user.email)
2017-08-28 14:52:28 +08:00
2019-10-15 16:05:51 +08:00
info = {}
info['email'] = user.email
info['name'] = email2nickname(user.email)
info['contact_email'] = email2contact_email(user.email)
2019-10-15 16:05:51 +08:00
info['login_id'] = profile.login_id if profile and profile.login_id else ''
info['is_staff'] = user.is_staff
info['is_active'] = user.is_active
orgs = ccnet_api.get_orgs_by_user(user.email)
try:
if orgs:
org_id = orgs[0].org_id
info['org_id'] = org_id
info['org_name'] = orgs[0].org_name
info['quota_usage'] = seafile_api.get_org_user_quota_usage(org_id, user.email)
info['quota_total'] = seafile_api.get_org_user_quota(org_id, user.email)
else:
info['quota_usage'] = seafile_api.get_user_self_usage(user.email)
info['quota_total'] = seafile_api.get_user_quota(user.email)
except Exception as e:
logger.error(e)
info['quota_usage'] = -1
info['quota_total'] = -1
2019-10-15 16:05:51 +08:00
info['create_time'] = timestamp_to_isoformat_timestr(user.ctime)
info['last_login'] = UserLastLogin.objects.get_by_username(user.email).last_login if UserLastLogin.objects.get_by_username(user.email) else ''
info['role'] = get_user_role(user)
if getattr(settings, 'MULTI_INSTITUTION', False):
info['institution'] = profile.institution if profile else ''
2017-08-28 14:52:28 +08:00
2019-10-15 16:05:51 +08:00
data.append(info)
result = {'data': data, 'total_count': total_count}
return Response(result)
2017-08-28 14:52:28 +08:00
def post(self, request):
if user_number_over_limit():
error_msg = _("The number of users exceeds the limit.")
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
2017-08-28 14:52:28 +08:00
email = request.data.get('email', None)
if not email or not is_valid_username(email):
error_msg = 'email invalid.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
# basic user info check
is_staff = request.data.get("is_staff", None)
if is_staff:
try:
is_staff = to_python_boolean(is_staff)
except ValueError:
error_msg = 'is_staff invalid.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
is_active = request.data.get("is_active", None)
if is_active:
try:
is_active = to_python_boolean(is_active)
except ValueError:
error_msg = 'is_active invalid.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
# additional user info check
role = request.data.get("role", None)
if role:
available_roles = get_available_roles()
if role.lower() not in available_roles:
error_msg = 'role must be in %s.' % str(available_roles)
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
name = request.data.get("name", None)
if name:
if len(name) > 64:
error_msg = 'Name is too long (maximum is 64 characters).'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
if "/" in name:
error_msg = "Name should not include '/'."
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
department = request.data.get("department", None)
if department:
if len(department) > 512:
error_msg = "Department is too long (maximum is 512 characters)."
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
quota_total_mb = request.data.get("quota_total", None)
if quota_total_mb:
try:
quota_total_mb = int(quota_total_mb)
except ValueError:
error_msg = "Must be an integer that is greater than or equal to 0."
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
if quota_total_mb < 0:
error_msg = "Space quota is too low (minimum value is 0)."
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
if is_org_context(request):
org_id = request.user.org.org_id
org_quota_mb = seafile_api.get_org_quota(org_id) / \
get_file_size_unit('MB')
if quota_total_mb > org_quota_mb:
error_msg = 'Failed to set quota: maximum quota is %d MB' % org_quota_mb
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
try:
User.objects.get(email=email)
user_exist = True
except User.DoesNotExist:
user_exist = False
if user_exist:
error_msg = "User %s already exists." % email
2017-08-28 16:07:08 +08:00
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
2017-08-28 14:52:28 +08:00
password = request.data.get('password', None)
if not password:
error_msg = 'password required.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
# create user
try:
user_obj = User.objects.create_user(email)
update_user_info(request, user_obj)
2017-08-28 14:52:28 +08:00
except Exception as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
if IS_EMAIL_CONFIGURED and SEND_EMAIL_ON_ADDING_SYSTEM_MEMBER:
c = {'user': request.user.username, 'email': email, 'password': password}
try:
Python3 master (#4076) * delete thridpart/social_django * delete social_django in seahub/urls.py * delete social_django in seahub/settings.py * delete seahub/notifications/management/commands/send_wxwork_notices.py * delete social_django in code annotation * delete seahub/social_core * delete tests/seahub/social_core * delete social_core in seahub/urls.py * delete social_core in seahub/settings.py * change app_label to auth in SocialAuthUser model * 2to3 asserts * 2to3 basestring * 2to3 dict * 2to3 except * 2to3 filter * 2to3 future * 2to3 has_key * 2to3 idioms * 2to3 import * 2to3 imports * 2to3 long * 2to3 map * 2to3 next * 2to3 numliterals * 2to3 print * 2to3 raise * 2to3 raw_input * 2to3 reduce * 2to3 reload * 2to3 set_literal * 2to3 unicode * 2to3 urllib * 2to3 ws_comma * 2to3 xrange * 2to3 zip * add pymysql in __init__.py * fix encode and decode in seahub/cconvert.py * fix seafserv_rpc.is_passwd_set in seahub/views/__init__.py * fix smart_unicode to smart_text * fix force_unicode to force_text * delete seaserv.get_session_info * delete seaserv.ccnet_rpc * fix indent error in seahub/auth/middleware.py * update dev-requirements * update test-requirements * update requirements * fix StringIO to BytesIO in thumbnail * fix seaserv.list_inner_pub_repos to seafile_api.get_inner_pub_repo_list * fix seaserv.list_org_inner_pub_repos to seafile_api.list_org_inner_pub_repos * add logger in seahub/utils/__init__.py * fix sort cmp in seahub/views/__init__.py * fix sort cmp in seahub/base/management/commands/export_file_access_log.py * fix sort cmp in seahub/api2/endpoints/repo_trash.py * fix sort cmp in seahub/api2/endpoints/shared_repos.py * fix sort cmp in seahub/api2/endpoints/shared_folders.py * fix sort cmp in seahub/wiki/views.py * fix sort cmp in seahub/api2/endpoints/wiki_pages.py * fix sort cmp in seahub/api2/endpoints/group_libraries.py * fix sort cmp in seahub/base/models.py * fix sort cmp in seahub/api2/endpoints/upload_links.py * fix sort cmp in seahub/views/ajax.py * fix sort cmp in seahub/api2/views.py * fix sort cmp in seahub/views/wiki.py * fix sort cmp in seahub/api2/endpoints/repos.py * fix sort cmp in seahub/api2/endpoints/starred_items.py * fix sort cmp in seahub/views/file.py * fix sort cmp in seahub/api2/endpoints/dir.py * fix sort cmp in seahub/api2/endpoints/share_links.py * fix cmp to cmp_to_key in seahub/api2/endpoints/admin/device_trusted_ip.py * fix cmp to cmp_to_key in tests/api/endpoints/admin/test_device_trusted_ip.py * delete encode('utf-8') in seafile_api.list_dir_by_commit_and_path * delete encode('utf-8') in is_file_starred * delete encode('utf-8') in seafile_api.list_dir_by_path * delete path.encode('utf-8') in seahub/views/file.py * fix os.write to add encode('utf-8') * add encode('utf-8') for hashlib * add encode('utf-8') for hmac * fix with open(file, 'wb') for binary file * fix encode and decode in seahub/utils/hasher.py * fix next in thirdpart/shibboleth/views.py * fix next in seahub/profile/views.py * fix next in seahub/notifications/views.py * fix next in seahub/institutions/views.py * fix next in seahub/options/views.py * fix next in seahub/share/views.py * fix next in seahub/avatar/views.py * fix next in seahub/views/__init__.py * fix next in seahub/group/views.py * fix next in seahub/views/wiki.py * fix next in seahub/views/sysadmin.py * fix next in seahub/views/file.py * fix string.lowercase to string.ascii_lowercase in test * fix open file add 'rb' in test * fix self.user.username in test * add migrations in file_participants * fix list_org_inner_pub_repos to list_org_inner_pub_repos_by_owner * fix from seaserv import is_passwd_set to seafile_api.is_password_set * fix assert bytes resp.content in test * fix seafile_api.get_inner_pub_repo_list to seafile_api.list_inner_pub_repos_by_owner * fix seafile_api.is_passwd_set to seafile_api.is_password_set * fix AccountsApiTest assert length * rewrite sort_devices cmp to operator.lt * fix bytes + str in seahub/api2/views.py * fix assert bytes resp.content in test * fix hashlib encode in seahub/thirdpart/registration/models.py * change app_label to base in SocialAuthUser * fix base64 encode in seahub/base/database_storage/database_storage.py * fix assert bytes resp.content * remove path.decode in def mkstemp() * remove path.decode in FpathToLinkTest * remove str decode in FileTagTest * remove mock_write_xls.assert_called_once() in SysUserAdminExportExcelTest * fix urllib assert in FilesApiTest * fix link fields in FileCommentsTest * fix get_related_users_by_repo() * fix assert list in GetRepoSharedUsersTest * fix create user in AccountTest * fix repeated key in dict seahub/api2/views.py * add drone.yml * update nginx conf in test * update test conf in test * update dist and push after test success * update drone conf to dist and push * fix assert in BeSharedReposTest * fix seafile_api.list_org_inner_pub_repos_by_owner(org_id, username) to seafile_api.list_org_inner_pub_repos(org_id) * fix seafile_api.list_inner_pub_repos_by_owner(username) to seafile_api.get_inner_pub_repo_list() * update pyjwt requirement * update dist branch in drone * add SKIP in dist and push * fix StringIO to BytesIO in seahub/avatar/models.py * fix if org_id > 0 to if org_id and org_id > 0 * remove payment * fix StringIO to BytesIO in seahub/base/database_storage/database_storage.py * fix send_message to seafile_api.publish_event in seahub/drafts/utils.py * fix send_message to seafile_api.publish_event in seahub/api2/views.py * fix send_message to seafile_api.publish_event in seahub/api2/endpoints/repos.py * fix send_message to seafile_api.publish_event in seahub/views/file.py * fix send_message to seafile_api.publish_event in seahub/utils/__init__.py * fix image_file.read encode in seahub/base/database_storage/database_storage.py * fix DatabaseStorageTest * remove .travis.yml * drone branch include master
2019-09-11 11:46:43 +08:00
send_html_email(_('You are invited to join %s') % get_site_name(),
'sysadmin/user_add_email.html', c, None, [email])
except Exception as e:
logger.error(str(e))
2017-08-28 14:52:28 +08:00
user_info = get_user_info(email)
return Response(user_info)
class AdminLDAPUsers(APIView):
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAdminUser, )
throttle_classes = (UserRateThrottle, )
def get(self, request):
"""List all users from LDAP server
Permission checking:
1. only admin can perform this action.
"""
try:
page = int(request.GET.get('page', '1'))
per_page = int(request.GET.get('per_page', '25'))
except ValueError:
page = 1
per_page = 25
start = (page - 1) * per_page
end = page * per_page + 1
users = ccnet_api.get_emailusers('LDAP', start, end)
if len(users) == end - start:
users = users[:per_page]
has_next_page = True
else:
has_next_page = False
data = []
for user in users:
info = {}
info['email'] = user.email
info['quota_total'] = seafile_api.get_user_quota(user.email)
info['quota_usage'] = seafile_api.get_user_self_usage(user.email)
info['create_time'] = timestamp_to_isoformat_timestr(user.ctime)
info['last_login'] = UserLastLogin.objects.get_by_username(user.email).last_login if UserLastLogin.objects.get_by_username(user.email) else ''
data.append(info)
result = {'ldap_user_list': data, 'has_next_page': has_next_page}
return Response(result)
2017-08-28 14:52:28 +08:00
class AdminUser(APIView):
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAdminUser, )
throttle_classes = (UserRateThrottle, )
def get(self, request, email):
try:
User.objects.get(email=email)
except User.DoesNotExist:
error_msg = 'User %s not found.' % email
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
user_info = get_user_info(email)
return Response(user_info)
def put(self, request, email):
# basic user info check
is_staff = request.data.get("is_staff", None)
if is_staff:
try:
is_staff = to_python_boolean(is_staff)
except ValueError:
error_msg = 'is_staff invalid.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
is_active = request.data.get("is_active", None)
if is_active:
try:
is_active = to_python_boolean(is_active)
except ValueError:
error_msg = 'is_active invalid.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
# additional user info check
role = request.data.get("role", None)
if role:
available_roles = get_available_roles()
if role.lower() not in available_roles:
error_msg = 'role must be in %s.' % str(available_roles)
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
name = request.data.get("name", None)
if name:
if len(name) > 64:
error_msg = 'Name is too long (maximum is 64 characters).'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
if "/" in name:
error_msg = "Name should not include '/'."
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
2017-09-07 15:22:15 +08:00
# argument check for login_id
login_id = request.data.get("login_id", None)
if login_id is not None:
login_id = login_id.strip()
username_by_login_id = Profile.objects.get_username_by_login_id(login_id)
if username_by_login_id is not None:
return api_error(status.HTTP_400_BAD_REQUEST,
Python3 master (#4076) * delete thridpart/social_django * delete social_django in seahub/urls.py * delete social_django in seahub/settings.py * delete seahub/notifications/management/commands/send_wxwork_notices.py * delete social_django in code annotation * delete seahub/social_core * delete tests/seahub/social_core * delete social_core in seahub/urls.py * delete social_core in seahub/settings.py * change app_label to auth in SocialAuthUser model * 2to3 asserts * 2to3 basestring * 2to3 dict * 2to3 except * 2to3 filter * 2to3 future * 2to3 has_key * 2to3 idioms * 2to3 import * 2to3 imports * 2to3 long * 2to3 map * 2to3 next * 2to3 numliterals * 2to3 print * 2to3 raise * 2to3 raw_input * 2to3 reduce * 2to3 reload * 2to3 set_literal * 2to3 unicode * 2to3 urllib * 2to3 ws_comma * 2to3 xrange * 2to3 zip * add pymysql in __init__.py * fix encode and decode in seahub/cconvert.py * fix seafserv_rpc.is_passwd_set in seahub/views/__init__.py * fix smart_unicode to smart_text * fix force_unicode to force_text * delete seaserv.get_session_info * delete seaserv.ccnet_rpc * fix indent error in seahub/auth/middleware.py * update dev-requirements * update test-requirements * update requirements * fix StringIO to BytesIO in thumbnail * fix seaserv.list_inner_pub_repos to seafile_api.get_inner_pub_repo_list * fix seaserv.list_org_inner_pub_repos to seafile_api.list_org_inner_pub_repos * add logger in seahub/utils/__init__.py * fix sort cmp in seahub/views/__init__.py * fix sort cmp in seahub/base/management/commands/export_file_access_log.py * fix sort cmp in seahub/api2/endpoints/repo_trash.py * fix sort cmp in seahub/api2/endpoints/shared_repos.py * fix sort cmp in seahub/api2/endpoints/shared_folders.py * fix sort cmp in seahub/wiki/views.py * fix sort cmp in seahub/api2/endpoints/wiki_pages.py * fix sort cmp in seahub/api2/endpoints/group_libraries.py * fix sort cmp in seahub/base/models.py * fix sort cmp in seahub/api2/endpoints/upload_links.py * fix sort cmp in seahub/views/ajax.py * fix sort cmp in seahub/api2/views.py * fix sort cmp in seahub/views/wiki.py * fix sort cmp in seahub/api2/endpoints/repos.py * fix sort cmp in seahub/api2/endpoints/starred_items.py * fix sort cmp in seahub/views/file.py * fix sort cmp in seahub/api2/endpoints/dir.py * fix sort cmp in seahub/api2/endpoints/share_links.py * fix cmp to cmp_to_key in seahub/api2/endpoints/admin/device_trusted_ip.py * fix cmp to cmp_to_key in tests/api/endpoints/admin/test_device_trusted_ip.py * delete encode('utf-8') in seafile_api.list_dir_by_commit_and_path * delete encode('utf-8') in is_file_starred * delete encode('utf-8') in seafile_api.list_dir_by_path * delete path.encode('utf-8') in seahub/views/file.py * fix os.write to add encode('utf-8') * add encode('utf-8') for hashlib * add encode('utf-8') for hmac * fix with open(file, 'wb') for binary file * fix encode and decode in seahub/utils/hasher.py * fix next in thirdpart/shibboleth/views.py * fix next in seahub/profile/views.py * fix next in seahub/notifications/views.py * fix next in seahub/institutions/views.py * fix next in seahub/options/views.py * fix next in seahub/share/views.py * fix next in seahub/avatar/views.py * fix next in seahub/views/__init__.py * fix next in seahub/group/views.py * fix next in seahub/views/wiki.py * fix next in seahub/views/sysadmin.py * fix next in seahub/views/file.py * fix string.lowercase to string.ascii_lowercase in test * fix open file add 'rb' in test * fix self.user.username in test * add migrations in file_participants * fix list_org_inner_pub_repos to list_org_inner_pub_repos_by_owner * fix from seaserv import is_passwd_set to seafile_api.is_password_set * fix assert bytes resp.content in test * fix seafile_api.get_inner_pub_repo_list to seafile_api.list_inner_pub_repos_by_owner * fix seafile_api.is_passwd_set to seafile_api.is_password_set * fix AccountsApiTest assert length * rewrite sort_devices cmp to operator.lt * fix bytes + str in seahub/api2/views.py * fix assert bytes resp.content in test * fix hashlib encode in seahub/thirdpart/registration/models.py * change app_label to base in SocialAuthUser * fix base64 encode in seahub/base/database_storage/database_storage.py * fix assert bytes resp.content * remove path.decode in def mkstemp() * remove path.decode in FpathToLinkTest * remove str decode in FileTagTest * remove mock_write_xls.assert_called_once() in SysUserAdminExportExcelTest * fix urllib assert in FilesApiTest * fix link fields in FileCommentsTest * fix get_related_users_by_repo() * fix assert list in GetRepoSharedUsersTest * fix create user in AccountTest * fix repeated key in dict seahub/api2/views.py * add drone.yml * update nginx conf in test * update test conf in test * update dist and push after test success * update drone conf to dist and push * fix assert in BeSharedReposTest * fix seafile_api.list_org_inner_pub_repos_by_owner(org_id, username) to seafile_api.list_org_inner_pub_repos(org_id) * fix seafile_api.list_inner_pub_repos_by_owner(username) to seafile_api.get_inner_pub_repo_list() * update pyjwt requirement * update dist branch in drone * add SKIP in dist and push * fix StringIO to BytesIO in seahub/avatar/models.py * fix if org_id > 0 to if org_id and org_id > 0 * remove payment * fix StringIO to BytesIO in seahub/base/database_storage/database_storage.py * fix send_message to seafile_api.publish_event in seahub/drafts/utils.py * fix send_message to seafile_api.publish_event in seahub/api2/views.py * fix send_message to seafile_api.publish_event in seahub/api2/endpoints/repos.py * fix send_message to seafile_api.publish_event in seahub/views/file.py * fix send_message to seafile_api.publish_event in seahub/utils/__init__.py * fix image_file.read encode in seahub/base/database_storage/database_storage.py * fix DatabaseStorageTest * remove .travis.yml * drone branch include master
2019-09-11 11:46:43 +08:00
_("Login id %s already exists." % login_id))
2017-09-07 15:22:15 +08:00
contact_email = request.data.get("contact_email", None)
if contact_email is not None and contact_email.strip() != '':
if not is_valid_email(contact_email):
error_msg = 'Contact email invalid.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
profile = Profile.objects.get_profile_by_contact_email(contact_email)
if profile:
error_msg = 'Contact email %s already exists.' % contact_email
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
reference_id = request.data.get("reference_id", "")
2017-09-07 17:12:35 +08:00
if reference_id:
2017-09-19 17:55:13 +08:00
if ' ' in reference_id:
return api_error(status.HTTP_400_BAD_REQUEST, 'Reference ID can not contain spaces.')
2017-09-07 17:12:35 +08:00
primary_id = ccnet_api.get_primary_id(reference_id)
if primary_id:
return api_error(status.HTTP_400_BAD_REQUEST, 'Reference ID %s already exists.' % reference_id)
2017-09-07 15:22:15 +08:00
2017-08-28 14:52:28 +08:00
department = request.data.get("department", None)
if department:
if len(department) > 512:
error_msg = "Department is too long (maximum is 512 characters)."
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
quota_total_mb = request.data.get("quota_total", None)
if quota_total_mb:
try:
quota_total_mb = int(quota_total_mb)
except ValueError:
error_msg = "Must be an integer that is greater than or equal to 0."
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
if quota_total_mb < 0:
error_msg = "Space quota is too low (minimum value is 0)."
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
if is_org_context(request):
org_id = request.user.org.org_id
org_quota_mb = seafile_api.get_org_quota(org_id) / \
get_file_size_unit('MB')
if quota_total_mb > org_quota_mb:
error_msg = 'Failed to set quota: maximum quota is %d MB' % org_quota_mb
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
# query user info
try:
user_obj = User.objects.get(email=email)
2017-08-28 14:52:28 +08:00
except User.DoesNotExist:
error_msg = 'User %s not found.' % email
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
try:
update_user_info(request, user_obj)
2017-08-28 14:52:28 +08:00
except Exception as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
user_info = get_user_info(email)
return Response(user_info)
def delete(self, request, email):
try:
User.objects.get(email=email)
except User.DoesNotExist:
error_msg = 'User %s not found.' % email
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
# delete user
try:
User.objects.get(email=email).delete()
except Exception as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
return Response({'success': True})
2019-10-15 16:05:51 +08:00
class AdminUserResetPassword(APIView):
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAdminUser, )
throttle_classes = (UserRateThrottle, )
def put(self, request, email):
"""Reset password for user
Permission checking:
1. only admin can perform this action.
"""
if not is_valid_username(email):
error_msg = 'email invalid'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
try:
user = User.objects.get(email=email)
except User.DoesNotExist as e:
logger.error(e)
error_msg = 'email invalid.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
if isinstance(INIT_PASSWD, FunctionType):
new_password = INIT_PASSWD()
else:
new_password = INIT_PASSWD
user.set_password(new_password)
user.save()
if config.FORCE_PASSWORD_CHANGE:
UserOptions.objects.set_force_passwd_change(user.username)
if IS_EMAIL_CONFIGURED:
if SEND_EMAIL_ON_RESETTING_USER_PASSWD:
c = {'email': email, 'password': new_password}
contact_email = Profile.objects.get_contact_email_by_user(email)
try:
send_html_email(_(u'Password has been reset on %s') % get_site_name(),
'sysadmin/user_reset_email.html', c, None, [contact_email])
reset_tip = _('Successfully reset password to %(passwd)s, an email has been sent to %(user)s.') % \
{'passwd': new_password, 'user': contact_email}
except Exception as e:
logger.warning(e)
reset_tip = _('Successfully reset password to %(passwd)s, but failed to send email to %(user)s, please check your email configuration.') % \
{'passwd': new_password, 'user': email}
else:
reset_tip = _('Successfully reset password to %(passwd)s for user %(user)s.') % \
{'passwd': new_password, 'user': email}
else:
reset_tip = _('Successfully reset password to %(passwd)s for user %(user)s. But email notification can not be sent, because Email service is not properly configured.') % \
{'passwd': new_password, 'user': email}
2019-10-15 16:05:51 +08:00
return Response({'new_password': new_password, 'reset_tip': reset_tip})
2019-10-15 16:05:51 +08:00
class AdminUserGroups(APIView):
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAdminUser, )
throttle_classes = (UserRateThrottle, )
def get(self, request, email):
""" return all groups user joined
Permission checking:
1. Admin user;
"""
if not is_valid_username(email):
error_msg = 'email invalid.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
try:
User.objects.get(email=email)
except User.DoesNotExist as e:
logger.error(e)
error_msg = 'User %s not found.' % email
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
groups_info = []
try:
groups = ccnet_api.get_personal_groups_by_user(email)
except Exception as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
# Use dict to reduce memcache fetch cost in large for-loop.
nickname_dict = {}
creator_name_set = set([g.creator_name for g in groups])
for e in creator_name_set:
if e not in nickname_dict:
nickname_dict[e] = email2nickname(e)
for group in groups:
isoformat_timestr = timestamp_to_isoformat_timestr(group.timestamp)
group_info = {
"id": group.id,
"name": group.group_name,
"owner_email": group.creator_name,
"owner_name": nickname_dict.get(group.creator_name, ''),
"created_at": isoformat_timestr,
"parent_group_id": group.parent_group_id if is_pro_version() else 0
}
groups_info.append(group_info)
try:
is_group_staff = ccnet_api.check_group_staff(group.id, email)
except Exception as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
if email == group.creator_name:
group_info['role'] = 'Owner'
elif is_group_staff:
group_info['role'] = 'Admin'
else:
group_info['role'] = 'Member'
return Response({'group_list': groups_info})
class AdminUserShareLinks(APIView):
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAdminUser,)
throttle_classes = (UserRateThrottle,)
def get(self, request, email):
""" Get all shared download links of a user.
Permission checking:
1. only admin can perform this action.
"""
if not is_valid_username(email):
error_msg = 'email invalid.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
try:
User.objects.get(email=email)
except User.DoesNotExist as e:
logger.error(e)
error_msg = 'User %s not found.' % email
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
share_links = FileShare.objects.filter(username=email)
links_info = []
for fs in share_links:
link_info = get_user_share_link_info(fs)
links_info.append(link_info)
return Response({'share_link_list': links_info})
class AdminUserUploadLinks(APIView):
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAdminUser,)
throttle_classes = (UserRateThrottle,)
def get(self, request, email):
""" Get all shared upload links of a user.
Permission checking:
1. only admin can perform this action.
"""
if not is_valid_username(email):
error_msg = 'email invalid.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
try:
User.objects.get(email=email)
except User.DoesNotExist as e:
logger.error(e)
error_msg = 'User %s not found.' % email
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
upload_links = UploadLinkShare.objects.filter(username=email)
links_info = []
for fs in upload_links:
link_info = get_user_upload_link_info(fs)
links_info.append(link_info)
return Response({'upload_link_list': links_info})
class AdminUserBeSharedRepos(APIView):
authentication_classes = (TokenAuthentication, SessionAuthentication)
throttle_classes = (UserRateThrottle,)
permission_classes = (IsAdminUser,)
def get(self, request, email):
""" List 'all' libraries shared to a user
Permission checking:
1. only admin can perform this action.
"""
if not is_valid_username(email):
error_msg = 'email invalid.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
try:
User.objects.get(email=email)
except User.DoesNotExist as e:
logger.error(e)
error_msg = 'User %s not found.' % email
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
try:
beshared_repos = seafile_api.get_share_in_repo_list(email, -1, -1)
except Exception as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
# Use dict to reduce memcache fetch cost in large for-loop.
nickname_dict = {}
owner_set = set([x.user for x in beshared_repos])
for e in owner_set:
if e not in nickname_dict:
nickname_dict[e] = email2nickname(e)
repos_info = []
for repo in beshared_repos:
repo_info = {}
repo_info['id'] = repo.repo_id
repo_info['name'] = repo.repo_name
repo_info['owner_email'] = repo.user
repo_info['owner_name'] = nickname_dict.get(repo.user, '')
repo_info['size'] = repo.size
repo_info['encrypted'] = repo.encrypted
repo_info['file_count'] = repo.file_count
repo_info['status'] = normalize_repo_status_code(repo.status)
repo_info['last_modify'] = timestamp_to_isoformat_timestr(repo.last_modify)
repos_info.append(repo_info)
return Response({'repo_list': repos_info})