def put(self, request): ''' 实现添加邮箱逻辑 :param request: :return: ''' json_str = request.body.decode() json_dict = json.loads(json_str) email = json_dict.get('email') # 校验参数 ---->正则 if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email): return HttpResponseForbidden('参数email有误') # 给 email 赋值 try: request.user.email = email request.user.save() except Exception as e: logger.error(e) return JsonResponse({'code': RETCODE.EMAILERR, 'errmsg': '添加邮箱失败'}) # 4.异步发送邮件 verify_url = generate_verify_email_url(request.user) from celery_tasks.email.tasks import send_verify_email send_verify_email.delay(email, verify_url) return JsonResponse({'code': RETCODE.OK, 'errmsg': '添加邮箱成功'})
def is_bind_openid(openid, request): try: # openid = SecretOauth().loads(openid).get('openid') oauth_user = OAuthQQUser.objects.get(openid=openid) except Exception as e: logger.error(e) context = SecretOauth().dumps(openid) context = {'openid': context} return render(request, 'oauth_callback.html', context=context) else: # 如果openid已绑定美多商城用户 # 实现状态保持 qq_user = oauth_user.user login(request, qq_user) # 重定向到主页 response = redirect(reverse('contents:index')) # 登录时用户名写入到cookie,有效期15天 response.set_cookie('username', qq_user.username, max_age=3600 * 24 * 15) return response
def get(self, request, category_id): ''' 提供商品热销排行JSON数据 :param request: :param category_id: :return: ''' # 根据商品的倒序排序 取前两个 try: skus = SKU.objects.filter(category_id=category_id, is_launched=True).order_by('-sales')[:2] except Exception as e: logger.error(e) return JsonResponse({ 'code': RETCODE.DBERR, 'errmsg': '查询的数据不存在', 'hot_skus': [] }) # 序列化 hot_skus = [] for sku in skus: hot_skus.append({ 'id': sku.id, 'default_image_url': sku.default_image.url, 'name': sku.name, 'price': sku.price }) return JsonResponse({ 'code': RETCODE.OK, 'errmsg': 'OK', 'hot_skus': hot_skus })
def send_verify_email(self, to_email, verify_url): """ subject :主题标题 message :邮件内容 from_email:发件人 recipient_list:收件人列表 html_message: html标签邮件内容 """ subject = "美多商城邮箱验证" message = "" from_email = settings.EMAIL_FROM recipient_list = [to_email] html_message = '<p>尊敬的用户您好!</p>' \ '<p>感谢您使用美多商城。</p>' \ '<p>您的邮箱为:%s 。请点击此链接激活您的邮箱:</p>' \ '<p><a href="%s">%s<a></p>' % (to_email, verify_url, verify_url) try: # 发邮件djano提供 send_mail(subject, message, from_email, recipient_list, html_message=html_message) except Exception as e: logger.error(e) # 如果发送不成功 , 最大尝试次数3次 raise self.retry(exec=e, max_retries=3)
def post(self, request): # 1. 接收参数 username = request.POST.get('username') password = request.POST.get('password') password2 = request.POST.get('password2') mobile = request.POST.get('mobile') allow = request.POST.get('allow') # 2. 校验 判空 正则 if not all([username, password, password2, mobile, allow]): return HttpResponseForbidden('参数不齐') # 2.1 校验用户名 if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username): return HttpResponseForbidden('请输入5-20个字符的用户名') # 2.2 校验密码 if not re.match(r'^[0-9A-Za-z]{8,20}$', password): return HttpResponseForbidden('请输入8-20个字符的密码') # 2.3 校验两个密码是否一致 # 2.4 校验手机号 if not re.match(r'^1[3-9]\d{9}$', mobile): return HttpResponseForbidden('请输入正确的手机号码') # 2.5 是否勾选同意 按钮 if allow != 'on': return HttpResponseForbidden('请勾选用户协议') # 3. 注册用户到数据库 try: user = User.objects.create_user( username=username, password=password, mobile=mobile ) except Exception as e: logger.error(e) return render(request, 'register.html', {'register_errmsg': ' 注册失败'}) # 4. 登录状态 login(request, user) # 5. 返回相应对象 print(request.POST) # 6 验证短信验证吗 msg_code 表单注册 sms_code = request.POST.get('msg_code') # 6.1 从redis 中取出来 redis_code_client = get_redis_connection('sms_code') redis_code = redis_code_client.get('sms_%s' % mobile) # 6.2.1 判断是否存在 if redis_code is None: return render(request, 'register.html', {'sms_code_errmsg': '无效的短信验证码'}) # 6.2.2 判断是否相等 if sms_code != redis_code.decode(): return render(request, 'register.html', {'sms_code_errmsg': '输入短信验证码有误'}) # 5.1 成功 重定向到首页re response = redirect(reverse('contents:index')) # 注册时用户名写入到cookie,有效期15天 response.set_cookie('username', user.username, constants.USERNAME_EXPIRE_TIME) return response
def delete(self, request, address_id): try: # 查询要删除的地址 address = Address.objects.get(id=address_id) # 将地址逻辑删除设置为True address.is_deleted = True address.save() except Exception as e: logger.error(e) return JsonResponse({'code': RETCODE.DBERR, 'errmsg': '删除地址失败'}) # 响应删除地址结果 return JsonResponse({'code': RETCODE.OK, 'errmsg': '删除地址成功'})
def check_verify_email_token(token): """ 验证token并提取user :param token: 用户信息签名后的结果 :return: user, None """ from utils.secret import SecretOauth try: token_dict = SecretOauth().loads(token) except BadData: return None try: user = User.objects.get(id=token_dict['user_id'], email=token_dict['email']) except Exception as e: logger.error(e) return None else: return user
def put(self, request, address_id): ''' # 设置默认地址 :param request: :param address_id: :return: ''' try: # 接收参数,查询地址 address = Address.objects.get(id=address_id) # 设置地址为默认地址 request.user.default_address = address request.user.save() except Exception as e: logger.error(e) return JsonResponse({'code': RETCODE.DBERR, 'errmsg': '设置默认地址失败'}) # 响应设置默认地址结果 return JsonResponse({'code': RETCODE.OK, 'errmsg': '设置默认地址成功'})
def post(self, request): ''' 实现修改密码逻辑 :param request: :return: ''' # 接收参数 old_password = request.POST.get('old_pwd') new_password = request.POST.get('new_pwd') new_password2 = request.POST.get('new_cpwd') # 校验参数 if not all([old_password, new_password, new_password2]): return HttpResponseForbidden('缺少必传参数') ret = request.user.check_password(old_password) if ret == False: return render(request, 'user_center_pass.html', {'origin_pwd_errmsg': '原始密码错误'}) if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password): return HttpResponseForbidden('密码最少8位,最长20位') if new_password != new_password2: return HttpResponseForbidden('两次输入的密码不一致') # 修改密码 try: request.user.set_password(new_password) request.user.save() except Exception as e: logger.error(e) return render(request, 'user_center_pass.html', {'change_pwd_errmsg': '修改密码失败'}) # 清理状态保持信息 logout(request) response = redirect(reverse('users:login')) response.delete_cookie('username') # # 响应密码修改结果:重定向到登录界面 return response
def get(self, request): """实现邮箱验证逻辑""" # 接收参数 token = request.GET.get('token') # 校验参数:判断token是否为空和过期,提取user if not token: return HttpResponseBadRequest('缺少token') user = check_verify_email_token(token) if not user: return HttpResponseForbidden('无效的token') # 修改email_active的值为True try: user.email_active = True user.save() except Exception as e: logger.error(e) return HttpResponseServerError('激活邮件失败') # 返回邮箱验证结果 return redirect(reverse('users:info'))
def put(self, request, address_id): ''' 修改标题 :param request: :return: ''' # 接收参数:地址标题 json_dict = json.loads(request.body) title = json_dict.get('title') try: # 查询地址 address = Address.objects.get(id=address_id) # 设置新的地址标题 address.title = title address.save() except Exception as e: logger.error(e) return JsonResponse({'code': RETCODE.DBERR, 'errmsg': '设置地址标题失败'}) # 4.响应删除地址结果 return JsonResponse({'code': RETCODE.OK, 'errmsg': '设置地址标题成功'})
def get(self, request): """Oauth2.0认证""" # 提取code请求参数 code = request.GET.get('code') if not code: return HttpResponseForbidden('缺少code') # 创建工具对象 oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID, client_secret=settings.QQ_CLIENT_SECRET, redirect_uri=settings.QQ_REDIRECT_URI) try: # 使用code向QQ服务器请求access_token access_token = oauth.get_access_token(code) # 使用access_token向QQ服务器请求openid openid = oauth.get_open_id(access_token) response = is_bind_openid(openid, request) print(openid) return response except Exception as e: logger.error(e) return HttpResponseServerError('OAuth2.0认证失败')
def post(self, request): """实现新增地址逻辑""" # 判断是否超过地址上限:最多20个 # Address.objects.filter(user=request.user,is_deleted=False).count() count = request.user.addresses.filter(is_deleted=False).count() if count >= constants.USER_ADDRESS_COUNTS_LIMIT: return JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '超过地址数量上限'}) # 接收参数 json_dict = json.loads(request.body.decode()) receiver = json_dict.get('receiver') province_id = json_dict.get('province_id') city_id = json_dict.get('city_id') district_id = json_dict.get('district_id') place = json_dict.get('place') mobile = json_dict.get('mobile') tel = json_dict.get('tel') email = json_dict.get('email') # 校验参数 if not all([receiver, province_id, city_id, district_id, place, mobile]): return HttpResponseForbidden('缺少必传参数') if not re.match(r'^1[3-9]\d{9}$', mobile): return HttpResponseForbidden('参数mobile有误') if tel: if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel): return HttpResponseForbidden('参数tel有误') if email: if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email): return HttpResponseForbidden('参数email有误') # 保存地址信息 try: address = Address.objects.create( user=request.user, title=receiver, receiver=receiver, province_id=province_id, city_id=city_id, district_id=district_id, place=place, mobile=mobile, tel=tel, email=email ) # 设置默认地址 if not request.user.default_address: request.user.default_address = address request.user.save() except Exception as e: logger.error(e) return JsonResponse({'code': RETCODE.DBERR, 'errmsg': '新增地址失败'}) # 新增地址成功,将新增的地址响应给前端实现局部刷新 address_dict = { "id": address.id, "title": address.title, "receiver": address.receiver, "province": address.province.name, "city": address.city.name, "district": address.district.name, "place": address.place, "mobile": address.mobile, "tel": address.tel, "email": address.email } # 响应保存结果 return JsonResponse({'code': RETCODE.OK, 'errmsg': '新增地址成功', 'address': address_dict})
def put(self, request, address_id): """修改地址""" # 接收参数 json_dict = json.loads(request.body.decode()) receiver = json_dict.get('receiver') province_id = json_dict.get('province_id') city_id = json_dict.get('city_id') district_id = json_dict.get('district_id') place = json_dict.get('place') mobile = json_dict.get('mobile') tel = json_dict.get('tel') email = json_dict.get('email') # 校验参数 if not all([receiver, province_id, city_id, district_id, place, mobile]): return HttpResponseForbidden('缺少必传参数') if not re.match(r'^1[3-9]\d{9}$', mobile): return HttpResponseForbidden('参数mobile有误') if tel: if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel): return HttpResponseForbidden('参数tel有误') if email: if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email): return HttpResponseForbidden('参数email有误') # 判断地址是否存在,并更新地址信息 update 修改 try: Address.objects.filter(id=address_id).update( user=request.user, title=receiver, receiver=receiver, province_id=province_id, city_id=city_id, district_id=district_id, place=place, mobile=mobile, tel=tel, email=email ) # save 修改 # try: # address = Address.objects.get(id=address_id) # address.user = request.user # address.title = receiver # address.receiver = receiver # address.province_id = province_id # address.city_id = city_id # address.district_id = district_id # address.place = place # address.mobile = mobile # address.tel = tel # address.email = email # address.save() except Exception as e: logger.error(e) return JsonResponse({'code': RETCODE.DBERR, 'errmsg': '更新地址失败'}) # 构造响应数据 address = Address.objects.get(id=address_id) address_dict = { "id": address.id, "title": address.title, "receiver": address.receiver, "province": address.province.name, "city": address.city.name, "district": address.district.name, "place": address.place, "mobile": address.mobile, "tel": address.tel, "email": address.email } # 响应更新地址结果 return JsonResponse({'code': RETCODE.OK, 'errmsg': '更新地址成功', 'address': address_dict})
def get(self, request): ''' 提供省市区数据 :param request: :return: ''' area_id = request.GET.get('area_id') # 1.0 如果area_id 不存在 查询省 if not area_id: try: pro_list = Area.objects.filter(parent__isnull=True) # 序列化 省级list # 1.0 标准写法 # province_list = [] # for pro in pro_list: # province_list.append({'id': pro.id, 'name': pro.name}) # 2.0 列表推导式 province_list = [{ 'id': pro.id, 'name': pro.name } for pro in pro_list] except Exception as e: logger.error(e) return JsonResponse({ 'code': RETCODE.DBERR, 'errmsg': '省份数据错误' }) return JsonResponse({ 'code': RETCODE.OK, 'errmsg': 'OK', 'province_list': province_list }) else: # 提供市或区数据 try: parent = Area.objects.get(id=area_id) # 查询市或区的父级 subs = parent.subs.all() # 序列化市或区数据 # sub_list = [] # for sub_model in subs: # sub_list.append({'id': sub_model.id, 'name': sub_model.name}) sub_list = [{'id': sub.id, 'name': sub.name} for sub in subs] sub_data = { 'id': parent.id, # 父级pk 'name': parent.name, # 父级name 'subs': sub_list # 父级的子集 } except Exception as e: logger.error(e) return JsonResponse({ 'code': RETCODE.DBERR, 'errmsg': '城市或区数据错误' }) # 响应市或区数据 return JsonResponse({ 'code': RETCODE.OK, 'errmsg': 'OK', 'sub_data': sub_data })
def post(self, request): """美多商城用户绑定到openid""" # 接收参数 mobile = request.POST.get('mobile') pwd = request.POST.get('password') sms_code = request.POST.get('sms_code') openid = request.POST.get('openid') print(openid) openid = SecretOauth().loads(openid) # 判断参数是否齐全 if not all([mobile, pwd]): return HttpResponseForbidden('参数不齐') # 判断手机号是否合法 if not re.match(r'^1[3-9]\d{9}$', mobile): return HttpResponseForbidden('请输入正确的手机号码') # 判断密码是否合格 if not re.match(r'^[0-9A-Za-z]{8,20}$', pwd): return HttpResponseForbidden('请输入8-20位的密码') # 判断短信验证码是否一致 sms_code = request.POST.get('msg_code') # 6.1 从redis 中取出来 redis_code_client = get_redis_connection('sms_code') redis_code = redis_code_client.get('sms_%s' % mobile) if redis_code is None: return render(request, 'oauth_callback.html', {'sms_code_errmsg': '无效的短信验证码'}) if sms_code != redis_code.decode(): return render(request, 'oauth_callback.html', {'sms_code_errmsg': '输入短信验证码有误'}) # 判断openid是否有效:错误提示放在sms_code_errmsg位置 if not openid: return render(request, 'oauth_callback.html', {'openid_errmsg': '无效的openid'}) # 保存注册数据 try: user = User.objects.get(mobile=mobile) except User.DoesNotExist: # 用户不存在,新建用户 user = User.objects.create_user(username=mobile, password=pwd, mobile=mobile) else: # 如果用户存在,检查用户密码 if not user.check_password(pwd): return render(request, 'oauth_callback.html', {'account_errmsg': '用户名或密码错误'}) # 将用户绑定openid try: OAuthQQUser.objects.create(openid=openid, user=user) except Exception as e: logger.error(e) return render(request, 'oauth_callback.html', {'qq_login_errmsg': 'QQ登录失败'}) # 实现状态保持 login(request, user) # 响应绑定结果 next = request.GET.get('state') response = redirect(next) response = merge_cart_cookie_to_redis(request=request, user=user, response=response) # 登录时用户名写入到cookie,有效期15天 response.set_cookie('username', user.username, max_age=3600 * 24 * 15) return response
def get(self, reqeust, mobile): """ :param reqeust: 请求对象 :param mobile: 手机号 :return: JSON """ # 2.1 接收图片验证码 image_code = reqeust.GET.get('image_code') uuid = reqeust.GET.get('image_code_id') # 2.2 校验图片验证码的正确性 image_redis_client = get_redis_connection('verify_image_code') redis_img_code = image_redis_client.get('img_%s' % uuid) # 判断服务器返回的验证 if redis_img_code is None: return JsonResponse({ 'code': RETCODE.IMAGECODEERR, 'errmsg': '图形验证码失效了' }) # 如果有值 删除redis服务器上的图形验证码 try: image_redis_client.delete('img_%s' % uuid) except Exception as e: logger.error(e) # 2.2 和前端传过来的进行做对比 # 千万注意: 在redis取出来的是 bytes 类型不能直接做对比 decode() if image_code.lower() != redis_img_code.decode().lower(): return JsonResponse({ 'code': RETCODE.IMAGECODEERR, 'errmsg': '输入图形验证码有误' }) # 2.3 判断有没有send_flag 标识 # 2.3.1 链接数据库 sms_redis_client = get_redis_connection('sms_code') # 2.3.2 取出标示 send_flag = sms_redis_client.get('send_flag_%s' % mobile) # 2.3.3 如果存在 发送太频繁 if send_flag: return JsonResponse({ 'code': RETCODE.THROTTLINGERR, 'errmsg': '发送短信太频繁' }) # 2.3.4 如果不存 吧send_flag 标识一下 # 3.生成短信验证码,redis-存储 from random import randint sms_code = "%06d" % randint(MIN, MAX) try: pl = sms_redis_client.pipeline() pl.setex('send_flag_%s' % mobile, SMS_SEND_FREQUENT, PO) pl.setex("sms_%s" % mobile, SMS_EXPIRATION_TIME, sms_code) pl.execute() except Exception as e: logger.error(e) # 4.让第三方 容联云-给手机号-发送短信 # from libs.yuntongxun.sms import CCP # 手机号 验证码 过期时间5分钟 ,类型默认1 # CCP().send_template_sms(mobile, [sms_code, 5], 1) # CCP().send_template_sms(mobile, [sms_code, 5], 1) # print("当前验证码是:", sms_code) from celery_tasks.sms.tasks import ccp_send_sms_code ccp_send_sms_code.delay(mobile, sms_code) # print(sms_code) # 5.告诉前端短信发送完毕 return JsonResponse({'code': RETCODE.OK, 'errmsg': '发送短信成功'})