import random import re import json from sanic import response from unify_api.utils.response_code import RET from pot_libs.settings import SETTING from pot_libs.sanic_api import summary from pot_libs.utils.pendulum_wrapper import my_pendulum from unify_api.constants import PRODUCT_INFOS from unify_api.modules.users.components.current_user_info_cps import * from pot_libs.common.components.responses import success_res from unify_api.modules.users.procedures.jwt_user import jwt_user from unify_api.modules.users.procedures.send_sms import sample from pot_libs.aredis_util import aredis_utils from unify_api.modules.users.dao.current_user_info_dao import * from unify_api.modules.common.dao.common_dao import user_by_phone_number, \ user_by_user_id from pot_libs.aiohttp_util.aiohttp_utils import AioHttpUtils from unify_api.modules.users.procedures.jwt_user import auth_phone_verify, \ check_password AUTH_EXP = 300 # redis缓存时间 VALIDATION_EXP = 60 # 发送验证码间隔时间 @summary('用户头像昵称等信息') async def get_user_info(request) -> UserInfoResponse: # 1.从jwt中获取user_id user_id = jwt_user(request) if not user_id: valid_body = { "code": 401, "message": "token is valid", "data": {}, "srv_time": my_pendulum.now().to_datetime_string() } return response.json(body=valid_body, status=401) # 2.查询用户 user_info = await user_by_user_id(user_id) if not user_info: return UserInfoResponse().user_error() # head_image_url = "" # 3.查询出用户昵称等信息 # if user_info["wechat_id"]: # sql = "select nickname, headimgurl, user.zhiweiu_auth, " \ # "user.real_name, user.unit from wechat_mp_user wu " \ # "inner join user on " \ # "wu.unionid = user.wechat_id where user.user_id = %s" # async with MysqlUtil() as conn: # user_info = await conn.fetchone(sql=sql, args=(int(user_id)), ) # head_image_url = user_info.get("headimgurl")[5:] # 4. 查询用户产品信息 pro_sql = "select product from user_product_auth where user_id = %s" async with MysqlUtil() as conn: pro_info = await conn.fetchall(sql=pro_sql, args=(int(user_id)), ) # [{'product': 1}, {'product': 2}, {'product': 3}] product_list = [] if pro_info: for pro in pro_info: # ulock的app产品跳过, PRODUCT_INFOS只存u+云的产品 if pro["product"] not in PRODUCT_INFOS: continue product_list.append(PRODUCT_INFOS[pro["product"]]) product_list = sorted(product_list, key=lambda x: x["sort_num"]) # 4. 查询zhiweiu权限, 默认普通用户 zhiweiu_auth = user_info.get("zhiweiu_auth") if not zhiweiu_auth and zhiweiu_auth != 0: zhiweiu_auth = 1 return UserInfoResponse( user_id=user_id, # nick_name=user_info.get("nickname") or user_info.get("real_name"), nick_name=user_info.get("real_name"), head_image_url="http://cdn.ucyber.cn/common/default-avatar.png", real_name=user_info.get("real_name"), unit=user_info.get("unit"), product_list=product_list, zhiweiu_auth=zhiweiu_auth ) @summary("发送手机验证码") async def get_send_sms(request): phone = request.args.get("phone") if re.match(r'^1[3-9]\d{9}$', phone): send_flag = await aredis_utils.RedisUtils().get( f"sms:send_sms_flag_{phone}") if send_flag: return success_res(code=RET.send_sms_quick, msg="请求验证码过于频繁") code = '%06d' % random.randint(1, 999999) # 短信间隔 await aredis_utils.RedisUtils().setex( f"sms:send_sms_flag_{phone}", VALIDATION_EXP, 1) await aredis_utils.RedisUtils().setex( f"sms:sms_{phone}", AUTH_EXP, code) result_body = sample.main([phone, code]) log.info(f"send_sms {phone}, {code}, {result_body}") if result_body.code == "OK": return success_res(msg="发送成功") else: if result_body.message == "触发天级流控Permits:10": msg = "您今日发送短信次数已用完" elif result_body.message == "触发小时级流控Permits:5": msg = "请求验证码过于频繁,请1小时后重新发送" elif result_body.message == "触发分钟级流控Permits:1": msg = "请求验证码过于频繁,请1分钟后重新发送" else: msg = "验证码发送失败" return success_res(code=RET.send_sms_quick2, msg=msg) return success_res(code=RET.send_sms_fail, msg="手机号码不合法") @summary("首次登录保存用户信息") async def post_save_userinfo(request, body: SaveUserReq): real_name = body.real_name unit = body.unit job = body.job phone = body.phone password = body.password password2 = body.password2 wechat_id = body.wechat_id verify = body.verify if not all([real_name, job, unit, phone, password]): return success_res(code=RET.params_loss, msg="缺少必传参数") if password != password2: return success_res(code=RET.password_error, msg="两次密码不一致") passwd = check_password(password) if verify: auth_verify = await auth_phone_verify(phone, verify) if not auth_verify: return success_res(code=RET.verify_error, msg="验证码不一致") if wechat_id: wechat_info = await is_having_wechat_id(wechat_id) is_having = await phone_is_having_dao(phone) if wechat_info: await update_user_info_by_wechat_id(real_name, unit, job, passwd, phone, wechat_id) elif is_having and is_having["wechat_id"]: return success_res(code=RET.verify_error, msg="该手机号已注册") elif is_having: # 修改信息 await update_user_info(real_name, unit, job, passwd, phone, wechat_id) else: # 注册 await insert_user_info(real_name, unit, job, passwd, phone, wechat_id) else: await insert_user_info(real_name, unit, job, passwd, phone) user = await user_by_phone_number(phone) # 获取token request_body = { "phone": phone, "client_name": "validation", "host": request.host, "user_id": user["user_id"], "db": SETTING.mysql_db } resp_str, status = await AioHttpUtils().post( SETTING.auth_url, request_body, timeout=50, ) log.info(f"post_save_userinfo resp_str={resp_str} status={status}") resp = json.loads(resp_str) if status == 200: return success_res(data=resp) else: return success_res(msg="保存用户信息成功") @summary("修改手机号") async def post_update_phone(request, body: UpdatePhoneReq): user_id = body.user_id phone = body.phone verify = body.verify log.info(f"post_update_phone {phone} {verify}") # 检验手机号 wechat_product_dict, old_zhiwei_u, old_role = {}, None, None wechat_product_auth, wechat_product_auth_dict = None, {} phone_info = await user_by_phone_number(phone) if phone_info: if phone_info.get("wechat_id"): return 401, {"code": 40001, "data": None, "message": "该手机号已被绑定"} else: # 删除这条记录 await update_not_wechat(user_id, phone) old_zhiwei_u = phone_info["zhiweiu_auth"] old_role = phone_info["role"] wechat_product_auth = await \ search_user_product_auth_dao(phone_info["user_id"]) wechat_product_auth_dict = \ {wechat_product["product"]: wechat_product["cid_ext"] for wechat_product in wechat_product_auth} \ if wechat_product_auth else {} wechat_product_dict = \ {wechat_product["product"]: wechat_product["proxy"] for wechat_product in wechat_product_auth} \ if wechat_product_auth else {} # 效验验证码 auth_verify = await auth_phone_verify(phone, verify) if not auth_verify: return success_res(code=RET.verify_error, msg="验证码不一致") user_product_auth = await search_user_product_auth_dao(user_id) user_product_auth_dict = \ {user_product["product"]: user_product["cid_ext"] for user_product in user_product_auth} if user_product_auth else {} user_product_dict = \ {user_product["product"]: user_product["proxy"] for user_product in user_product_auth} if user_product_auth else {} if all([wechat_product_auth, user_product_auth]): product_auth = wechat_product_auth_dict.update( user_product_auth_dict) elif wechat_product_auth: product_auth = wechat_product_auth_dict elif user_product_auth: product_auth = user_product_auth_dict else: product_auth = None # 绑定手机和智维u、role sql_list = [f"phone_number='{phone}'"] if old_zhiwei_u: sql_list.append(f"zhiweiu_auth={old_zhiwei_u}") if old_role: sql_list.append(f"role={old_role}") mid_sql = ",".join(sql_list) await update_user_auth_dao(user_id, mid_sql) # 修改权限 if product_auth: for key, value in product_auth.items(): is_auth = await search_product_auth_dao(user_id, key) if is_auth: await update_product_auth_dao(key, value, user_id, proxy=user_product_dict.get(key) or wechat_product_dict.get(key)) else: await insert_product_auth_dao(user_id, key, value, proxy=(user_product_dict.get(key) or wechat_product_dict.get(key))) return success_res(msg="修改成功") @summary("验证手机号") async def post_auth_phone(request, body: AuthPhoneReq): phone = body.phone verify = body.verify auth_verify = await auth_phone_verify(phone, verify) if not auth_verify: return success_res(code=RET.verify_error, msg="验证码不一致") return success_res(msg="验证通过") @summary("找回密码") async def post_back_password(request, body: PhoneIsHavingReq): phone = body.phone is_delete = await phone_is_having_dao(phone) if not is_delete: return success_res(code=RET.phone_not_register, msg="手机号未注册或已注销") return success_res(msg="成功") @summary("修改密码") async def post_update_password(request, body: UpdatePasswordReq): phone = body.phone is_delete = await phone_is_having_dao(phone) if not is_delete: return success_res(code=RET.phone_not_register, msg="手机号未注册") password = body.password password2 = body.password2 if password != password2: return success_res(code=RET.password_error, msg="两次密码不一致") passwd = check_password(password) await update_password_dao(phone, passwd) return success_res(msg="修改成功") @summary("获取个人信息") async def post_userinfo(request, body: UserinfoReq) -> UserinfoResp: user_id = body.user_id data = await user_by_user_id(user_id) is_wechat = 1 if data["wechat_id"] else 0 return UserinfoResp(user_id=data["user_id"], phone=data["phone_number"], unit=data.get("unit") or "", job=data.get("job") or "", name=data.get("real_name") or "", is_wechat=is_wechat) @summary("修改个人信息") async def post_update_userinfo(request, body: UpdateUserInfoReq) \ -> UserinfoResp: user_id = body.user_id name = body.name unit = body.unit job = body.job if not any([name, unit, job]): return success_res(code=RET.params_loss, msg="缺少参数") if name: await update_userinfo_dao(user_id, 'real_name', name) elif unit: await update_userinfo_dao(user_id, 'unit', unit) else: await update_userinfo_dao(user_id, 'job', job) data = await user_by_user_id(user_id) is_wechat = 1 if data["wechat_id"] else 0 return UserinfoResp(user_id=data["user_id"], phone=data["phone_number"], unit=data["unit"], job=data["job"], name=data["real_name"], is_wechat=is_wechat) @summary("解除微信绑定") async def post_delete_wechat(request, body: UserinfoReq) \ -> UserinfoResp: user_id = body.user_id await update_userinfo_dao(user_id, "wechat_id", None) return success_res(msg="解除微信绑定成功") @summary("微信绑定") async def post_update_wechat(request, body: UpdateWechatReq): user_id = body.user_id code = body.code # 1.通过code换取网页授权access_token url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&" \ "secret=%s&code=%s&grant_type=authorization_code" % \ (SETTING.wechat_open_appid2, SETTING.wechat_open_secret_key2, code) log.info(f"post_update_wechat url:{url}") res_token, token_status = await AioHttpUtils().get(url) log.info(f"post_update_wechat res_token:{res_token}") if token_status != 200: log.error("post_update_wechat get access_token fail") return success_res(code=RET.wechat_error, msg="微信绑定失败") result = json.loads(res_token) # 2.获取用户信息 if 'access_token' not in result: log.error("post_update_wechat access_token not found") return success_res(code=RET.wechat_error, msg="微信绑定失败") url = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s" \ % (result['access_token'], result['openid']) res, user_info_status = await AioHttpUtils().get(url) log.info(f"post_update_wechat user_info:{res}") if user_info_status != 200: log.error("post_update_wechat get user info fail") return success_res(code=RET.wechat_error, msg="微信绑定失败") user_info = json.loads(res) wechat_product_dict, old_zhiwei_u, old_role = {}, None, None if 'openid' in user_info and 'unionid' in user_info: unionid = user_info['unionid'] data = await search_user_by_wechat_id_dao(unionid) wechat_product_auth, wechat_product_auth_dict = None, {} log.info(f"post_update_wechat{data}, unionid:{unionid}") if data: log.info(f"post_update_wechat{data}") if data.get("phone_number"): return success_res(code=RET.wechat_repeat, msg="该微信号已经被绑定") else: old_zhiwei_u = data["zhiweiu_auth"] old_role = data["role"] r = '%04d' % random.randint(1, 9999) new_wechat_id = f"delete{r}{unionid}" # 删除老用户 await update_user_is_delete(data["user_id"], new_wechat_id) # # 添加微信到新用户 # await update_not_phone(user_id, unionid) # 修改权限 wechat_product_auth = await \ search_user_product_auth_dao(data["user_id"]) wechat_product_auth_dict = \ {wechat_product["product"]: wechat_product["cid_ext"] for wechat_product in wechat_product_auth} \ if wechat_product_auth else {} wechat_product_dict = \ {wechat_product["product"]: wechat_product["proxy"] for wechat_product in wechat_product_auth} \ if wechat_product_auth else {} user_product_auth = await search_user_product_auth_dao(user_id) user_product_auth_dict = \ {user_product["product"]: user_product["cid_ext"] for user_product in user_product_auth} \ if user_product_auth else {} user_product_dict = \ {user_product["product"]: user_product["proxy"] for user_product in user_product_auth} \ if user_product_auth else {} if all([wechat_product_auth, user_product_auth]): product_auth = wechat_product_auth_dict.update( user_product_auth_dict) elif wechat_product_auth: product_auth = wechat_product_auth_dict elif user_product_auth: product_auth = user_product_auth_dict else: product_auth = None # 绑定微信和智维u、role sql_list = [f"wechat_id='{unionid}'"] if old_zhiwei_u: sql_list.append(f"zhiweiu_auth={old_zhiwei_u}") if old_role: sql_list.append(f"role={old_role}") mid_sql = ",".join(sql_list) await update_user_auth_dao(user_id, mid_sql) # 修改权限 if product_auth: for key, value in product_auth.items(): is_auth = await search_product_auth_dao(user_id, key) if is_auth: await update_product_auth_dao(key, value, user_id, proxy=user_product_dict.get(key) or wechat_product_dict.get(key)) else: await insert_product_auth_dao(user_id, key, value, proxy=user_product_dict.get(key) or wechat_product_dict.get(key)) log.info(f"post_update_wechat product_auth:{product_auth}") return success_res(msg="微信绑定成功") return success_res(code=RET.wechat_error, msg="微信绑定失败") @summary("手机号码是否被绑定") async def post_phone_is_having(request, body: PhoneIsHavingReq): phone = body.phone data = await phone_is_having_dao(phone) if data: return success_res(code=RET.phone_repeat, msg="该手机号码已经被绑定") return success_res(msg="该手机号码可用") @summary("注销用户") async def post_delete_user(request, body: UserinfoReq): user_id = body.user_id data = await user_by_user_id(user_id) code = '%04d' % random.randint(1, 9999) new_wechat_id = f"delete{code}" + data["wechat_id"] \ if data["wechat_id"] else None await update_user_is_delete(user_id, new_wechat_id) return success_res(msg="注销成功")