1# Copyright (c) 2012-2016 Seafile Ltd. 2import os 3import logging 4from types import FunctionType 5from constance import config 6 7from rest_framework import status 8from rest_framework.authentication import SessionAuthentication 9from rest_framework.permissions import IsAdminUser 10from rest_framework.response import Response 11from rest_framework.views import APIView 12 13from django.db.models import Q 14from django.core.cache import cache 15from django.utils.translation import ugettext as _ 16from django.utils.timezone import make_naive, is_aware 17 18from seaserv import seafile_api, ccnet_api 19 20from seahub.api2.authentication import TokenAuthentication 21from seahub.api2.throttling import UserRateThrottle 22from seahub.api2.utils import api_error, to_python_boolean 23from seahub.api2.models import TokenV2 24 25import seahub.settings as settings 26from seahub.settings import SEND_EMAIL_ON_ADDING_SYSTEM_MEMBER, INIT_PASSWD, \ 27 SEND_EMAIL_ON_RESETTING_USER_PASSWD 28from seahub.base.templatetags.seahub_tags import email2nickname, email2contact_email 29from seahub.base.accounts import User 30from seahub.base.models import UserLastLogin 31from seahub.two_factor.models import default_device 32from seahub.profile.models import Profile 33from seahub.profile.settings import CONTACT_CACHE_TIMEOUT, CONTACT_CACHE_PREFIX, \ 34 NICKNAME_CACHE_PREFIX, NICKNAME_CACHE_TIMEOUT 35from seahub.utils import is_valid_username2, is_org_context, \ 36 is_pro_version, normalize_cache_key, is_valid_email, \ 37 IS_EMAIL_CONFIGURED, send_html_email, get_site_name, \ 38 gen_shared_link, gen_shared_upload_link 39 40from seahub.utils.file_size import get_file_size_unit 41from seahub.utils.timeutils import timestamp_to_isoformat_timestr, \ 42 datetime_to_isoformat_timestr 43from seahub.utils.user_permissions import get_user_role 44from seahub.utils.repo import normalize_repo_status_code 45from seahub.constants import DEFAULT_ADMIN 46from seahub.role_permissions.models import AdminRole 47from seahub.role_permissions.utils import get_available_roles 48from seahub.utils.licenseparse import user_number_over_limit 49from seahub.institutions.models import Institution 50from seahub.avatar.templatetags.avatar_tags import api_avatar_url 51from seahub.admin_log.signals import admin_operation 52from seahub.admin_log.models import USER_DELETE, USER_ADD 53from seahub.api2.endpoints.group_owned_libraries import get_group_id_by_repo_owner 54from seahub.group.utils import group_id_to_name 55from seahub.institutions.models import InstitutionAdmin 56 57from seahub.options.models import UserOptions 58from seahub.share.models import FileShare, UploadLinkShare 59 60logger = logging.getLogger(__name__) 61json_content_type = 'application/json; charset=utf-8' 62 63 64def get_user_last_access_time(email, last_login_time): 65 66 device_last_access = '' 67 devices = TokenV2.objects.filter(user=email).order_by('-last_accessed') 68 if devices: 69 device_last_access = devices[0].last_accessed 70 71 # before make_naive 72 # 2021-04-09 05:32:30+00:00 73 # tzinfo: UTC 74 75 # after make_naive 76 # 2021-04-09 13:32:30 77 # tzinfo: None 78 last_access_time_list = [] 79 if last_login_time: 80 if is_aware(last_login_time): 81 last_login_time = make_naive(last_login_time) 82 last_access_time_list.append(last_login_time) 83 84 if device_last_access: 85 if is_aware(device_last_access): 86 device_last_access = make_naive(device_last_access) 87 last_access_time_list.append(device_last_access) 88 89 if not last_access_time_list: 90 return '' 91 else: 92 return datetime_to_isoformat_timestr(sorted(last_access_time_list)[-1]) 93 94 95def get_user_upload_link_info(uls): 96 data = {} 97 98 repo_id = uls.repo_id 99 try: 100 repo = seafile_api.get_repo(repo_id) 101 except Exception as e: 102 logger.error(e) 103 repo = None 104 105 path = uls.path 106 if path: 107 obj_name = '/' if path == '/' else os.path.basename(path.rstrip('/')) 108 else: 109 obj_name = '' 110 111 data['repo_name'] = repo.repo_name if repo else '' 112 data['path'] = path 113 data['token'] = uls.token 114 data['link'] = gen_shared_upload_link(uls.token) 115 data['obj_name'] = obj_name 116 data['view_cnt'] = uls.view_cnt 117 118 return data 119 120 121def get_user_share_link_info(fileshare): 122 data = {} 123 124 repo_id = fileshare.repo_id 125 try: 126 repo = seafile_api.get_repo(repo_id) 127 except Exception as e: 128 logger.error(e) 129 repo = None 130 131 path = fileshare.path 132 if path: 133 obj_name = '/' if path == '/' else os.path.basename(path.rstrip('/')) 134 else: 135 obj_name = '' 136 137 data['repo_name'] = repo.repo_name if repo else '' 138 data['token'] = fileshare.token 139 data['link'] = gen_shared_link(fileshare.token, fileshare.s_type) 140 141 data['path'] = path 142 data['obj_name'] = obj_name 143 data['is_dir'] = True if fileshare.s_type == 'd' else False 144 145 data['view_cnt'] = fileshare.view_cnt 146 147 if fileshare.s_type == 'f': 148 obj_id = seafile_api.get_file_id_by_path(repo_id, path) 149 data['size'] = seafile_api.get_file_size(repo.store_id, 150 repo.version, obj_id) 151 else: 152 data['size'] = '' 153 154 return data 155 156 157def create_user_info(request, email, role, nickname, contact_email, quota_total_mb): 158 # update additional user info 159 160 if is_pro_version() and role: 161 User.objects.update_role(email, role) 162 163 if nickname is not None: 164 Profile.objects.add_or_update(email, nickname) 165 key = normalize_cache_key(nickname, NICKNAME_CACHE_PREFIX) 166 cache.set(key, nickname, NICKNAME_CACHE_TIMEOUT) 167 168 if contact_email is not None: 169 Profile.objects.add_or_update(email, contact_email=contact_email) 170 key = normalize_cache_key(email, CONTACT_CACHE_PREFIX) 171 cache.set(key, contact_email, CONTACT_CACHE_TIMEOUT) 172 173 if quota_total_mb: 174 quota_total = int(quota_total_mb) * get_file_size_unit('MB') 175 if is_org_context(request): 176 org_id = request.user.org.org_id 177 seafile_api.set_org_user_quota(org_id, email, quota_total) 178 else: 179 seafile_api.set_user_quota(email, quota_total) 180 181 182def update_user_info(request, user, password, is_active, is_staff, role, 183 nickname, login_id, contact_email, reference_id, quota_total_mb, institution_name): 184 185 # update basic user info 186 if is_active is not None: 187 user.is_active = is_active 188 189 if password: 190 user.set_password(password) 191 192 if is_staff is not None: 193 user.is_staff = is_staff 194 195 # update user 196 user.save() 197 198 email = user.username 199 200 # update additional user info 201 if is_pro_version() and role: 202 User.objects.update_role(email, role) 203 204 if nickname is not None: 205 Profile.objects.add_or_update(email, nickname) 206 key = normalize_cache_key(nickname, NICKNAME_CACHE_PREFIX) 207 cache.set(key, nickname, NICKNAME_CACHE_TIMEOUT) 208 209 if login_id is not None: 210 Profile.objects.add_or_update(email, login_id=login_id) 211 212 if contact_email is not None: 213 Profile.objects.add_or_update(email, contact_email=contact_email) 214 key = normalize_cache_key(email, CONTACT_CACHE_PREFIX) 215 cache.set(key, contact_email, CONTACT_CACHE_TIMEOUT) 216 217 if reference_id is not None: 218 if reference_id.strip(): 219 ccnet_api.set_reference_id(email, reference_id.strip()) 220 else: 221 # remove reference id 222 ccnet_api.set_reference_id(email, None) 223 224 if institution_name is not None: 225 Profile.objects.add_or_update(email, institution=institution_name) 226 if institution_name == '': 227 InstitutionAdmin.objects.filter(user=email).delete() 228 229 if quota_total_mb is not None: 230 quota_total = int(quota_total_mb) * get_file_size_unit('MB') 231 orgs = ccnet_api.get_orgs_by_user(email) 232 try: 233 if orgs: 234 org_id = orgs[0].org_id 235 seafile_api.set_org_user_quota(org_id, email, quota_total) 236 else: 237 seafile_api.set_user_quota(email, quota_total) 238 except Exception as e: 239 logger.error(e) 240 seafile_api.set_user_quota(email, -1) 241 242 243def get_user_info(email): 244 245 user = User.objects.get(email=email) 246 profile = Profile.objects.get_profile_by_user(email) 247 248 info = {} 249 info['email'] = email 250 info['name'] = email2nickname(email) 251 info['contact_email'] = profile.contact_email if profile and profile.contact_email else '' 252 info['login_id'] = profile.login_id if profile and profile.login_id else '' 253 254 info['is_staff'] = user.is_staff 255 info['is_active'] = user.is_active 256 info['reference_id'] = user.reference_id if user.reference_id else '' 257 258 orgs = ccnet_api.get_orgs_by_user(email) 259 try: 260 if orgs: 261 org_id = orgs[0].org_id 262 info['org_id'] = org_id 263 info['org_name'] = orgs[0].org_name 264 info['quota_usage'] = seafile_api.get_org_user_quota_usage(org_id, user.email) 265 info['quota_total'] = seafile_api.get_org_user_quota(org_id, user.email) 266 else: 267 info['quota_usage'] = seafile_api.get_user_self_usage(user.email) 268 info['quota_total'] = seafile_api.get_user_quota(user.email) 269 except Exception as e: 270 logger.error(e) 271 info['quota_usage'] = -1 272 info['quota_total'] = -1 273 274 info['create_time'] = timestamp_to_isoformat_timestr(user.ctime) 275 276 info['has_default_device'] = True if default_device(user) else False 277 info['is_force_2fa'] = UserOptions.objects.is_force_2fa(email) 278 279 if getattr(settings, 'MULTI_INSTITUTION', False): 280 info['institution'] = profile.institution if profile else '' 281 282 info['role'] = get_user_role(user) 283 284 return info 285 286 287class AdminAdminUsers(APIView): 288 289 authentication_classes = (TokenAuthentication, SessionAuthentication) 290 permission_classes = (IsAdminUser, ) 291 throttle_classes = (UserRateThrottle, ) 292 293 def get(self, request): 294 """List all admins from database and ldap imported 295 """ 296 297 if not request.user.admin_permissions.can_manage_user(): 298 return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') 299 300 try: 301 admin_users = ccnet_api.get_superusers() 302 except Exception as e: 303 logger.error(e) 304 error_msg = 'Internal Server Error' 305 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 306 307 admin_users_info = [] 308 for user in admin_users: 309 user_info = {} 310 profile = Profile.objects.get_profile_by_user(user.email) 311 user_info['email'] = user.email 312 user_info['name'] = email2nickname(user.email) 313 user_info['contact_email'] = email2contact_email(user.email) 314 user_info['login_id'] = profile.login_id if profile and profile.login_id else '' 315 316 user_info['is_staff'] = user.is_staff 317 user_info['is_active'] = user.is_active 318 319 orgs = ccnet_api.get_orgs_by_user(user.email) 320 try: 321 if orgs: 322 org_id = orgs[0].org_id 323 user_info['org_id'] = org_id 324 user_info['org_name'] = orgs[0].org_name 325 user_info['quota_usage'] = seafile_api.get_org_user_quota_usage(org_id, user.email) 326 user_info['quota_total'] = seafile_api.get_org_user_quota(org_id, user.email) 327 else: 328 user_info['quota_usage'] = seafile_api.get_user_self_usage(user.email) 329 user_info['quota_total'] = seafile_api.get_user_quota(user.email) 330 except Exception as e: 331 logger.error(e) 332 user_info['quota_usage'] = -1 333 user_info['quota_total'] = -1 334 335 user_info['create_time'] = timestamp_to_isoformat_timestr(user.ctime) 336 337 last_login_obj = UserLastLogin.objects.get_by_username(user.email) 338 if last_login_obj: 339 user_info['last_login'] = datetime_to_isoformat_timestr(last_login_obj.last_login) 340 user_info['last_access_time'] = get_user_last_access_time(user.email, 341 last_login_obj.last_login) 342 else: 343 user_info['last_login'] = '' 344 user_info['last_access_time'] = get_user_last_access_time(user.email, '') 345 346 try: 347 admin_role = AdminRole.objects.get_admin_role(user.email) 348 user_info['admin_role'] = admin_role.role 349 except AdminRole.DoesNotExist: 350 user_info['admin_role'] = DEFAULT_ADMIN 351 admin_users_info.append(user_info) 352 353 result = { 354 'admin_user_list': admin_users_info, 355 } 356 return Response(result) 357 358 359class AdminUsers(APIView): 360 361 authentication_classes = (TokenAuthentication, SessionAuthentication) 362 permission_classes = (IsAdminUser, ) 363 throttle_classes = (UserRateThrottle, ) 364 365 def get_info_of_users_order_by_quota_usage(self, source, direction, 366 page, per_page): 367 368 # get user's quota usage info 369 user_usage_dict = {} 370 users_with_usage = seafile_api.list_user_quota_usage() 371 for user in users_with_usage: 372 email = user.user 373 if email not in user_usage_dict: 374 user_usage_dict[email] = user.usage 375 376 # get all users and map quota usage to user 377 if source == 'db': 378 users = ccnet_api.get_emailusers('DB', -1, -1) 379 else: 380 users = ccnet_api.get_emailusers('LDAPImport', -1, -1) 381 382 for user in users: 383 email = user.email 384 user.quota_usage = user_usage_dict.get(email, -1) 385 386 # sort 387 users.sort(key=lambda item: item.quota_usage, 388 reverse = direction == 'desc') 389 390 data = [] 391 MULTI_INSTITUTION = getattr(settings, 'MULTI_INSTITUTION', False) 392 for user in users[(page-1)*per_page: page*per_page]: 393 394 info = {} 395 info['email'] = user.email 396 info['name'] = email2nickname(user.email) 397 info['contact_email'] = email2contact_email(user.email) 398 399 profile = Profile.objects.get_profile_by_user(user.email) 400 info['login_id'] = profile.login_id if profile and profile.login_id else '' 401 402 info['is_staff'] = user.is_staff 403 info['is_active'] = user.is_active 404 info['create_time'] = timestamp_to_isoformat_timestr(user.ctime) 405 406 info['quota_usage'] = user.quota_usage 407 info['quota_total'] = seafile_api.get_user_quota(user.email) 408 409 last_login_obj = UserLastLogin.objects.get_by_username(user.email) 410 if last_login_obj: 411 info['last_login'] = datetime_to_isoformat_timestr(last_login_obj.last_login) 412 info['last_access_time'] = get_user_last_access_time(user.email, 413 last_login_obj.last_login) 414 else: 415 info['last_login'] = '' 416 info['last_access_time'] = get_user_last_access_time(user.email, '') 417 418 info['role'] = get_user_role(user) 419 420 if MULTI_INSTITUTION: 421 info['institution'] = profile.institution if profile else '' 422 423 data.append(info) 424 425 return data 426 427 def get(self, request): 428 """List all users in DB or LDAPImport 429 430 Permission checking: 431 1. only admin can perform this action. 432 """ 433 434 if not request.user.admin_permissions.can_manage_user(): 435 return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') 436 437 # parameter check 438 try: 439 page = int(request.GET.get('page', '1')) 440 per_page = int(request.GET.get('per_page', '25')) 441 except ValueError: 442 page = 1 443 per_page = 25 444 445 start = (page - 1) * per_page 446 447 source = request.GET.get('source', 'DB').lower().strip() 448 if source not in ['db', 'ldapimport']: 449 # source: 'DB' or 'LDAPImport', default is 'DB' 450 error_msg = 'source %s invalid.' % source 451 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 452 453 order_by = request.GET.get('order_by', '').lower().strip() 454 if order_by: 455 if order_by not in ('quota_usage'): 456 error_msg = 'order_by invalid.' 457 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 458 459 direction = request.GET.get('direction', 'desc').lower().strip() 460 if direction not in ('asc', 'desc'): 461 error_msg = 'direction invalid.' 462 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 463 464 if source == 'db': 465 466 total_count = ccnet_api.count_emailusers('DB') + \ 467 ccnet_api.count_inactive_emailusers('DB') 468 if order_by: 469 470 if total_count > 500 and \ 471 not getattr(settings, 'ALWAYS_SORT_USERS_BY_QUOTA_USAGE', False): 472 error_msg = _("There are more than 500 users, and sort is not offered.") 473 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 474 475 try: 476 data = self.get_info_of_users_order_by_quota_usage(source, 477 direction, 478 page, 479 per_page) 480 except Exception as e: 481 logger.error(e) 482 error_msg = 'Internal Server Error' 483 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 484 485 result = {'data': data, 'total_count': total_count} 486 return Response(result) 487 else: 488 users = ccnet_api.get_emailusers('DB', start, per_page) 489 490 elif source == 'ldapimport': 491 492 # api param is 'LDAP', but actually get count of 'LDAPImport' users 493 total_count = ccnet_api.count_emailusers('LDAP') + \ 494 ccnet_api.count_inactive_emailusers('LDAP') 495 if order_by: 496 497 if total_count > 500 and \ 498 not getattr(settings, 'ALWAYS_SORT_USERS_BY_QUOTA_USAGE', False): 499 error_msg = _("There are more than 500 users, and sort is not offered.") 500 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 501 502 try: 503 data = self.get_info_of_users_order_by_quota_usage(source, 504 direction, 505 page, 506 per_page) 507 except Exception as e: 508 logger.error(e) 509 error_msg = 'Internal Server Error' 510 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 511 512 result = {'data': data, 'total_count': total_count} 513 return Response(result) 514 else: 515 users = ccnet_api.get_emailusers('LDAPImport', start, per_page) 516 517 data = [] 518 for user in users: 519 profile = Profile.objects.get_profile_by_user(user.email) 520 521 info = {} 522 info['email'] = user.email 523 info['name'] = email2nickname(user.email) 524 info['contact_email'] = email2contact_email(user.email) 525 info['login_id'] = profile.login_id if profile and profile.login_id else '' 526 527 info['is_staff'] = user.is_staff 528 info['is_active'] = user.is_active 529 530 orgs = ccnet_api.get_orgs_by_user(user.email) 531 try: 532 if orgs: 533 org_id = orgs[0].org_id 534 info['org_id'] = org_id 535 info['org_name'] = orgs[0].org_name 536 info['quota_usage'] = seafile_api.get_org_user_quota_usage(org_id, user.email) 537 info['quota_total'] = seafile_api.get_org_user_quota(org_id, user.email) 538 else: 539 info['quota_usage'] = seafile_api.get_user_self_usage(user.email) 540 info['quota_total'] = seafile_api.get_user_quota(user.email) 541 except Exception as e: 542 logger.error(e) 543 info['quota_usage'] = -1 544 info['quota_total'] = -1 545 546 info['role'] = get_user_role(user) 547 548 info['create_time'] = timestamp_to_isoformat_timestr(user.ctime) 549 550 last_login_obj = UserLastLogin.objects.get_by_username(user.email) 551 if last_login_obj: 552 info['last_login'] = datetime_to_isoformat_timestr(last_login_obj.last_login) 553 info['last_access_time'] = get_user_last_access_time(user.email, 554 last_login_obj.last_login) 555 else: 556 info['last_login'] = '' 557 info['last_access_time'] = get_user_last_access_time(user.email, '') 558 559 if getattr(settings, 'MULTI_INSTITUTION', False): 560 info['institution'] = profile.institution if profile else '' 561 562 data.append(info) 563 564 result = {'data': data, 'total_count': total_count} 565 return Response(result) 566 567 def post(self, request): 568 569 if not request.user.admin_permissions.can_manage_user(): 570 return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') 571 572 if user_number_over_limit(): 573 error_msg = _("The number of users exceeds the limit.") 574 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 575 576 email = request.data.get('email', None) 577 if not email or not is_valid_email(email): 578 error_msg = 'email invalid.' 579 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 580 581 # basic user info check 582 is_staff = request.data.get("is_staff", 'False') 583 try: 584 is_staff = to_python_boolean(is_staff) 585 except ValueError: 586 error_msg = 'is_staff invalid.' 587 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 588 589 is_active = request.data.get("is_active", 'True') 590 try: 591 is_active = to_python_boolean(is_active) 592 except ValueError: 593 error_msg = 'is_active invalid.' 594 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 595 596 # additional user info check 597 role = '' 598 if is_pro_version(): 599 role = request.data.get("role", None) 600 if role: 601 available_roles = get_available_roles() 602 if role not in available_roles: 603 error_msg = 'role must be in %s.' % str(available_roles) 604 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 605 606 name = request.data.get("name", None) 607 if name: 608 if len(name) > 64: 609 error_msg = 'Name is too long (maximum is 64 characters).' 610 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 611 612 if "/" in name: 613 error_msg = "Name should not include '/'." 614 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 615 616 contact_email = request.data.get('contact_email', None) 617 if contact_email and not is_valid_email(contact_email): 618 error_msg = 'contact_email invalid.' 619 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 620 621 quota_total_mb = request.data.get("quota_total", None) 622 if quota_total_mb: 623 try: 624 quota_total_mb = int(quota_total_mb) 625 except ValueError: 626 error_msg = "Must be an integer that is greater than or equal to 0." 627 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 628 629 if quota_total_mb < 0: 630 error_msg = "Space quota is too low (minimum value is 0)." 631 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 632 633 if is_org_context(request): 634 org_id = request.user.org.org_id 635 org_quota_mb = seafile_api.get_org_quota(org_id) / get_file_size_unit('MB') 636 637 if quota_total_mb > org_quota_mb: 638 error_msg = 'Failed to set quota: maximum quota is %d MB' % org_quota_mb 639 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 640 641 try: 642 User.objects.get(email=email) 643 user_exist = True 644 except User.DoesNotExist: 645 user_exist = False 646 647 if user_exist: 648 error_msg = "User %s already exists." % email 649 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 650 651 password = request.data.get('password', None) 652 if not password: 653 error_msg = 'password required.' 654 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 655 656 # create user 657 try: 658 user_obj = User.objects.create_user(email, password, is_staff, is_active) 659 create_user_info(request, email=user_obj.username, role=role, 660 nickname=name, contact_email=contact_email, 661 quota_total_mb=quota_total_mb) 662 except Exception as e: 663 logger.error(e) 664 error_msg = 'Internal Server Error' 665 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 666 667 add_user_tip = _('Successfully added user %(user)s.') % {'user': email} 668 if IS_EMAIL_CONFIGURED and SEND_EMAIL_ON_ADDING_SYSTEM_MEMBER: 669 c = {'user': request.user.username, 'email': email, 'password': password} 670 try: 671 send_html_email(_('You are invited to join %s') % get_site_name(), 672 'sysadmin/user_add_email.html', 673 c, 674 None, 675 [email2contact_email(email)]) 676 677 add_user_tip = _('Successfully added user %(user)s. An email notification has been sent.') % {'user': email} 678 except Exception as e: 679 logger.error(str(e)) 680 add_user_tip = _('Successfully added user %(user)s. But email notification can not be sent, because Email service is not properly configured.') % {'user': email} 681 682 user_info = get_user_info(email) 683 user_info['add_user_tip'] = add_user_tip 684 685 # send admin operation log signal 686 admin_op_detail = { 687 "email": email, 688 } 689 admin_operation.send(sender=None, admin_name=request.user.username, 690 operation=USER_ADD, detail=admin_op_detail) 691 692 if config.FORCE_PASSWORD_CHANGE: 693 UserOptions.objects.set_force_passwd_change(email) 694 695 return Response(user_info) 696 697 698class AdminLDAPUsers(APIView): 699 700 authentication_classes = (TokenAuthentication, SessionAuthentication) 701 permission_classes = (IsAdminUser, ) 702 throttle_classes = (UserRateThrottle, ) 703 704 def get(self, request): 705 """List all users from LDAP server 706 707 Permission checking: 708 1. only admin can perform this action. 709 """ 710 711 if not request.user.admin_permissions.can_manage_user(): 712 return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') 713 714 try: 715 page = int(request.GET.get('page', '1')) 716 per_page = int(request.GET.get('per_page', '25')) 717 except ValueError: 718 page = 1 719 per_page = 25 720 721 start = (page - 1) * per_page 722 end = page * per_page + 1 723 users = ccnet_api.get_emailusers('LDAP', start, end) 724 725 if len(users) == end - start: 726 users = users[:per_page] 727 has_next_page = True 728 else: 729 has_next_page = False 730 731 data = [] 732 for user in users: 733 info = {} 734 info['email'] = user.email 735 info['quota_total'] = seafile_api.get_user_quota(user.email) 736 info['quota_usage'] = seafile_api.get_user_self_usage(user.email) 737 info['create_time'] = timestamp_to_isoformat_timestr(user.ctime) 738 739 last_login_obj = UserLastLogin.objects.get_by_username(user.email) 740 if last_login_obj: 741 info['last_login'] = datetime_to_isoformat_timestr(last_login_obj.last_login) 742 info['last_access_time'] = get_user_last_access_time(user.email, 743 last_login_obj.last_login) 744 else: 745 info['last_login'] = '' 746 info['last_access_time'] = get_user_last_access_time(user.email, '') 747 748 data.append(info) 749 750 result = {'ldap_user_list': data, 'has_next_page': has_next_page} 751 return Response(result) 752 753 754class AdminSearchUser(APIView): 755 756 authentication_classes = (TokenAuthentication, SessionAuthentication) 757 permission_classes = (IsAdminUser, ) 758 throttle_classes = (UserRateThrottle, ) 759 760 def get(self, request): 761 """Search user from DB, LDAPImport and Profile 762 763 Permission checking: 764 1. only admin can perform this action. 765 """ 766 767 if not request.user.admin_permissions.can_manage_user(): 768 return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') 769 770 query_str = request.GET.get('query', '').lower() 771 if not query_str: 772 error_msg = 'query invalid.' 773 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 774 775 users = [] 776 777 page = request.GET.get('page', '') 778 per_page = request.GET.get('per_page', '') 779 780 if not page or not per_page: 781 782 # search user from ccnet db 783 users += ccnet_api.search_emailusers('DB', query_str, 0, 10) 784 785 # search user from ccnet ldapimport 786 users += ccnet_api.search_emailusers('LDAP', query_str, 0, 10) 787 788 ccnet_user_emails = [u.email for u in users] 789 790 # get institution for user from ccnet 791 if getattr(settings, 'MULTI_INSTITUTION', False): 792 user_institution_dict = {} 793 profiles = Profile.objects.filter(user__in=ccnet_user_emails) 794 for profile in profiles: 795 email = profile.user 796 if email not in user_institution_dict: 797 user_institution_dict[email] = profile.institution 798 799 for user in users: 800 user.institution = user_institution_dict.get(user.email, '') 801 802 # search user from profile 803 searched_profile = Profile.objects.filter((Q(nickname__icontains=query_str)) | \ 804 Q(contact_email__icontains=query_str))[:10] 805 806 for profile in searched_profile: 807 email = profile.user 808 institution = profile.institution 809 810 # remove duplicate emails 811 if email not in ccnet_user_emails: 812 try: 813 # get is_staff and is_active info 814 user = User.objects.get(email=email) 815 user.institution = institution 816 users.append(user) 817 except User.DoesNotExist: 818 continue 819 820 page_info = { 821 'has_next_page': '', 822 'current_page': '' 823 } 824 825 else: 826 827 try: 828 page = int(page) 829 per_page = int(per_page) 830 except ValueError: 831 page = 1 832 per_page = 25 833 834 ccnet_users = [] 835 ccnet_db_users = ccnet_api.search_emailusers('DB', query_str, 0, page * per_page) 836 ccnet_ldap_import_users = [] 837 838 if len(ccnet_db_users) == page * per_page: 839 840 # users from ccnet db is enough 841 ccnet_users = ccnet_db_users[-per_page:] 842 843 elif len(ccnet_db_users) < page * per_page: 844 845 ccnet_ldap_import_users = ccnet_api.search_emailusers('LDAP', 846 query_str, 847 0, 848 page*per_page - len(ccnet_db_users)) 849 850 if int(len(ccnet_db_users)/per_page) == page-1: 851 # need ccnet_db_users + ccnet_ldap_import_users 852 ccnet_users = ccnet_db_users[(page-1)*per_page-len(ccnet_db_users):] + ccnet_ldap_import_users 853 854 if int(len(ccnet_db_users)/per_page) < page-1: 855 # users only from ccnet_ldap_import_users 856 ccnet_users = ccnet_ldap_import_users[-per_page:] 857 858 # search user from profile 859 profile_users = [] 860 all_ccnet_users = ccnet_db_users + ccnet_ldap_import_users 861 all_profile_users = [] 862 863 if len(all_ccnet_users) == page * per_page: 864 865 # users from ccnet is enough 866 users = ccnet_users 867 868 if len(all_ccnet_users) < page * per_page: 869 all_profile_users = Profile.objects.filter((Q(nickname__icontains=query_str)) | \ 870 Q(contact_email__icontains=query_str)) \ 871 [0:page*per_page-len(all_ccnet_users)] 872 873 if int(len(all_ccnet_users)/per_page) == page-1: 874 # need ccnet users + profile users 875 tmp_users = [] 876 for profile_user in all_profile_users: 877 try: 878 user = User.objects.get(email=profile_user.user) 879 tmp_users.append(user) 880 except User.DoesNotExist: 881 continue 882 883 users = ccnet_users + tmp_users 884 885 if int(len(all_ccnet_users)/per_page) < page-1: 886 # only need profile users 887 for profile_user in list(all_profile_users)[-per_page:]: 888 try: 889 user = User.objects.get(email=profile_user.user) 890 users.append(user) 891 except User.DoesNotExist: 892 continue 893 894 if len(all_ccnet_users) + len(all_profile_users) >= page * per_page: 895 has_next_page = True 896 else: 897 has_next_page = False 898 899 page_info = { 900 'has_next_page': has_next_page, 901 'current_page': page 902 } 903 904 # get institution for user from ccnet 905 if getattr(settings, 'MULTI_INSTITUTION', False): 906 for user in users: 907 if not hasattr(user, 'institution'): 908 profile = Profile.objects.filter(user=user.email) 909 user.institution = profile.institution 910 911 data = [] 912 has_appended = [] 913 914 for user in users: 915 916 if user.email in has_appended: 917 continue 918 else: 919 has_appended.append(user.email) 920 921 info = {} 922 info['email'] = user.email 923 info['name'] = email2nickname(user.email) 924 info['contact_email'] = email2contact_email(user.email) 925 926 info['is_staff'] = user.is_staff 927 info['is_active'] = user.is_active 928 929 info['source'] = user.source.lower() 930 931 orgs = ccnet_api.get_orgs_by_user(user.email) 932 if orgs: 933 org_id = orgs[0].org_id 934 info['org_id'] = org_id 935 info['org_name'] = orgs[0].org_name 936 info['quota_usage'] = seafile_api.get_org_user_quota_usage(org_id, user.email) 937 info['quota_total'] = seafile_api.get_org_user_quota(org_id, user.email) 938 else: 939 info['quota_usage'] = seafile_api.get_user_self_usage(user.email) 940 info['quota_total'] = seafile_api.get_user_quota(user.email) 941 942 info['create_time'] = timestamp_to_isoformat_timestr(user.ctime) 943 944 last_login_obj = UserLastLogin.objects.get_by_username(user.email) 945 if last_login_obj: 946 info['last_login'] = datetime_to_isoformat_timestr(last_login_obj.last_login) 947 info['last_access_time'] = get_user_last_access_time(user.email, 948 last_login_obj.last_login) 949 else: 950 info['last_login'] = '' 951 info['last_access_time'] = get_user_last_access_time(user.email, '') 952 953 info['role'] = get_user_role(user) 954 955 if getattr(settings, 'MULTI_INSTITUTION', False): 956 info['institution'] = user.institution 957 958 data.append(info) 959 960 result = { 961 'user_list': data, 962 'page_info': page_info, 963 } 964 return Response(result) 965 966 967class AdminUser(APIView): 968 969 authentication_classes = (TokenAuthentication, SessionAuthentication) 970 permission_classes = (IsAdminUser, ) 971 throttle_classes = (UserRateThrottle, ) 972 973 def get(self, request, email): 974 975 if not (request.user.admin_permissions.can_manage_user() or \ 976 request.user.admin_permissions.can_update_user()): 977 return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') 978 979 avatar_size = request.data.get('avatar_size', 64) 980 try: 981 avatar_size = int(avatar_size) 982 except Exception as e: 983 logger.error(e) 984 error_msg = 'avatar_size invalid.' 985 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 986 987 try: 988 User.objects.get(email=email) 989 except User.DoesNotExist: 990 error_msg = 'User %s not found.' % email 991 return api_error(status.HTTP_404_NOT_FOUND, error_msg) 992 993 user_info = get_user_info(email) 994 user_info['avatar_url'], _, _ = api_avatar_url(email, avatar_size) 995 996 return Response(user_info) 997 998 def put(self, request, email): 999 1000 if not (request.user.admin_permissions.can_manage_user() or \ 1001 request.user.admin_permissions.can_update_user()): 1002 return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') 1003 1004 # basic user info check 1005 is_staff = request.data.get("is_staff", None) 1006 if is_staff: 1007 try: 1008 is_staff = to_python_boolean(is_staff) 1009 except ValueError: 1010 error_msg = 'is_staff invalid.' 1011 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 1012 1013 is_active = request.data.get("is_active", None) 1014 if is_active: 1015 try: 1016 is_active = to_python_boolean(is_active) 1017 except ValueError: 1018 error_msg = 'is_active invalid.' 1019 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 1020 1021 # additional user info check 1022 role = request.data.get("role", None) 1023 if role: 1024 available_roles = get_available_roles() 1025 if role not in available_roles: 1026 error_msg = 'role must be in %s.' % str(available_roles) 1027 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 1028 1029 name = request.data.get("name", None) 1030 if name: 1031 if len(name) > 64: 1032 error_msg = 'Name is too long (maximum is 64 characters).' 1033 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 1034 1035 if "/" in name: 1036 error_msg = "Name should not include '/'." 1037 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 1038 1039 # argument check for login_id 1040 login_id = request.data.get("login_id", None) 1041 if login_id is not None: 1042 login_id = login_id.strip() 1043 username_by_login_id = Profile.objects.get_username_by_login_id(login_id) 1044 if username_by_login_id is not None: 1045 return api_error(status.HTTP_400_BAD_REQUEST, 1046 _("Login id %s already exists." % login_id)) 1047 1048 contact_email = request.data.get("contact_email", None) 1049 if contact_email is not None and contact_email.strip() != '': 1050 if not is_valid_email(contact_email): 1051 error_msg = 'Contact email invalid.' 1052 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 1053 1054 password = request.data.get("password") 1055 1056 reference_id = request.data.get("reference_id", None) 1057 if reference_id: 1058 if ' ' in reference_id: 1059 return api_error(status.HTTP_400_BAD_REQUEST, 'Reference ID can not contain spaces.') 1060 primary_id = ccnet_api.get_primary_id(reference_id) 1061 if primary_id: 1062 return api_error(status.HTTP_400_BAD_REQUEST, 'Reference ID %s already exists.' % reference_id) 1063 1064 quota_total_mb = request.data.get("quota_total", None) 1065 if quota_total_mb: 1066 try: 1067 quota_total_mb = int(quota_total_mb) 1068 except ValueError: 1069 error_msg = "Must be an integer that is greater than or equal to 0." 1070 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 1071 1072 if quota_total_mb < 0: 1073 error_msg = "Space quota is too low (minimum value is 0)." 1074 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 1075 1076 if is_org_context(request): 1077 org_id = request.user.org.org_id 1078 org_quota_mb = seafile_api.get_org_quota(org_id) / get_file_size_unit('MB') 1079 1080 if quota_total_mb > org_quota_mb: 1081 error_msg = 'Failed to set quota: maximum quota is %d MB' % org_quota_mb 1082 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 1083 1084 institution = request.data.get("institution", None) 1085 if institution: 1086 try: 1087 Institution.objects.get(name=institution) 1088 except Institution.DoesNotExist: 1089 error_msg = 'Institution %s does not exist' % institution 1090 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 1091 1092 # query user info 1093 try: 1094 user_obj = User.objects.get(email=email) 1095 except User.DoesNotExist: 1096 error_msg = 'User %s not found.' % email 1097 return api_error(status.HTTP_404_NOT_FOUND, error_msg) 1098 1099 try: 1100 update_user_info(request, user=user_obj, password=password, is_active=is_active, is_staff=is_staff, 1101 role=role, nickname=name, login_id=login_id, contact_email=contact_email, 1102 reference_id=reference_id, quota_total_mb=quota_total_mb, institution_name=institution) 1103 except Exception as e: 1104 logger.error(e) 1105 error_msg = 'Internal Server Error' 1106 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 1107 1108 # update user 1109 try: 1110 user_obj.save() 1111 except Exception as e: 1112 logger.error(e) 1113 error_msg = 'Internal Server Error' 1114 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 1115 1116 update_status_tip = '' 1117 if is_active is not None: 1118 update_status_tip = _('Edit succeeded') 1119 if user_obj.is_active and IS_EMAIL_CONFIGURED: 1120 try: 1121 send_html_email(_(u'Your account on %s is activated') % get_site_name(), 1122 'sysadmin/user_activation_email.html', 1123 {'username': user_obj.email}, 1124 None, 1125 [email2contact_email(user_obj.email)]) 1126 update_status_tip = _('Edit succeeded, an email has been sent.') 1127 except Exception as e: 1128 logger.error(e) 1129 update_status_tip = _('Edit succeeded, but failed to send email, please check your email configuration.') 1130 1131 user_info = get_user_info(email) 1132 user_info['update_status_tip'] = update_status_tip 1133 1134 return Response(user_info) 1135 1136 def delete(self, request, email): 1137 1138 if not request.user.admin_permissions.can_manage_user(): 1139 return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') 1140 1141 try: 1142 User.objects.get(email=email) 1143 except User.DoesNotExist: 1144 error_msg = 'User %s not found.' % email 1145 return api_error(status.HTTP_404_NOT_FOUND, error_msg) 1146 1147 # delete user 1148 try: 1149 User.objects.get(email=email).delete() 1150 except Exception as e: 1151 logger.error(e) 1152 error_msg = 'Internal Server Error' 1153 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 1154 1155 # send admin operation log signal 1156 admin_op_detail = { 1157 "email": email, 1158 } 1159 admin_operation.send(sender=None, admin_name=request.user.username, 1160 operation=USER_DELETE, detail=admin_op_detail) 1161 1162 return Response({'success': True}) 1163 1164 1165class AdminUserResetPassword(APIView): 1166 1167 authentication_classes = (TokenAuthentication, SessionAuthentication) 1168 permission_classes = (IsAdminUser, ) 1169 throttle_classes = (UserRateThrottle, ) 1170 1171 def put(self, request, email): 1172 """Reset password for user 1173 1174 Permission checking: 1175 1. only admin can perform this action. 1176 """ 1177 1178 if not request.user.admin_permissions.can_manage_user(): 1179 return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') 1180 1181 if not is_valid_username2(email): 1182 error_msg = 'email invalid' 1183 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 1184 1185 try: 1186 user = User.objects.get(email=email) 1187 except User.DoesNotExist as e: 1188 logger.error(e) 1189 error_msg = 'email invalid.' 1190 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 1191 1192 if isinstance(INIT_PASSWD, FunctionType): 1193 new_password = INIT_PASSWD() 1194 else: 1195 new_password = INIT_PASSWD 1196 user.set_password(new_password) 1197 user.save() 1198 1199 if config.FORCE_PASSWORD_CHANGE: 1200 UserOptions.objects.set_force_passwd_change(user.username) 1201 1202 if IS_EMAIL_CONFIGURED: 1203 if SEND_EMAIL_ON_RESETTING_USER_PASSWD: 1204 c = {'email': email, 'password': new_password} 1205 contact_email = Profile.objects.get_contact_email_by_user(email) 1206 try: 1207 send_html_email(_(u'Password has been reset on %s') % get_site_name(), 1208 'sysadmin/user_reset_email.html', c, None, [contact_email]) 1209 reset_tip = _('Successfully reset password to %(passwd)s, an email has been sent to %(user)s.') % \ 1210 {'passwd': new_password, 'user': contact_email} 1211 except Exception as e: 1212 logger.warning(e) 1213 reset_tip = _('Successfully reset password to %(passwd)s, but failed to send email to %(user)s, please check your email configuration.') % \ 1214 {'passwd': new_password, 'user': email} 1215 else: 1216 reset_tip = _('Successfully reset password to %(passwd)s for user %(user)s.') % \ 1217 {'passwd': new_password, 'user': email} 1218 else: 1219 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.') % \ 1220 {'passwd': new_password, 'user': email} 1221 1222 return Response({'new_password': new_password, 'reset_tip': reset_tip}) 1223 1224 1225class AdminUserGroups(APIView): 1226 1227 authentication_classes = (TokenAuthentication, SessionAuthentication) 1228 permission_classes = (IsAdminUser, ) 1229 throttle_classes = (UserRateThrottle, ) 1230 1231 def get(self, request, email): 1232 """ return all groups user joined 1233 1234 Permission checking: 1235 1. Admin user; 1236 """ 1237 1238 if not request.user.admin_permissions.can_manage_user(): 1239 return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') 1240 1241 try: 1242 User.objects.get(email=email) 1243 except User.DoesNotExist as e: 1244 logger.error(e) 1245 error_msg = 'User %s not found.' % email 1246 return api_error(status.HTTP_404_NOT_FOUND, error_msg) 1247 1248 groups_info = [] 1249 try: 1250 groups = ccnet_api.get_groups(email) 1251 except Exception as e: 1252 logger.error(e) 1253 error_msg = 'Internal Server Error' 1254 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 1255 1256 # Use dict to reduce memcache fetch cost in large for-loop. 1257 nickname_dict = {} 1258 creator_name_set = set([g.creator_name for g in groups]) 1259 for e in creator_name_set: 1260 if e not in nickname_dict: 1261 nickname_dict[e] = email2nickname(e) 1262 1263 for group in groups: 1264 isoformat_timestr = timestamp_to_isoformat_timestr(group.timestamp) 1265 group_info = { 1266 "id": group.id, 1267 "name": group.group_name, 1268 "owner_email": group.creator_name, 1269 "owner_name": nickname_dict.get(group.creator_name, ''), 1270 "created_at": isoformat_timestr, 1271 "parent_group_id": group.parent_group_id if is_pro_version() else 0 1272 } 1273 groups_info.append(group_info) 1274 1275 try: 1276 is_group_staff = ccnet_api.check_group_staff(group.id, email) 1277 except Exception as e: 1278 logger.error(e) 1279 error_msg = 'Internal Server Error' 1280 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 1281 1282 if email == group.creator_name: 1283 group_info['role'] = 'Owner' 1284 elif is_group_staff: 1285 group_info['role'] = 'Admin' 1286 else: 1287 group_info['role'] = 'Member' 1288 return Response({'group_list': groups_info}) 1289 1290 1291class AdminUserShareLinks(APIView): 1292 authentication_classes = (TokenAuthentication, SessionAuthentication) 1293 permission_classes = (IsAdminUser,) 1294 throttle_classes = (UserRateThrottle,) 1295 1296 def get(self, request, email): 1297 """ Get all shared download links of a user. 1298 1299 Permission checking: 1300 1. only admin can perform this action. 1301 """ 1302 1303 if not request.user.admin_permissions.can_manage_user(): 1304 return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') 1305 1306 try: 1307 User.objects.get(email=email) 1308 except User.DoesNotExist as e: 1309 logger.error(e) 1310 error_msg = 'User %s not found.' % email 1311 return api_error(status.HTTP_404_NOT_FOUND, error_msg) 1312 1313 share_links = FileShare.objects.filter(username=email) 1314 1315 links_info = [] 1316 for fs in share_links: 1317 link_info = get_user_share_link_info(fs) 1318 links_info.append(link_info) 1319 1320 return Response({'share_link_list': links_info}) 1321 1322 1323class AdminUserUploadLinks(APIView): 1324 authentication_classes = (TokenAuthentication, SessionAuthentication) 1325 permission_classes = (IsAdminUser,) 1326 throttle_classes = (UserRateThrottle,) 1327 1328 def get(self, request, email): 1329 """ Get all shared upload links of a user. 1330 1331 Permission checking: 1332 1. only admin can perform this action. 1333 """ 1334 1335 if not request.user.admin_permissions.can_manage_user(): 1336 return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') 1337 1338 try: 1339 User.objects.get(email=email) 1340 except User.DoesNotExist as e: 1341 logger.error(e) 1342 error_msg = 'User %s not found.' % email 1343 return api_error(status.HTTP_404_NOT_FOUND, error_msg) 1344 1345 upload_links = UploadLinkShare.objects.filter(username=email) 1346 1347 links_info = [] 1348 for fs in upload_links: 1349 link_info = get_user_upload_link_info(fs) 1350 links_info.append(link_info) 1351 1352 return Response({'upload_link_list': links_info}) 1353 1354 1355class AdminUserBeSharedRepos(APIView): 1356 1357 authentication_classes = (TokenAuthentication, SessionAuthentication) 1358 throttle_classes = (UserRateThrottle,) 1359 permission_classes = (IsAdminUser,) 1360 1361 def get(self, request, email): 1362 """ List 'all' libraries shared to a user 1363 1364 Permission checking: 1365 1. only admin can perform this action. 1366 """ 1367 1368 if not request.user.admin_permissions.can_manage_user(): 1369 return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') 1370 1371 try: 1372 User.objects.get(email=email) 1373 except User.DoesNotExist as e: 1374 logger.error(e) 1375 error_msg = 'User %s not found.' % email 1376 return api_error(status.HTTP_404_NOT_FOUND, error_msg) 1377 1378 try: 1379 beshared_repos = seafile_api.get_share_in_repo_list(email, -1, -1) 1380 except Exception as e: 1381 logger.error(e) 1382 error_msg = 'Internal Server Error' 1383 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 1384 1385 # Use dict to reduce memcache fetch cost in large for-loop. 1386 nickname_dict = {} 1387 owner_set = set([x.user for x in beshared_repos]) 1388 for email in owner_set: 1389 if email not in nickname_dict: 1390 if '@seafile_group' in email: 1391 group_id = get_group_id_by_repo_owner(email) 1392 group_name = group_id_to_name(group_id) 1393 nickname_dict[email] = group_name 1394 else: 1395 nickname_dict[email] = email2nickname(email) 1396 1397 repos_info = [] 1398 for repo in beshared_repos: 1399 repo_info = {} 1400 repo_info['id'] = repo.repo_id 1401 repo_info['name'] = repo.repo_name 1402 repo_info['owner_email'] = repo.user 1403 repo_info['owner_name'] = nickname_dict.get(repo.user, '') 1404 repo_info['size'] = repo.size 1405 repo_info['encrypted'] = repo.encrypted 1406 repo_info['file_count'] = repo.file_count 1407 repo_info['status'] = normalize_repo_status_code(repo.status) 1408 repo_info['last_modify'] = timestamp_to_isoformat_timestr(repo.last_modify) 1409 1410 repos_info.append(repo_info) 1411 1412 return Response({'repo_list': repos_info}) 1413 1414 1415class AdminUpdateUserCcnetEmail(APIView): 1416 1417 authentication_classes = (TokenAuthentication, SessionAuthentication) 1418 permission_classes = (IsAdminUser, ) 1419 throttle_classes = (UserRateThrottle, ) 1420 1421 def put(self, request): 1422 """update ccnet email 1423 1424 Permission checking: 1425 1. only admin can perform this action. 1426 """ 1427 1428 # argument check 1429 old_ccnet_email = request.data.get("old_email", None) 1430 if not old_ccnet_email: 1431 error_msg = 'old_email invalid.' 1432 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 1433 1434 new_ccnet_email = request.data.get("new_email", None) 1435 if not new_ccnet_email: 1436 error_msg = 'new_email invalid.' 1437 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 1438 1439 new_ccnet_email = new_ccnet_email.strip() 1440 if not is_valid_email(new_ccnet_email): 1441 error_msg = 'new_email invalid.' 1442 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 1443 1444 # resource check 1445 if not ccnet_api.get_emailuser(old_ccnet_email): 1446 error_msg = 'User %s not found.' % old_ccnet_email 1447 return api_error(status.HTTP_404_NOT_FOUND, error_msg) 1448 1449 if ccnet_api.get_emailuser(new_ccnet_email): 1450 error_msg = "User %s already exists." % new_ccnet_email 1451 return api_error(status.HTTP_400_BAD_REQUEST, error_msg) 1452 1453 # update 1454 try: 1455 ccnet_api.update_emailuser_id(old_ccnet_email, new_ccnet_email) 1456 logger.debug('the ccnet database was successfully updated') 1457 except Exception as e: 1458 logger.error(e) 1459 error_msg = 'Internal Server Error' 1460 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 1461 1462 try: 1463 from seahub.api2.models import Token 1464 token_list = Token.objects.filter(user=old_ccnet_email) 1465 for token in token_list: 1466 token.user = new_ccnet_email 1467 token.save() 1468 logger.debug('the api2_token table in seahub database was successfully updated') 1469 except Exception as e: 1470 logger.error(e) 1471 error_msg = 'Internal Server Error' 1472 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 1473 1474 try: 1475 from seahub.api2.models import TokenV2 1476 tokenv2_list = TokenV2.objects.filter(user=old_ccnet_email) 1477 for tokenv2 in tokenv2_list: 1478 tokenv2.user = new_ccnet_email 1479 tokenv2.save() 1480 logger.debug('the api2_tokenv2 table in seahub database was successfully updated') 1481 except Exception as e: 1482 logger.error(e) 1483 error_msg = 'Internal Server Error' 1484 return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) 1485 1486 try: 1487 from seahub.admin_log.models import AdminLog 1488 adminlog_list = AdminLog.objects.filter(email=old_ccnet_email) 1489 for adminlog in adminlog_list: 1490 adminlog.email = new_ccnet_email 1491 adminlog.save() 1492 logger.debug('the admin_log_adminlog table in seahub database was successfully updated') 1493 except Exception as e: 1494 logger.error(e) 1495 1496 try: 1497 from seahub.avatar.models import Avatar 1498 avatar_list = Avatar.objects.filter(emailuser=old_ccnet_email) 1499 for avatar in avatar_list: 1500 avatar.emailuser = new_ccnet_email 1501 avatar.save() 1502 logger.debug('the avatar_avatar table in seahub database was successfully updated') 1503 except Exception as e: 1504 logger.error(e) 1505 1506 try: 1507 from seahub.base.models import ClientLoginToken 1508 clientlogintoken_list = ClientLoginToken.objects.filter(username=old_ccnet_email) 1509 for clientlogintoken in clientlogintoken_list: 1510 clientlogintoken.username = new_ccnet_email 1511 clientlogintoken.save() 1512 logger.debug('the base_clientlogintoken table in seahub database was successfully updated') 1513 except Exception as e: 1514 logger.error(e) 1515 1516 try: 1517 from seahub.base.models import DeviceToken 1518 devicetoken_list = DeviceToken.objects.filter(user=old_ccnet_email) 1519 for devicetoken in devicetoken_list: 1520 devicetoken.user = new_ccnet_email 1521 devicetoken.save() 1522 logger.debug('the base_devicetoken table in seahub database was successfully updated') 1523 except Exception as e: 1524 logger.error(e) 1525 1526 try: 1527 from seahub.base.models import FileComment 1528 filecomment_list = FileComment.objects.filter(author=old_ccnet_email) 1529 for filecomment in filecomment_list: 1530 filecomment.author = new_ccnet_email 1531 filecomment.save() 1532 logger.debug('the base_filecomment table in seahub database was successfully updated') 1533 except Exception as e: 1534 logger.error(e) 1535 1536 try: 1537 from seahub.base.models import UserLastLogin 1538 userlastlogin_list = UserLastLogin.objects.filter(username=old_ccnet_email) 1539 for userlastlogin in userlastlogin_list: 1540 userlastlogin.username = new_ccnet_email 1541 userlastlogin.save() 1542 logger.debug('the base_userlastlogin table in seahub database was successfully updated') 1543 except Exception as e: 1544 logger.error(e) 1545 1546 try: 1547 from seahub.base.models import UserStarredFiles 1548 userstarredfiles_list = UserStarredFiles.objects.filter(email=old_ccnet_email) 1549 for userstarredfiles in userstarredfiles_list: 1550 userstarredfiles.email = new_ccnet_email 1551 userstarredfiles.save() 1552 logger.debug('the base_userstarredfiles table in seahub database was successfully updated') 1553 except Exception as e: 1554 logger.error(e) 1555 1556 try: 1557 from seahub.drafts.models import Draft 1558 draft_list = Draft.objects.filter(username=old_ccnet_email) 1559 for draft in draft_list: 1560 draft.username = new_ccnet_email 1561 draft.save() 1562 logger.debug('the drafts_draft table in seahub database was successfully updated') 1563 except Exception as e: 1564 logger.error(e) 1565 1566 try: 1567 from seahub.drafts.models import DraftReviewer 1568 draftreviewer_list = DraftReviewer.objects.filter(reviewer=old_ccnet_email) 1569 for draftreviewer in draftreviewer_list: 1570 draftreviewer.reviewer = new_ccnet_email 1571 draftreviewer.save() 1572 logger.debug('the drafts_draftreviewer table in seahub database was successfully updated') 1573 except Exception as e: 1574 logger.error(e) 1575 1576 try: 1577 from seahub.file_participants.models import FileParticipant 1578 fileparticipant_list = FileParticipant.objects.filter(username=old_ccnet_email) 1579 for fileparticipant in fileparticipant_list: 1580 fileparticipant.username = new_ccnet_email 1581 fileparticipant.save() 1582 logger.debug('the file_participants_fileparticipant table in seahub database was successfully updated') 1583 except Exception as e: 1584 logger.error(e) 1585 1586 try: 1587 from seahub.institutions.models import InstitutionAdmin 1588 institutionadmin_list = InstitutionAdmin.objects.filter(user=old_ccnet_email) 1589 for institutionadmin in institutionadmin_list: 1590 institutionadmin.user = new_ccnet_email 1591 institutionadmin.save() 1592 logger.debug('the institutions_institutionadmin table in seahub database was successfully updated') 1593 except Exception as e: 1594 logger.error(e) 1595 1596 try: 1597 from seahub.invitations.models import Invitation 1598 invitation_list = Invitation.objects.filter(inviter=old_ccnet_email) 1599 for invitation in invitation_list: 1600 invitation.inviter = new_ccnet_email 1601 invitation.save() 1602 logger.debug('the invitations_invitation table in seahub database was successfully updated') 1603 except Exception as e: 1604 logger.error(e) 1605 1606 try: 1607 from seahub.notifications.models import UserNotification 1608 usernotification_list = UserNotification.objects.filter(to_user=old_ccnet_email) 1609 for usernotification in usernotification_list: 1610 usernotification.to_user = new_ccnet_email 1611 usernotification.save() 1612 logger.debug('the notifications_usernotification table in seahub database was successfully updated') 1613 except Exception as e: 1614 logger.error(e) 1615 1616 try: 1617 from seahub.options.models import UserOptions 1618 useroptions_list = UserOptions.objects.filter(email=old_ccnet_email) 1619 for useroptions in useroptions_list: 1620 useroptions.email = new_ccnet_email 1621 useroptions.save() 1622 logger.debug('the options_useroptions table in seahub database was successfully updated') 1623 except Exception as e: 1624 logger.error(e) 1625 1626 try: 1627 from seahub.profile.models import DetailedProfile 1628 detailedprofile_list = DetailedProfile.objects.filter(user=old_ccnet_email) 1629 for detailedprofile in detailedprofile_list: 1630 detailedprofile.user = new_ccnet_email 1631 detailedprofile.save() 1632 logger.debug('the profile_detailedprofile table in seahub database was successfully updated') 1633 except Exception as e: 1634 logger.error(e) 1635 1636 try: 1637 from seahub.profile.models import Profile 1638 profile_list = Profile.objects.filter(user=old_ccnet_email) 1639 for profile in profile_list: 1640 profile.user = new_ccnet_email 1641 profile.save() 1642 logger.debug('the profile_profile table in seahub database was successfully updated') 1643 except Exception as e: 1644 logger.error(e) 1645 1646 try: 1647 from seahub.role_permissions.models import AdminRole 1648 adminrole_list = AdminRole.objects.filter(email=old_ccnet_email) 1649 for adminrole in adminrole_list: 1650 adminrole.email = new_ccnet_email 1651 adminrole.save() 1652 logger.debug('the role_permissions_adminrole table in seahub database was successfully updated') 1653 except Exception as e: 1654 logger.error(e) 1655 1656 try: 1657 from seahub.share.models import AnonymousShare 1658 anonymousshare_list = AnonymousShare.objects.filter(repo_owner=old_ccnet_email) 1659 for anonymousshare in anonymousshare_list: 1660 anonymousshare.repo_owner = new_ccnet_email 1661 anonymousshare.save() 1662 logger.debug('the share_anonymousshare table in seahub database was successfully updated') 1663 except Exception as e: 1664 logger.error(e) 1665 1666 try: 1667 from seahub.share.models import FileShare 1668 fileshare_list = FileShare.objects.filter(username=old_ccnet_email) 1669 for fileshare in fileshare_list: 1670 fileshare.username = new_ccnet_email 1671 fileshare.save() 1672 logger.debug('the share_fileshare table in seahub database was successfully updated') 1673 except Exception as e: 1674 logger.error(e) 1675 1676 try: 1677 from seahub.share.models import UploadLinkShare 1678 uploadlinkshare_list = UploadLinkShare.objects.filter(username=old_ccnet_email) 1679 for uploadlinkshare in uploadlinkshare_list: 1680 uploadlinkshare.username = new_ccnet_email 1681 uploadlinkshare.save() 1682 logger.debug('the share_uploadlinkshare table in seahub database was successfully updated') 1683 except Exception as e: 1684 logger.error(e) 1685 1686 try: 1687 from seahub.auth.models import SocialAuthUser 1688 socialauthuser_list = SocialAuthUser.objects.filter(username=old_ccnet_email) 1689 for socialauthuser in socialauthuser_list: 1690 socialauthuser.username = new_ccnet_email 1691 socialauthuser.save() 1692 logger.debug('the social_auth_usersocialauth table in seahub database was successfully updated') 1693 except Exception as e: 1694 logger.error(e) 1695 1696 try: 1697 from seahub_extra.sysadmin_extra.models import UserLoginLog 1698 userlastlogin_list = UserLoginLog.objects.filter(username=old_ccnet_email) 1699 for userlastlogin in userlastlogin_list: 1700 userlastlogin.username = new_ccnet_email 1701 userlastlogin.save() 1702 logger.debug('the sysadmin_extra_userloginlog table in seahub database was successfully updated') 1703 except Exception as e: 1704 logger.error(e) 1705 1706 try: 1707 from seahub.tags.models import FileTag 1708 filetag_list = FileTag.objects.filter(username=old_ccnet_email) 1709 for filetag in filetag_list: 1710 filetag.username = new_ccnet_email 1711 filetag.save() 1712 logger.debug('the tags_filetag table in seahub database was successfully updated') 1713 except Exception as e: 1714 logger.error(e) 1715 1716 try: 1717 from termsandconditions.models import UserTermsAndConditions 1718 usertermsandconditions_list = UserTermsAndConditions.objects.filter(username=old_ccnet_email) 1719 for usertermsandconditions in usertermsandconditions_list: 1720 usertermsandconditions.username = new_ccnet_email 1721 usertermsandconditions.save() 1722 logger.debug('the termsandconditions_usertermsandconditions table in seahub database was successfully updated') 1723 except Exception as e: 1724 logger.error(e) 1725 1726 try: 1727 from seahub.wiki.models import Wiki 1728 wiki_list = Wiki.objects.filter(username=old_ccnet_email) 1729 for wiki in wiki_list: 1730 wiki.username = new_ccnet_email 1731 wiki.save() 1732 logger.debug('the wiki_wiki table in seahub database was successfully updated') 1733 except Exception as e: 1734 logger.error(e) 1735 1736 try: 1737 from seahub.ocm.models import OCMShare 1738 ocmshare_list = OCMShare.objects.filter(from_user=old_ccnet_email) 1739 for ocmshare in ocmshare_list: 1740 ocmshare.from_user = new_ccnet_email 1741 ocmshare.save() 1742 logger.debug('the ocm_share table in seahub database was successfully updated') 1743 except Exception as e: 1744 logger.error(e) 1745 1746 try: 1747 from seahub.ocm.models import OCMShareReceived 1748 ocmsharereceived_list = OCMShareReceived.objects.filter(to_user=old_ccnet_email) 1749 for ocmsharereceived in ocmsharereceived_list: 1750 ocmsharereceived.to_user = new_ccnet_email 1751 ocmsharereceived.save() 1752 logger.debug('the ocm_share_received table in seahub database was successfully updated') 1753 except Exception as e: 1754 logger.error(e) 1755 1756 return Response({'success': True}) 1757