def create_ldap_user(self, email=None, password=None, nickname=None, is_staff=False, is_active=False): """ Creates and saves an ldap User which can without email. """ virtual_id = gen_user_virtual_id() user = User(email=virtual_id) user.is_staff = is_staff user.is_active = is_active user.set_password(password) user.save() # Set email as contact email. if email: email = email.lower() Profile.objects.add_or_update(username=virtual_id, contact_email=email, nickname=nickname) return self.get(email=virtual_id)
def post(self, request): # parameter check user_list = request.data.get('userlist', []) if not user_list: error_msg = 'userlist invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # permission check if not ENABLE_DINGTALK: error_msg = 'Feature is not enabled.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) if not request.user.admin_permissions.can_manage_user(): return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') user_ids_in_db = [] auth_users = SocialAuthUser.objects.filter(provider='dingtalk') for user in auth_users: user_ids_in_db.append(user.uid) success = [] failed = [] for user in user_list: user_id = user.get('userid') if user_id in user_ids_in_db: failed.append({ 'userid': user_id, 'name': user.get('name'), 'error_msg': '用户已存在', }) continue email = gen_user_virtual_id() try: User.objects.create_user(email) SocialAuthUser.objects.add(email, 'dingtalk', user_id) success.append({ 'userid': user_id, 'name': user.get('name'), 'email': email, }) except Exception as e: logger.error(e) failed.append({ 'userid': user_id, 'name': user.get('name'), 'error_msg': '导入失败' }) try: update_dingtalk_user_info(email, user.get('name'), user.get('contact_email'), user.get('avatar')) except Exception as e: logger.error(e) return Response({'success': success, 'failed': failed})
def get_username(strategy, details, backend, user=None, *args, **kwargs): if 'username' not in backend.setting('USER_FIELDS', USER_FIELDS): return storage = strategy.storage if not user: final_username = gen_user_virtual_id() else: final_username = storage.user.get_username(user) return {'username': final_username}
def post(self, request): if not admin_work_weixin_departments_check(): error_msg = 'Feature is not enabled.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) if not request.user.admin_permissions.can_manage_user(): return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') api_user_list = request.data.get(WORK_WEIXIN_DEPARTMENT_MEMBERS_FIELD, None) if not api_user_list or not isinstance(api_user_list, list): error_msg = 'userlist invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) success = [] failed = [] social_auth_queryset = SocialAuthUser.objects.filter( provider=WORK_WEIXIN_PROVIDER, uid__contains=WORK_WEIXIN_UID_PREFIX) for api_user in api_user_list: error_data = _handler_work_weixin_user_data( api_user, social_auth_queryset) if not error_data: email = gen_user_virtual_id() if _import_user_from_work_weixin(email, api_user): success.append({ 'userid': api_user.get('userid'), 'name': api_user.get('name'), 'email': email, }) else: failed.append({ 'userid': api_user.get('userid'), 'name': api_user.get('name'), 'error_msg': '导入失败' }) else: failed.append(error_data) return Response({'success': success, 'failed': failed})
def create_user(self, email, password=None, is_staff=False, is_active=False): """ Creates and saves a User with given username and password. """ virtual_id = gen_user_virtual_id() # Lowercasing email address to avoid confusion. email = email.lower() user = User(email=virtual_id) user.is_staff = is_staff user.is_active = is_active user.set_password(password) user.save() # Set email as contact email. Profile.objects.add_or_update(username=virtual_id, contact_email=email) return self.get(email=virtual_id)
def post(self, request): """import department from work weixin permission: IsProVersion """ if not request.user.admin_permissions.can_manage_user(): return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') # argument check department_id = request.data.get('work_weixin_department_id') try: department_id = int(department_id) except Exception as e: logger.error(e) error_msg = 'work_weixin_department_ids invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # is pro version and work weixin check if not IsProVersion or not admin_work_weixin_departments_check(): error_msg = 'Feature is not enabled.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) access_token = get_work_weixin_access_token() if not access_token: logger.error('can not get work weixin access_token') error_msg = '获取企业微信组织架构失败' return api_error(status.HTTP_404_NOT_FOUND, error_msg) # list departments from work weixin api_department_list = self._list_departments_from_work_weixin( access_token, department_id) if api_department_list is None: error_msg = '获取企业微信组织架构失败' return api_error(status.HTTP_404_NOT_FOUND, error_msg) # list department members from work weixin api_user_list = self._list_department_members_from_work_weixin( access_token, department_id) if api_user_list is None: error_msg = '获取企业微信组织架构成员失败' return api_error(status.HTTP_404_NOT_FOUND, error_msg) # main success = list() failed = list() department_map_to_group_dict = dict() for index, department_obj in enumerate(api_department_list): # check department argument new_group_name = department_obj.get('name') department_obj_id = department_obj.get('id') if department_obj_id is None or not new_group_name or not validate_group_name( new_group_name): failed_msg = self._api_department_failed_msg( department_obj_id, new_group_name, '部门参数错误') failed.append(failed_msg) continue # check parent group if index == 0: parent_group_id = -1 else: parent_department_id = department_obj.get('parentid') parent_group_id = department_map_to_group_dict.get( parent_department_id) if parent_group_id is None: failed_msg = self._api_department_failed_msg( department_obj_id, new_group_name, '父级部门不存在') failed.append(failed_msg) continue # check department exist by group name exist, exist_group = self._admin_check_group_name_conflict( new_group_name) if exist: department_map_to_group_dict[ department_obj_id] = exist_group.id failed_msg = self._api_department_failed_msg( department_obj_id, new_group_name, '部门已存在') failed.append(failed_msg) continue # import department try: group_id = ccnet_api.create_group( new_group_name, DEPARTMENT_OWNER, parent_group_id=parent_group_id) seafile_api.set_group_quota(group_id, -2) department_map_to_group_dict[department_obj_id] = group_id success_msg = self._api_department_success_msg( department_obj_id, new_group_name, group_id) success.append(success_msg) except Exception as e: logger.error(e) failed_msg = self._api_department_failed_msg( department_obj_id, new_group_name, '部门导入失败') failed.append(failed_msg) # todo filter ccnet User database social_auth_queryset = SocialAuthUser.objects.filter( provider=WORK_WEIXIN_PROVIDER, uid__contains=WORK_WEIXIN_UID_PREFIX) # import api_user for api_user in api_user_list: uid = WORK_WEIXIN_UID_PREFIX + api_user.get('userid', '') api_user['contact_email'] = api_user['email'] api_user_name = api_user.get('name') # determine the user exists if social_auth_queryset.filter(uid=uid).exists(): email = social_auth_queryset.get(uid=uid).username else: # create user email = gen_user_virtual_id() create_user_success = _import_user_from_work_weixin( email, api_user) if not create_user_success: failed_msg = self._api_user_failed_msg( '', api_user_name, department_id, '导入用户失败') failed.append(failed_msg) continue # bind user to department api_user_department_list = api_user.get('department') for department_obj_id in api_user_department_list: group_id = department_map_to_group_dict.get(department_obj_id) if group_id is None: # the api_user also exist in the brother department which not import continue if ccnet_api.is_group_user(group_id, email): failed_msg = self._api_user_failed_msg( email, api_user_name, department_obj_id, '部门成员已存在') failed.append(failed_msg) continue try: ccnet_api.group_add_member(group_id, DEPARTMENT_OWNER, email) success_msg = self._api_user_success_msg( email, api_user_name, department_obj_id, group_id) success.append(success_msg) except Exception as e: logger.error(e) failed_msg = self._api_user_failed_msg( email, api_user_name, department_id, '导入部门成员失败') failed.append(failed_msg) return Response({ 'success': success, 'failed': failed, })
def work_weixin_oauth_callback(request): if not work_weixin_oauth_check(): return render_error(request, _('Feature is not enabled.')) code = request.GET.get('code', None) state = request.GET.get('state', None) if state != request.session.get('work_weixin_oauth_state', None) or not code: logger.error( 'can not get right code or state from work weixin request') return render_error(request, _('Error, please contact administrator.')) access_token = get_work_weixin_access_token() if not access_token: logger.error('can not get work weixin access_token') return render_error(request, _('Error, please contact administrator.')) data = { 'access_token': access_token, 'code': code, } api_response = requests.get(WORK_WEIXIN_GET_USER_INFO_URL, params=data) api_response_dic = handler_work_weixin_api_response(api_response) if not api_response_dic: logger.error('can not get work weixin user info') return render_error(request, _('Error, please contact administrator.')) if not api_response_dic.get('UserId', None): logger.error('can not get UserId in work weixin user info response') return render_error(request, _('Error, please contact administrator.')) user_id = api_response_dic.get('UserId') uid = WORK_WEIXIN_UID_PREFIX + user_id work_weixin_user = SocialAuthUser.objects.get_by_provider_and_uid( WORK_WEIXIN_PROVIDER, uid) if work_weixin_user: email = work_weixin_user.username is_new_user = False else: email = gen_user_virtual_id() SocialAuthUser.objects.add(email, WORK_WEIXIN_PROVIDER, uid) is_new_user = True try: user = auth.authenticate(remote_user=email) except User.DoesNotExist: user = None if not user: return render_error( request, _('Error, new user registration is not allowed, please contact administrator.' )) # update user info if is_new_user or WORK_WEIXIN_USER_INFO_AUTO_UPDATE: user_info_data = { 'access_token': access_token, 'userid': user_id, } user_info_api_response = requests.get(WORK_WEIXIN_GET_USER_PROFILE_URL, params=user_info_data) user_info_api_response_dic = handler_work_weixin_api_response( user_info_api_response) if user_info_api_response_dic: api_user = user_info_api_response_dic api_user['username'] = email api_user['contact_email'] = api_user['email'] update_work_weixin_user_info(api_user) if not user.is_active: return render_error( request, _('Your account is created successfully, please wait for administrator to activate your account.' )) # User is valid. Set request.user and persist user in the session # by logging the user in. request.user = user auth.login(request, user) # generate auth token for Seafile client api_token = get_api_token(request) # redirect user to page response = HttpResponseRedirect( request.session.get('work_weixin_oauth_redirect', '/')) response.set_cookie('seahub_auth', user.username + '@' + api_token.key) return response
def weixin_oauth_callback(request): if not ENABLE_WEIXIN: return render_error(request, _('Error, please contact administrator.')) state = request.GET.get('state', '') if not state or state != request.session.get('weixin_oauth_login_state', ''): logger.error('invalid state') return render_error(request, _('Error, please contact administrator.')) # get access_token and user openid parameters = { 'appid': WEIXIN_OAUTH_APP_ID, 'secret': WEIXIN_OAUTH_APP_SECRET, 'code': request.GET.get('code'), 'grant_type': WEIXIN_OAUTH_GRANT_TYPE, } access_token_url = WEIXIN_OAUTH_ACCESS_TOKEN_URL + '?' + urllib.parse.urlencode(parameters) access_token_json = requests.get(access_token_url).json() openid = access_token_json.get('openid', '') access_token = access_token_json.get('access_token', '') if not access_token or not openid: logger.error('invalid access_token or openid') logger.error(access_token_url) logger.error(access_token_json) return render_error(request, _('Error, please contact administrator.')) # login user in auth_user = SocialAuthUser.objects.get_by_provider_and_uid('weixin', openid) if auth_user: email = auth_user.username else: email = gen_user_virtual_id() SocialAuthUser.objects.add(email, 'weixin', openid) try: user = auth.authenticate(remote_user=email) except User.DoesNotExist: user = None except Exception as e: logger.error(e) return render_error(request, _('Error, please contact administrator.')) if not user or not user.is_active: return render_error(request, _('User %s not found or inactive.') % email) request.user = user auth.login(request, user) # get user profile info parameters = { 'access_token': access_token, 'openid': openid, } user_info_url = WEIXIN_OAUTH_USER_INFO_URL + '?' + urllib.parse.urlencode(parameters) user_info_resp = requests.get(user_info_url).json() name = user_info_resp['nickname'] if 'nickname' in user_info_resp else '' name = name.encode('raw_unicode_escape').decode('utf-8') if name: profile = Profile.objects.get_profile_by_user(email) if not profile: profile = Profile(user=email) profile.nickname = name.strip() profile.save() avatar_url = user_info_resp['headimgurl'] if 'headimgurl' in user_info_resp else '' try: image_name = 'dingtalk_avatar' image_file = requests.get(avatar_url).content avatar = Avatar.objects.filter(emailuser=email, primary=True).first() avatar = avatar or Avatar(emailuser=email, primary=True) avatar_file = ContentFile(image_file) avatar_file.name = image_name avatar.avatar = avatar_file avatar.save() except Exception as e: logger.error(e) # generate auth token for Seafile client api_token = get_api_token(request) # redirect user to home page response = HttpResponseRedirect(request.session['weixin_oauth_login_redirect']) response.set_cookie('seahub_auth', email + '@' + api_token.key) return response
def post(self, request): """import department from dingtalk """ if not ENABLE_DINGTALK: error_msg = 'Feature is not enabled.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) if not request.user.admin_permissions.can_manage_user(): return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') # argument check department_id = request.data.get('department_id') try: department_id = int(department_id) except Exception as e: logger.error(e) error_msg = 'department_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) access_token = dingtalk_get_access_token() if not access_token: error_msg = '获取钉钉组织架构失败' return api_error(status.HTTP_404_NOT_FOUND, error_msg) # get department list # https://developers.dingtalk.com/document/app/obtain-the-department-list data = {'access_token': access_token, 'id': department_id} current_department_resp_json = requests.get(DINGTALK_DEPARTMENT_GET_DEPARTMENT_URL, params=data).json() current_department_list = [current_department_resp_json] sub_department_resp_json = requests.get(DINGTALK_DEPARTMENT_LIST_DEPARTMENT_URL, params=data).json() sub_department_list = sub_department_resp_json.get('department', []) department_list = current_department_list + sub_department_list department_list = sorted(department_list, key=lambda x:x['id']) # get department user list data = { 'access_token': access_token, 'department_id': department_id, 'offset': 0, 'size': DINGTALK_DEPARTMENT_USER_SIZE, } user_resp_json = requests.get(DINGTALK_DEPARTMENT_GET_DEPARTMENT_USER_LIST_URL, params=data).json() api_user_list = user_resp_json.get('userlist', []) # main success = list() failed = list() department_map_to_group_dict = dict() for index, department_obj in enumerate(department_list): # check department argument new_group_name = department_obj.get('name') department_obj_id = department_obj.get('id') parent_department_id = department_obj.get('parentid', 0) if department_obj_id is None or not new_group_name or not validate_group_name(new_group_name): failed_msg = self._api_department_failed_msg( department_obj_id, new_group_name, '部门参数错误') failed.append(failed_msg) continue # check parent group if index == 0: parent_group_id = -1 else: parent_group_id = department_map_to_group_dict.get(parent_department_id) if parent_group_id is None: failed_msg = self._api_department_failed_msg( department_obj_id, new_group_name, '父级部门不存在') failed.append(failed_msg) continue # check department exist exist_department = ExternalDepartment.objects.get_by_provider_and_outer_id( DINGTALK_PROVIDER, department_obj_id) if exist_department: department_map_to_group_dict[department_obj_id] = exist_department.group_id failed_msg = self._api_department_failed_msg( department_obj_id, new_group_name, '部门已存在') failed.append(failed_msg) continue # import department try: group_id = ccnet_api.create_group( new_group_name, DEPARTMENT_OWNER, parent_group_id=parent_group_id) seafile_api.set_group_quota(group_id, -2) ExternalDepartment.objects.create( group_id=group_id, provider=DINGTALK_PROVIDER, outer_id=department_obj_id, ) department_map_to_group_dict[department_obj_id] = group_id success_msg = self._api_department_success_msg( department_obj_id, new_group_name, group_id) success.append(success_msg) except Exception as e: logger.error(e) failed_msg = self._api_department_failed_msg( department_obj_id, new_group_name, '部门导入失败') failed.append(failed_msg) # todo filter ccnet User database social_auth_queryset = SocialAuthUser.objects.filter(provider='dingtalk') # import api_user for api_user in api_user_list: uid = api_user.get('unionid', '') api_user['contact_email'] = api_user['email'] api_user_name = api_user.get('name') # determine the user exists if social_auth_queryset.filter(uid=uid).exists(): email = social_auth_queryset.get(uid=uid).username else: # create user email = gen_user_virtual_id() try: User.objects.create_user(email) SocialAuthUser.objects.add(email, 'dingtalk', uid) except Exception as e: logger.error(e) failed_msg = self._api_user_failed_msg( '', api_user_name, department_id, '导入用户失败') failed.append(failed_msg) continue # bind user to department api_user_department_list = api_user.get('department') for department_obj_id in api_user_department_list: group_id = department_map_to_group_dict.get(department_obj_id) if group_id is None: # the api_user also exist in the brother department which not import continue if ccnet_api.is_group_user(group_id, email, in_structure=False): failed_msg = self._api_user_failed_msg( email, api_user_name, department_obj_id, '部门成员已存在') failed.append(failed_msg) continue try: ccnet_api.group_add_member(group_id, DEPARTMENT_OWNER, email) success_msg = self._api_user_success_msg( email, api_user_name, department_obj_id, group_id) success.append(success_msg) except Exception as e: logger.error(e) failed_msg = self._api_user_failed_msg( email, api_user_name, department_id, '导入部门成员失败') failed.append(failed_msg) try: update_dingtalk_user_info(email, api_user.get('name'), api_user.get('contact_email'), api_user.get('avatar')) except Exception as e: logger.error(e) return Response({ 'success': success, 'failed': failed, })
def dingtalk_callback(request): if not ENABLE_DINGTALK: return render_error(request, _('Error, please contact administrator.')) state = request.GET.get('state', '') if not state or state != request.session.get('dingtalk_login_state', ''): logger.error('invalid state') return render_error(request, _('Error, please contact administrator.')) timestamp = str(int(time.time() * 1000)).encode('utf-8') appsecret = DINGTALK_QR_CONNECT_APP_SECRET.encode('utf-8') signature = base64.b64encode( hmac.new(appsecret, timestamp, digestmod=sha256).digest()) parameters = { 'accessKey': DINGTALK_QR_CONNECT_APP_ID, 'timestamp': timestamp, 'signature': signature, } code = request.GET.get('code') data = {"tmp_auth_code": code} full_user_info_url = DINGTALK_QR_CONNECT_USER_INFO_URL + '?' + urllib.parse.urlencode( parameters) user_info_resp = requests.post(full_user_info_url, data=json.dumps(data)) user_info = user_info_resp.json()['user_info'] # seahub authenticate user if 'unionid' not in user_info: logger.error('Required user info not found.') logger.error(user_info) return render_error(request, _('Error, please contact administrator.')) auth_user = SocialAuthUser.objects.get_by_provider_and_uid( 'dingtalk', user_info['unionid']) if auth_user: email = auth_user.username else: email = gen_user_virtual_id() SocialAuthUser.objects.add(email, 'dingtalk', user_info['unionid']) try: user = auth.authenticate(remote_user=email) except User.DoesNotExist: user = None except Exception as e: logger.error(e) return render_error(request, _('Error, please contact administrator.')) if not user or not user.is_active: return render_error(request, _('User %s not found or inactive.') % email) # User is valid. Set request.user and persist user in the session # by logging the user in. request.user = user request.session['remember_me'] = DINGTALK_QR_CONNECT_LOGIN_REMEMBER_ME auth.login(request, user) # update user's profile name = user_info['nick'] if 'nick' in user_info else '' if name: profile = Profile.objects.get_profile_by_user(email) if not profile: profile = Profile(user=email) profile.nickname = name.strip() profile.save() user_detail_info = dingtalk_get_detailed_user_info(user_info['unionid']) contact_email = user_detail_info.get('email', '') if contact_email: profile.contact_email = contact_email profile.save() # generate auth token for Seafile client api_token = get_api_token(request) # redirect user to home page response = HttpResponseRedirect( request.session.get('dingtalk_login_redirect', '/')) response.set_cookie('seahub_auth', email + '@' + api_token.key) return response