def post(self): ret = self.check_privilege(TP_PRIVILEGE_SYS_CONFIG) if ret != TPE_OK: return args = self.get_argument('args', None) if args is None: return self.write_json(TPE_PARAM) try: args = json.loads(args) except: return self.write_json(TPE_JSON_FORMAT) try: _server = args['server'] _port = int(args['port']) _ssl = args['ssl'] _sender = args['sender'] _password = args['password'] _recipient = args['recipient'] except: return self.write_json(TPE_PARAM) code, msg = yield mail.tp_send_mail( _recipient, '您好!\n\n这是一封测试邮件,仅用于验证系统的邮件发送模块工作是否正常。\n\n请忽略本邮件。', subject='测试邮件', sender='Teleport Server <{}>'.format(_sender), server=_server, port=_port, use_ssl=_ssl, username=_sender, password=_password) self.write_json(code, message=msg)
def post(self): ret = self.check_privilege(TP_PRIVILEGE_SYS_CONFIG) if ret != TPE_OK: return args = self.get_argument('args', None) if args is None: return self.write_json(TPE_PARAM) try: args = json.loads(args) except: return self.write_json(TPE_JSON_FORMAT) try: _server = args['server'] _port = int(args['port']) _ssl = args['ssl'] _sender = args['sender'] _password = args['password'] _recipient = args['recipient'] except: return self.write_json(TPE_PARAM) code, msg = yield mail.tp_send_mail( _recipient, '您好!\n\n这是一封测试邮件,仅用于验证系统的邮件发送模块工作是否正常。\n\n请忽略本邮件。', subject='测试邮件', sender='Teleport Server <{}>'.format(_sender), server=_server, port=_port, use_ssl=_ssl, username=_sender, password=_password ) self.write_json(code, message=msg)
def post(self): args = self.get_argument('args', None) if args is None: return self.write_json(TPE_PARAM) try: args = json.loads(args) except: return self.write_json(TPE_JSON_FORMAT) try: mode = int(args['mode']) except: return self.write_json(TPE_PARAM) password = '' if mode == 1: # 管理员直接在后台给用户发送密码重置邮件 err = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if err != TPE_OK: return self.write_json(err) try: user_id = int(args['id']) except: return self.write_json(TPE_PARAM) elif mode == 2: # 管理员直接在后台为用户重置密码 err = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if err != TPE_OK: return self.write_json(err) try: user_id = int(args['id']) password = args['password'] except: return self.write_json(TPE_PARAM) elif mode == 3: # 用户自行找回密码,需要填写用户名、邮箱、验证码 try: username = args['username'] email = args['email'] captcha = args['captcha'] except: return self.write_json(TPE_PARAM) code = self.get_session('captcha') if code is None: return self.write_json(TPE_CAPTCHA_EXPIRED, '验证码已失效') if code.lower() != captcha.lower(): return self.write_json(TPE_CAPTCHA_MISMATCH, '验证码错误') self.del_session('captcha') err, user_info = user.get_by_username(username) if err != TPE_OK: return self.write_json(err) if user_info.email != email: return self.write_json(TPE_NOT_EXISTS) user_id = user_info.id elif mode == 4: # 用户通过密码重置邮件中的链接(有token验证),在页面上设置新密码,需要提供token、新密码 try: token = args['token'] password = args['password'] except: return self.write_json(TPE_PARAM) err, user_id = user.check_reset_token(token) if err != TPE_OK: return self.write_json(err) elif mode == 5: # 用户输入当前密码和新密码进行设置 try: current_password = args['current_password'] password = args['password'] except: return self.write_json(TPE_PARAM) err, user_info = user.get_by_username( self.get_current_user()['username']) if err != TPE_OK: return self.write_json(err) if not tp_password_verify(current_password, user_info['password']): return self.write_json(TPE_USER_AUTH) user_id = user_info['id'] elif mode == 6: # 用户密码过期,在登录前进行修改 try: username = args['username'] current_password = args['password'] password = args['new_password'] captcha = args['captcha'] except: return self.write_json(TPE_PARAM) code = self.get_session('captcha') if code is None: return self.write_json(TPE_CAPTCHA_EXPIRED, '验证码已失效') if code.lower() != captcha.lower(): return self.write_json(TPE_CAPTCHA_MISMATCH, '验证码错误') self.del_session('captcha') err, user_info = user.get_by_username(username) if err != TPE_OK: return self.write_json(err) # xxx 如果是密码过期而在登录前修改密码,需要额外判断用户是否已经被锁定 # 如果用户被禁用或锁定,在登录时会被拒绝,因此此处仍然允许其修改密码 # if user_info['state'] != TP_STATE_NORMAL: # if user_info['state'] == TP_STATE_LOCKED: # return self.write_json(TPE_USER_LOCKED) # elif user_info['state'] == TP_STATE_DISABLED: # return self.write_json(TPE_USER_DISABLED) # else: # return self.write_json(TPE_FAILED) if not tp_password_verify(current_password, user_info['password']): return self.write_json(TPE_USER_AUTH) user_id = user_info['id'] else: return self.write_json(TPE_PARAM) if user_id == 0: return self.write_json(TPE_PARAM) if mode == 1 or mode == 3: err, email, token = user.generate_reset_password_token( self, user_id) # generate an URL for reset password, valid in 24hr. reset_url = '{}://{}/user/reset-password?token={}'.format( self.request.protocol, self.request.host, token) err, msg = yield mail.tp_send_mail( email, 'Teleport用户,您好!\n\n请访问以下链接以重设您的teleport登录密码。此链接将于本邮件寄出24小时之后失效。\n' '访问此链接,将会为您打开密码重置页面,然后您可以设定新密码。\n\n' '如果您并没有做重设密码的操作,请忽略本邮件,请及时联系您的系统管理员!\n\n' '{reset_url}\n\n\n\n' '[本邮件由teleport系统自动发出,请勿回复]' '\n\n' ''.format(reset_url=reset_url), subject='密码重置确认函') return self.write_json(err, msg) elif mode == 2 or mode == 4 or mode == 5 or mode == 6: if len(password) == 0: return self.write_json(TPE_PARAM) # 根据需要进行弱密码检测 if tp_cfg().sys.password.force_strong: if not tp_check_strong_password(password): return self.write_json( TPE_FAILED, '密码强度太弱!强密码需要至少8个英文字符,必须包含大写字母、小写字母和数字。') password = tp_password_generate_secret(password) err = user.set_password(self, mode, user_id, password) if mode == 4 and err == TPE_OK: user.remove_reset_token(token) # 非用户自行修改密码的情况,都默认重置身份认证 if not (mode == 5 or mode == 6) and err == TPE_OK: # print("reset oath secret") user.update_oath_secret(self, user_id, '') self.write_json(err) else: self.write_json(TPE_PARAM)
def post(self): ret = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if ret != TPE_OK: return args = self.get_argument('args', None) if args is None: return self.write_json(TPE_PARAM) try: args = json.loads(args) except: return self.write_json(TPE_JSON_FORMAT) try: args['id'] = int(args['id']) args['role'] = int(args['role']) args['auth_type'] = int(args['auth_type']) args['username'] = args['username'].strip().lower() args['surname'] = args['surname'].strip() args['email'] = args['email'].strip() args['mobile'] = args['mobile'].strip() args['qq'] = args['qq'].strip() args['wechat'] = args['wechat'].strip() if args['valid_from'] == '': args['valid_from'] = 0 else: args['valid_from'] = tp_timestamp_from_str( args['valid_from'].strip(), '%Y-%m-%d %H:%M') if args['valid_to'] == '': args['valid_to'] = 0 else: args['valid_to'] = tp_timestamp_from_str( args['valid_to'].strip(), '%Y-%m-%d %H:%M') args['desc'] = args['desc'].strip() except: return self.write_json(TPE_PARAM) if len(args['username']) == 0: return self.write_json(TPE_PARAM) if args['id'] == -1: args['password'] = tp_gen_password(8) err, _ = user.create_user(self, args) if err == TPE_OK: if len(args['email']) == 0: return self.write_json(TPE_OK) # 对于创建成功的用户,发送密码邮件函 sys_smtp_password = tp_cfg().sys_smtp_password if len(sys_smtp_password) > 0: web_url = '{}://{}'.format(self.request.protocol, self.request.host) err, msg = yield mail.tp_send_mail( args['email'], '{surname} 您好!\n\n已为您创建teleport系统用户账号,现在可以使用以下信息登录teleport系统:\n\n' '登录用户名:{username}\n' '密码:{password}\n' '地址:{web_url}\n\n\n\n' '[本邮件由teleport系统自动发出,请勿回复]' '\n\n' ''.format(surname=args['surname'], username=args['username'], password=args['password'], web_url=web_url), subject='用户密码函') if err != TPE_OK: return self.write_json( TPE_OK, '用户账号创建成功,但发送密码函失败:{}'.format(msg)) else: return self.write_json(TPE_OK) else: return self.write_json(err) else: err = user.update_user(self, args) self.write_json(err)
def post(self): """ csv导入规则: 每一行的数据格式: 用户账号,用户姓名,登录认证方式,email地址,Mobile,QQ,WeChat,所属组,描述 在导入时: 0. 以“#”作为行注释。 1. 用户账号是必须填写的,其他均为可选。 2. 一个用户属于多个组,可以用“|”将组分隔,如果某个组并不存在,则会创建这个组。 3. 空行跳过,数据格式不正确的跳过。 """ ret = dict() ret['code'] = TPE_OK ret['message'] = '' rv = self.check_privilege(TP_PRIVILEGE_USER_CREATE | TP_PRIVILEGE_USER_GROUP, need_process=False) if rv != TPE_OK: ret['code'] = rv ret['code'] = rv if rv == TPE_NEED_LOGIN: ret['message'] = '需要登录!' elif rv == TPE_PRIVILEGE: ret['message'] = '权限不足!' else: ret['message'] = '未知错误!' return self.write(json.dumps(ret).encode('utf8')) success = list() failed = list() group_failed = list() csv_filename = '' try: upload_path = os.path.join(tp_cfg().data_path, 'tmp') # 文件的暂存路径 if not os.path.exists(upload_path): os.mkdir(upload_path) file_metas = self.request.files[ 'csvfile'] # 提取表单中‘name’为‘file’的文件元数据 for meta in file_metas: now = time.localtime(time.time()) tmp_name = 'upload-{:04d}{:02d}{:02d}{:02d}{:02d}{:02d}.csv'.format( now.tm_year, now.tm_mon, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec) csv_filename = os.path.join(upload_path, tmp_name) with open(csv_filename, 'wb') as f: f.write(meta['body']) # file encode maybe utf8 or gbk... check it out. file_encode = None with open(csv_filename, encoding='gbk') as f: try: f.readlines() file_encode = 'gbk' except: pass if file_encode is None: log.v('file `{}` is not gbk, try utf8\n'.format(csv_filename)) with open(csv_filename, encoding='utf_8_sig') as f: try: f.readlines() file_encode = 'utf_8_sig' except: pass if file_encode is None: os.remove(csv_filename) log.e( 'file `{}` unknown encode, neither GBK nor UTF8.\n'.format( csv_filename)) ret['code'] = TPE_FAILED ret['message'] = '文件无法解码:不是GBK编码或者UTF8编码!' return self.write(json.dumps(ret).encode('utf8')) group_list = dict() user_list = list() # 解析csv文件 with open(csv_filename, encoding=file_encode) as f: username_list = [] # 用于检查是否有重复的用户被添加 csv_reader = csv.reader(f) line = 0 for csv_recorder in csv_reader: line += 1 # 跳过空行和注释 if len(csv_recorder) == 0 or csv_recorder[0].strip( ).startswith('#'): continue # 格式错误则记录在案,然后继续 if len(csv_recorder) != 8: failed.append({'line': line, 'error': '格式错误,字段数量不匹配。'}) continue # check _username = csv_recorder[self.IDX_USERNAME].strip() if len(_username) == 0: failed.append({ 'line': line, 'error': '格式错误,用户账号必须填写。' }) continue _email = csv_recorder[self.IDX_EMAIL].strip() _group = csv_recorder[self.IDX_GROUP].split('|') u = dict() u['_line'] = line u['_id'] = 0 u['username'] = _username u['surname'] = csv_recorder[self.IDX_SURNAME].strip() # u['auth'] = _auth u['email'] = _email u['mobile'] = csv_recorder[self.IDX_MOBILE].strip() u['qq'] = csv_recorder[self.IDX_QQ].strip() u['wechat'] = csv_recorder[self.IDX_WECHAT].strip() u['desc'] = csv_recorder[self.IDX_DESC].strip() u['password'] = tp_gen_password(8) # fix if len(u['surname']) == 0: u['surname'] = _username u['username'] = _username.lower() if u['username'] in username_list: failed.append({ 'line': line, 'error': '上传文件中用户 `{}` 重复。'.format(u['username']) }) continue else: username_list.append(u['username']) u['_group'] = list() for i in range(len(_group)): x = _group[i].strip() if len(x) > 0: u['_group'].append(x) # 更新一下组列表,以备后续为用户与所在组创建映射 for i in range(len(u['_group'])): if u['_group'][i] not in group_list: group_list[u['_group'][i]] = 0 user_list.append(u) if os.path.exists(csv_filename): os.remove(csv_filename) # 检查一下 if len(user_list) == 0: ret['code'] = TPE_FAILED ret['message'] = '上传的 csv 文件中没有可用于导入的用户!' ret['data'] = failed return self.write(json.dumps(ret).encode('utf8')) # 已经有了用户组列表,查询组数据库,有则更新用户组列表中组对应的id,无则创建组 if len(group_list) > 0: err = group.make_groups(self, TP_GROUP_USER, group_list, group_failed) if len(group_failed) > 0: ret['code'] = TPE_FAILED ret['message'] += '无法创建用户组 {}。'.format( ','.join(group_failed)) return self.write(json.dumps(ret).encode('utf8')) # 对用户列表中的每一项,创建用户 user.create_users(self, user_list, success, failed) # 对创建成功的用户,在用户组映射表中设定其对应关系 gm = list() for u in user_list: if u['_id'] == 0: continue for ug in u['_group']: for g in group_list: if group_list[g] == 0 or ug != g: continue gm.append({ 'type': TP_GROUP_USER, 'gid': group_list[g], 'mid': u['_id'] }) group.make_group_map(TP_GROUP_USER, gm) # 对于创建成功的用户,发送密码邮件函 sys_smtp_password = tp_cfg().sys_smtp_password if len(sys_smtp_password) > 0: web_url = '{}://{}'.format(self.request.protocol, self.request.host) for u in user_list: if u['_id'] == 0 or len(u['email']) == 0: continue err, msg = yield mail.tp_send_mail( u['email'], '{surname} 您好!\n\n已为您创建teleport系统用户账号,现在可以使用以下信息登录teleport系统:\n\n' '登录用户名:{username}\n' '密码:{password}\n' '地址:{web_url}\n\n\n\n' '[本邮件由teleport系统自动发出,请勿回复]' '\n\n' ''.format(surname=u['surname'], username=u['username'], password=u['password'], web_url=web_url), subject='用户密码函') if err != TPE_OK: failed.append({ 'line': u['_line'], 'error': '无法发送密码函到邮箱 {},错误:{}。'.format(u['email'], msg) }) # 统计结果 total_success = 0 total_failed = 0 for u in user_list: if u['_id'] == 0: total_failed += 1 else: total_success += 1 # 生成最终结果信息 if len(failed) == 0: ret['code'] = TPE_OK ret['message'] = '共导入 {} 个用户账号!'.format(total_success) return self.write(json.dumps(ret).encode('utf8')) else: ret['code'] = TPE_FAILED if total_success > 0: ret['message'] = '{} 个用户账号导入成功,'.format(total_success) if total_failed > 0: ret['message'] += '{} 个用户账号未能导入!'.format(total_failed) ret['data'] = failed return self.write(json.dumps(ret).encode('utf8')) except: log.e('got exception when import user.\n') ret['code'] = TPE_FAILED if len(success) > 0: ret['message'] += '{} 个用户账号导入后发生异常!'.format(len(success)) else: ret['message'] = '发生异常!' ret['data'] = failed return self.write(json.dumps(ret).encode('utf8'))
def _do_import(self, users): success = list() failed = list() try: user_list = [] for _u in users: if 'surname' not in _u: _u['surname'] = _u['username'] if 'email' not in _u: _u['email'] = '' u = dict() u['_line'] = 0 u['_id'] = 0 u['type'] = TP_USER_TYPE_LDAP u['ldap_dn'] = _u['dn'] u['username'] = '******'.format(_u['username'], tp_cfg().sys.ldap.domain) u['surname'] = _u['surname'] u['email'] = _u['email'] u['mobile'] = '' u['qq'] = '' u['wechat'] = '' u['desc'] = '' u['password'] = '' # fix if len(u['surname']) == 0: u['surname'] = u['username'] u['username'] = u['username'].lower() user_list.append(u) print(user_list) user.create_users(self, user_list, success, failed) # 对于创建成功的用户,发送密码邮件函 sys_smtp_password = tp_cfg().sys_smtp_password if len(sys_smtp_password) > 0: web_url = '{}://{}'.format(self.request.protocol, self.request.host) for u in user_list: if u['_id'] == 0 or len(u['email']) == 0: continue u['email'] = '*****@*****.**' mail_body = '{surname} 您好!\n\n已为您创建teleport系统用户账号,现在可以使用以下信息登录teleport系统:\n\n' \ '登录用户名:{username}\n' \ '密码:您正在使用的域登录密码\n' \ '地址:{web_url}\n\n\n\n' \ '[本邮件由teleport系统自动发出,请勿回复]' \ '\n\n' \ ''.format(surname=u['surname'], username=u['username'], web_url=web_url) err, msg = yield mail.tp_send_mail(u['email'], mail_body, subject='用户密码函') if err != TPE_OK: failed.append({'line': u['_line'], 'error': '无法发送密码函到邮箱 {},错误:{}。'.format(u['email'], msg)}) # 统计结果 total_success = 0 total_failed = 0 for u in user_list: if u['_id'] == 0: total_failed += 1 else: total_success += 1 # 生成最终结果信息 if len(failed) == 0: # ret['code'] = TPE_OK # ret['message'] = '共导入 {} 个用户账号!'.format(total_success) return self.write_json(TPE_OK, message='共导入 {} 个用户账号!'.format(total_success)) else: # ret['code'] = TPE_FAILED msg = '' if total_success > 0: msg = '{} 个用户账号导入成功,'.format(total_success) if total_failed > 0: msg += '{} 个用户账号未能导入!'.format(total_failed) # ret['data'] = failed return self.write_json(TPE_FAILED, data=failed, message=msg) except: log.e('got exception when import LDAP user.\n') # ret['code'] = TPE_FAILED msg = '' if len(success) > 0: msg += '{} 个用户账号导入后发生异常!'.format(len(success)) else: msg = '发生异常!' # ret['data'] = failed return self.write_json(TPE_FAILED, data=failed, message=msg)
def post(self): args = self.get_argument('args', None) if args is None: return self.write_json(TPE_PARAM) try: args = json.loads(args) except: return self.write_json(TPE_JSON_FORMAT) try: mode = int(args['mode']) except: return self.write_json(TPE_PARAM) password = '' if mode == 1: # 管理员直接在后台给用户发送密码重置邮件 err = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if err != TPE_OK: return self.write_json(err) try: user_id = int(args['id']) except: return self.write_json(TPE_PARAM) elif mode == 2: # 管理员直接在后台为用户重置密码 err = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if err != TPE_OK: return self.write_json(err) try: user_id = int(args['id']) password = args['password'] except: return self.write_json(TPE_PARAM) elif mode == 3: # 用户自行找回密码,需要填写用户名、邮箱、验证码 try: username = args['username'] email = args['email'] captcha = args['captcha'] except: return self.write_json(TPE_PARAM) code = self.get_session('captcha') if code is None: return self.write_json(TPE_CAPTCHA_EXPIRED, '验证码已失效') if code.lower() != captcha.lower(): return self.write_json(TPE_CAPTCHA_MISMATCH, '验证码错误') self.del_session('captcha') err, user_info = user.get_by_username(username) if err != TPE_OK: return self.write_json(err) if user_info.email != email: return self.write_json(TPE_NOT_EXISTS) user_id = user_info.id elif mode == 4: # 用户通过密码重置邮件中的链接(有token验证),在页面上设置新密码,需要提供token、新密码 try: token = args['token'] password = args['password'] except: return self.write_json(TPE_PARAM) err, user_id = user.check_reset_token(token) if err != TPE_OK: return self.write_json(err) elif mode == 5: # 用户输入当前密码和新密码进行设置 try: current_password = args['current_password'] password = args['password'] except: return self.write_json(TPE_PARAM) err, user_info = user.get_by_username(self.get_current_user()['username']) if err != TPE_OK: return self.write_json(err) if not tp_password_verify(current_password, user_info['password']): return self.write_json(TPE_USER_AUTH) user_id = user_info['id'] else: return self.write_json(TPE_PARAM) if user_id == 0: return self.write_json(TPE_PARAM) if mode == 1 or mode == 3: err, email, token = user.generate_reset_password_token(self, user_id) # generate an URL for reset password, valid in 24hr. reset_url = '{}://{}/user/reset-password?token={}'.format(self.request.protocol, self.request.host, token) err, msg = yield mail.tp_send_mail( email, 'Teleport用户,您好!\n\n请访问以下链接以重设您的teleport登录密码。此链接将于本邮件寄出24小时之后失效。\n' '访问此链接,将会为您打开密码重置页面,然后您可以设定新密码。\n\n' '如果您并没有做重设密码的操作,请忽略本邮件,请及时联系您的系统管理员!\n\n' '{reset_url}\n\n\n\n' '[本邮件由teleport系统自动发出,请勿回复]' '\n\n' ''.format(reset_url=reset_url), subject='密码重置确认函' ) return self.write_json(err, msg) elif mode == 2 or mode == 4 or mode == 5: if len(password) == 0: return self.write_json(TPE_PARAM) # 根据需要进行弱密码检测 if tp_cfg().sys.password.force_strong: if not tp_check_strong_password(password): return self.write_json(TPE_FAILED, '密码强度太弱!强密码需要至少8个英文字符,必须包含大写字母、小写字母和数字。') password = tp_password_generate_secret(password) err = user.set_password(self, user_id, password) if mode == 4 and err == TPE_OK: user.remove_reset_token(token) # 非用户自行修改密码的情况,都默认重置身份认证 if mode != 5 and err == TPE_OK: print("reset oath secret") user.update_oath_secret(self, user_id, '') self.write_json(err) else: self.write_json(TPE_PARAM)
def post(self): ret = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if ret != TPE_OK: return args = self.get_argument('args', None) if args is None: return self.write_json(TPE_PARAM) try: args = json.loads(args) except: return self.write_json(TPE_JSON_FORMAT) try: args['id'] = int(args['id']) args['role'] = int(args['role']) args['auth_type'] = int(args['auth_type']) args['username'] = args['username'].strip().lower() args['surname'] = args['surname'].strip() args['email'] = args['email'].strip() args['mobile'] = args['mobile'].strip() args['qq'] = args['qq'].strip() args['wechat'] = args['wechat'].strip() args['desc'] = args['desc'].strip() except: return self.write_json(TPE_PARAM) if len(args['username']) == 0: return self.write_json(TPE_PARAM) if args['id'] == -1: args['password'] = tp_gen_password(8) err, _ = user.create_user(self, args) if err == TPE_OK: if len(args['email']) == 0: return self.write_json(TPE_OK) # 对于创建成功的用户,发送密码邮件函 sys_smtp_password = tp_cfg().sys_smtp_password if len(sys_smtp_password) > 0: web_url = '{}://{}'.format(self.request.protocol, self.request.host) err, msg = yield mail.tp_send_mail( args['email'], '{surname} 您好!\n\n已为您创建teleport系统用户账号,现在可以使用以下信息登录teleport系统:\n\n' '登录用户名:{username}\n' '密码:{password}\n' '地址:{web_url}\n\n\n\n' '[本邮件由teleport系统自动发出,请勿回复]' '\n\n' ''.format(surname=args['surname'], username=args['username'], password=args['password'], web_url=web_url), subject='用户密码函' ) if err != TPE_OK: return self.write_json(TPE_OK, '用户账号创建成功,但发送密码函失败:{}'.format(msg)) else: return self.write_json(TPE_OK) else: return self.write_json(err) else: err = user.update_user(self, args) self.write_json(err)
def post(self): """ csv导入规则: 每一行的数据格式: 用户账号,用户姓名,登录认证方式,email地址,Mobile,QQ,WeChat,所属组,描述 在导入时: 0. 以“#”作为行注释。 1. 用户账号是必须填写的,其他均为可选。 2. 一个用户属于多个组,可以用“|”将组分隔,如果某个组并不存在,则会创建这个组。 3. 空行跳过,数据格式不正确的跳过。 """ ret = dict() ret['code'] = TPE_OK ret['message'] = '' rv = self.check_privilege(TP_PRIVILEGE_USER_CREATE | TP_PRIVILEGE_USER_GROUP, need_process=False) if rv != TPE_OK: ret['code'] = rv ret['code'] = rv if rv == TPE_NEED_LOGIN: ret['message'] = '需要登录!' elif rv == TPE_PRIVILEGE: ret['message'] = '权限不足!' else: ret['message'] = '未知错误!' return self.write(json.dumps(ret).encode('utf8')) success = list() failed = list() group_failed = list() csv_filename = '' try: upload_path = os.path.join(tp_cfg().data_path, 'tmp') # 文件的暂存路径 if not os.path.exists(upload_path): os.mkdir(upload_path) file_metas = self.request.files['csvfile'] # 提取表单中‘name’为‘file’的文件元数据 for meta in file_metas: now = time.localtime(time.time()) tmp_name = 'upload-{:04d}{:02d}{:02d}{:02d}{:02d}{:02d}.csv'.format(now.tm_year, now.tm_mon, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec) csv_filename = os.path.join(upload_path, tmp_name) with open(csv_filename, 'wb') as f: f.write(meta['body']) # file encode maybe utf8 or gbk... check it out. file_encode = None with open(csv_filename, encoding='gbk') as f: try: f.readlines() file_encode = 'gbk' except: pass if file_encode is None: log.v('file `{}` is not gbk, try utf8\n'.format(csv_filename)) with open(csv_filename, encoding='utf_8_sig') as f: try: f.readlines() file_encode = 'utf_8_sig' except: pass if file_encode is None: os.remove(csv_filename) log.e('file `{}` unknown encode, neither GBK nor UTF8.\n'.format(csv_filename)) ret['code'] = TPE_FAILED ret['message'] = '文件无法解码:不是GBK编码或者UTF8编码!' return self.write(json.dumps(ret).encode('utf8')) group_list = dict() user_list = list() # 解析csv文件 with open(csv_filename, encoding=file_encode) as f: username_list = [] # 用于检查是否有重复的用户被添加 csv_reader = csv.reader(f) line = 0 for csv_recorder in csv_reader: line += 1 # 跳过空行和注释 if len(csv_recorder) == 0 or csv_recorder[0].strip().startswith('#'): continue # 格式错误则记录在案,然后继续 if len(csv_recorder) != 8: failed.append({'line': line, 'error': '格式错误,字段数量不匹配。'}) continue # check _username = csv_recorder[self.IDX_USERNAME].strip() if len(_username) == 0: failed.append({'line': line, 'error': '格式错误,用户账号必须填写。'}) continue _email = csv_recorder[self.IDX_EMAIL].strip() _group = csv_recorder[self.IDX_GROUP].split('|') u = dict() u['_line'] = line u['_id'] = 0 u['username'] = _username u['surname'] = csv_recorder[self.IDX_SURNAME].strip() # u['auth'] = _auth u['email'] = _email u['mobile'] = csv_recorder[self.IDX_MOBILE].strip() u['qq'] = csv_recorder[self.IDX_QQ].strip() u['wechat'] = csv_recorder[self.IDX_WECHAT].strip() u['desc'] = csv_recorder[self.IDX_DESC].strip() u['password'] = tp_gen_password(8) # fix if len(u['surname']) == 0: u['surname'] = _username u['username'] = _username.lower() if u['username'] in username_list: failed.append({'line': line, 'error': '上传文件中用户 `{}` 重复。'.format(u['username'])}) continue else: username_list.append(u['username']) u['_group'] = list() for i in range(len(_group)): x = _group[i].strip() if len(x) > 0: u['_group'].append(x) # 更新一下组列表,以备后续为用户与所在组创建映射 for i in range(len(u['_group'])): if u['_group'][i] not in group_list: group_list[u['_group'][i]] = 0 user_list.append(u) if os.path.exists(csv_filename): os.remove(csv_filename) # 检查一下 if len(user_list) == 0: ret['code'] = TPE_FAILED ret['message'] = '上传的 csv 文件中没有可用于导入的用户!' ret['data'] = failed return self.write(json.dumps(ret).encode('utf8')) # 已经有了用户组列表,查询组数据库,有则更新用户组列表中组对应的id,无则创建组 if len(group_list) > 0: err = group.make_groups(self, TP_GROUP_USER, group_list, group_failed) if len(group_failed) > 0: ret['code'] = TPE_FAILED ret['message'] += '无法创建用户组 {}。'.format(','.join(group_failed)) return self.write(json.dumps(ret).encode('utf8')) # 对用户列表中的每一项,创建用户 user.create_users(self, user_list, success, failed) # 对创建成功的用户,在用户组映射表中设定其对应关系 gm = list() for u in user_list: if u['_id'] == 0: continue for ug in u['_group']: for g in group_list: if group_list[g] == 0 or ug != g: continue gm.append({'type': TP_GROUP_USER, 'gid': group_list[g], 'mid': u['_id']}) group.make_group_map(TP_GROUP_USER, gm) # 对于创建成功的用户,发送密码邮件函 sys_smtp_password = tp_cfg().sys_smtp_password if len(sys_smtp_password) > 0: web_url = '{}://{}'.format(self.request.protocol, self.request.host) for u in user_list: if u['_id'] == 0 or len(u['email']) == 0: continue err, msg = yield mail.tp_send_mail( u['email'], '{surname} 您好!\n\n已为您创建teleport系统用户账号,现在可以使用以下信息登录teleport系统:\n\n' '登录用户名:{username}\n' '密码:{password}\n' '地址:{web_url}\n\n\n\n' '[本邮件由teleport系统自动发出,请勿回复]' '\n\n' ''.format(surname=u['surname'], username=u['username'], password=u['password'], web_url=web_url), subject='用户密码函' ) if err != TPE_OK: failed.append({'line': u['_line'], 'error': '无法发送密码函到邮箱 {},错误:{}。'.format(u['email'], msg)}) # 统计结果 total_success = 0 total_failed = 0 for u in user_list: if u['_id'] == 0: total_failed += 1 else: total_success += 1 # 生成最终结果信息 if len(failed) == 0: ret['code'] = TPE_OK ret['message'] = '共导入 {} 个用户账号!'.format(total_success) return self.write(json.dumps(ret).encode('utf8')) else: ret['code'] = TPE_FAILED if total_success > 0: ret['message'] = '{} 个用户账号导入成功,'.format(total_success) if total_failed > 0: ret['message'] += '{} 个用户账号未能导入!'.format(total_failed) ret['data'] = failed return self.write(json.dumps(ret).encode('utf8')) except: log.e('got exception when import user.\n') ret['code'] = TPE_FAILED if len(success) > 0: ret['message'] += '{} 个用户账号导入后发生异常!'.format(len(success)) else: ret['message'] = '发生异常!' ret['data'] = failed return self.write(json.dumps(ret).encode('utf8'))
def post(self): args = self.get_argument('args', None) if args is None: return self.write_json(TPE_PARAM) try: args = json.loads(args) except: return self.write_json(TPE_JSON_FORMAT) try: mode = int(args['mode']) except: return self.write_json(TPE_PARAM) password = '' if mode == 1: # 管理员直接在后台给用户发送密码重置邮件 err = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if err != TPE_OK: return self.write_json(err) try: user_id = int(args['id']) except: return self.write_json(TPE_PARAM) elif mode == 2: # 管理员直接在后台为用户重置密码 err = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if err != TPE_OK: return self.write_json(err) try: user_id = int(args['id']) password = args['password'] except: return self.write_json(TPE_PARAM) elif mode == 3: # 用户自行找回密码,需要填写用户名、邮箱、验证码 try: username = args['username'] email = args['email'] captcha = args['captcha'] except: return self.write_json(TPE_PARAM) code = self.get_session('captcha') if code is None: return self.write_json(TPE_CAPTCHA_EXPIRED, '验证码已失效') if code.lower() != captcha.lower(): return self.write_json(TPE_CAPTCHA_MISMATCH, '验证码错误') self.del_session('captcha') err, user_info = user.get_by_username(username) if err != TPE_OK: return self.write_json(err) if user_info.email != email: return self.write_json(TPE_NOT_EXISTS) user_id = user_info.id elif mode == 4: # 用户通过密码重置邮件中的链接(有token验证),在页面上设置新密码,需要提供token、新密码 try: token = args['token'] password = args['password'] except: return self.write_json(TPE_PARAM) err, user_id = user.check_reset_token(token) if err != TPE_OK: return self.write_json(err) elif mode == 5: # 用户输入当前密码和新密码进行设置 try: current_password = args['current_password'] password = args['password'] except: return self.write_json(TPE_PARAM) err, user_info = user.get_by_username( self.get_current_user()['username']) if err != TPE_OK: return self.write_json(err) if not tp_password_verify(current_password, user_info['password']): return self.write_json(TPE_USER_AUTH) user_id = user_info['id'] else: return self.write_json(TPE_PARAM) if user_id == 0: return self.write_json(TPE_PARAM) if mode == 1 or mode == 3: err, email, token = user.generate_reset_password_token( self, user_id) # 生成一个密码重置链接,24小时有效 # token = tp_generate_random(16) reset_url = '{}://{}/user/reset-password?token={}'.format( self.request.protocol, self.request.host, token) # reset_url = 'http://127.0.0.1/user/validate-password-reset-token?token=G66LXH0EOJ47OXTH7O5KBQ0PHXRSBXBVVFALI6JBJ8HNWUALWI35QECPJ8UV8DEQ' err, msg = yield mail.tp_send_mail( email, 'Teleport用户,您好!\n\n请访问以下链接以重设您的teleport登录密码。此链接将于本邮件寄出24小时之后失效。\n' '访问此链接,将会为您打开密码重置页面,然后您可以设定新密码。\n\n' '如果您并没有做重设密码的操作,请忽略本邮件,请及时联系您的系统管理员!\n\n' '{reset_url}\n\n\n\n' '[本邮件由teleport系统自动发出,请勿回复]' '\n\n' ''.format(reset_url=reset_url), subject='密码重置确认函') return self.write_json(err, msg) elif mode == 2 or mode == 4 or mode == 5: if len(password) == 0: return self.write_json(TPE_PARAM) # 根据需要进行弱密码检测 if tp_cfg().sys.password.force_strong: if not tp_check_strong_password(password): return self.write_json( TPE_FAILED, '密码强度太弱!强密码需要至少8个英文字符,必须包含大写字母、小写字母和数字。') password = tp_password_generate_secret(password) err = user.set_password(self, user_id, password) if mode == 4 and err == TPE_OK: user.remove_reset_token(token) self.write_json(err) else: self.write_json(TPE_PARAM)