def put(self, request): # 接收参数 # 校验参数 # 保存数据 # 响应添加结果 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 http.HttpResponseForbidden('参数email有误') # 赋值email字段 try: request.user.email = email request.user.save() except Exception as e: logger.error(e) return http.JsonResponse({ 'code': RETCODE.DBERR, 'errmsg': '添加邮箱失败' }) # 4.异步发送邮件 from apps.users.utils import generate_verify_email_url 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 http.JsonResponse({'code': RETCODE.OK, 'errmsg': '添加邮箱成功'})
def get(self, request, mobile): '''短信验证码逻辑实现''' # 1.解析校验参数--mobile 不用校验 uuid = request.GET.get('image_code_id') image_code = request.GET.get('image_code') # 2.校验图形验证码 如果正确 发送验证码, 不正确 直接返回 # 根据uuid 去redis数据库查询 图片验证码 from django_redis import get_redis_connection 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 http.JsonResponse({'code': "4001", 'errmsg': '图形验证码失效了'}) # 有值则删除 try: image_redis_client.delete('img_%s' % uuid) except Exception as e: logger.error(e) # 判断前端数据与redis数据库中数据是否相符 if image_code.lower() != redis_img_code.decode().lower(): return http.JsonResponse({'code': "4001", 'errmsg': '输入图形验证码有误'}) # 生成短信验证码 保存验证码 from random import randint sms_code = "%06d" % randint(0, 999999) sms_redis_client = get_redis_connection('sms_code') send_flag = sms_redis_client.get('send_flag_%s' % mobile) if send_flag: return http.JsonResponse({ 'code': RETCODE.THROTTLINGERR, 'errmsg': '发送短信过于频繁' }) # 创建管道 pl = sms_redis_client.pipeline() # 保存短信验证码 pl.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code) # 重新写入send_flag pl.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1) pl.execute() # 第三方发送短信验证码 from celery_tasks.sms.tasks import ccp_send_sms_code send_result = ccp_send_sms_code(mobile, sms_code) print("当前验证码是:", sms_code) if send_result != 0: return http.HttpResponse({'code': '4001', 'errmsg': '发送短信失败'}) return http.HttpResponse({'code': '0', 'errmsg': '发送短信成功'})
def check_verify_email_token(token): from utils.secret import SecretOauth try: token_dict = SecretOauth().loads(token) except: 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): # 查询数据 # 设置默认地址 # 返回响应结果 try: address = Address.objects.get(id=address_id) request.user.default_address = address request.user.save() except Exception as e: logger.error(e) return http.JsonResponse({ 'code': RETCODE.DBERR, 'errmsg': '设置默认地址失败' }) return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '设置默认地址成功'})
def get(self, request): """Oauth2.0认证""" code = request.GET.get('code') if not code: return http.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) except Exception as e: logger.error(e) return http.HttpResponseServerError('OAuth2.0认证失败') try: oauth_user = OAuthQQUser.objects.get(openid=openid) except: # 如果openid没绑定美多商Y城用户 # 加密 openid--使用itsdangerous access_token = SecretOauth().dumps({'openid': openid}) context = {'access_token': access_token} print(context) return render(request, 'oauth_callback.html', context) else: # 如果openid已绑定美多商城用户 # 实现状态保持 qq_user = oauth_user.user login(request, qq_user) # 响应结果 next = request.GET.get('state') response = redirect(next) # 登录时用户名写入到cookie,有效期15天 response.set_cookie('username', qq_user.username, max_age=3600 * 24 * 15) 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 http.JsonResponse({ 'code': RETCODE.DBERR, 'errmsg': '删除地址失败' }) # 响应删除地址结果 return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '删除地址成功'})
def put(self, request, address_id): # 解析参数 # 查询数据是否存在并更新 # 返回响应 json_dict = json.loads(request.body.decode()) title = json_dict('title') try: address = Address.objects.get(id=address_id) address.title = title address.save() except Exception as e: logger.error(e) return http.JsonResponse({ 'code': RETCODE.DBERR, 'errmsg': '设置地址标题失败' }) return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '设置地址标题成功'})
def post(self, request): '''修改密码实现''' # 解析参数 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 http.HttpResponseForbidden('缺少必传参数') result = request.user.check_password(password=old_password) if not result: logger.error(e) return render(request, 'user_center_pass.html', {'origin_pwd_errmsg': '原始密码错误'}) # 判断密码是否是8-20个数字 if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password): return http.HttpResponseForbidden('请输入8-20位的密码') if new_password != new_password2: return http.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 send_verify_email(self, to_email, verify_url): """ 发送验证邮箱邮件 :param to_email: 收件人邮箱 :param verify_url: 验证链接 :return: None """ subject = "美多商城邮箱验证" html_message = '<p>尊敬的用户您好!</p>' \ '<p>感谢您使用美多商城。</p>' \ '<p>您的邮箱为:%s 。请点击此链接激活您的邮箱:</p>' \ '<p><a href="%s">%s<a></p>' % (to_email, verify_url, verify_url) try: send_mail(subject, "", settings.EMAIL_FROM, [to_email], html_message=html_message) except Exception as e: logger.error(e) # 有异常自动重试三次 raise self.retry(exc=e, max_retries=3)
def get(self, request): """实现邮箱验证逻辑""" # 接收参数 token = request.GET.get('token') # 校验参数:判断token是否为空和过期,提取user if not token: return http.HttpResponseBadRequest('缺少token') from .utils import check_verify_email_token user = check_verify_email_token(token) if not user: return http.HttpResponseForbidden('无效的token') # 修改email_active的值为True try: user.email_active = True user.save() except Exception as e: logger.error(e) return http.HttpResponseServerError('激活邮件失败') # 返回邮箱验证结果 return redirect(reverse('users:info'))
def get(self, request): """提供省市区数据""" area_id = request.GET.get('area_id') if not area_id: '''提供省数据''' try: province_model_list = Area.objects.filter(parent__isnull=True) provience_list = [] for province_model in province_model_list: provience_list.append({ 'id': province_model.id, 'name': province_model.name }) except Exception as e: logger.error(e) return http.JsonResponse({ 'code': RETCODE.DBERR, 'errmsg': '省份数据错误' }) # 响应省份数据 return http.JsonResponse({ 'code': RETCODE.OK, 'errmsg': 'OK', 'provience_list': provience_list }) else: # 提供市区数据 try: parent_model = Area.objects.get(id=area_id) # 查询市或区的父级 sub_model_list = parent_model.subs.all() # 序列化市或区数据 sub_list = [] for sub_model in sub_model_list: sub_list.append({ 'id': sub_model.id, 'name': sub_model.name }) sub_data = { 'id': parent_model.id, # 父级pk 'name': parent_model.name, # 父级name 'subs': sub_list # 父级的子集 } except Exception as e: logger.error(e) return http.JsonResponse({ 'code': RETCODE.DBERR, 'errmsg': '城市或区数据错误' }) # 响应市或区数据 return http.JsonResponse({ 'code': RETCODE.OK, 'errmsg': 'OK', 'sub_data': sub_data })
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 http.HttpResponseForbidden('缺少必传参数') if not re.match(r'^1[3-9]\d{9}$', mobile): return http.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 http.HttpResponseForbidden('参数tel有误') if email: if not re.match( r'^[a-z0-9][\w/.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email): return http.HttpResponseForbidden('参数email有误') 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) except Exception as e: logger.error(e) return http.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 http.JsonResponse({ 'code': RETCODE.OK, 'errmsg': '更新地址成功', 'address': address_dict })
def post(self, request): """实现新增地址逻辑""" # 判断是否超过地址上限:最多20个 # 接收参数 # 校验参数 # 保存地址信息 # 新增地址成功,将新增的地址响应给前端实现局部刷新 count = request.user.addresses.count() from . import constants if count >= constants.USER_ADDRESS_COUNTS_LIMIT: return http.JsonResponse({ 'code': RETCODE.THROTTLINGERR, 'errmsg': '超过地址数量上限' }) json_dict = json.loads(request.body.decode()) receiver = json_dict.get('receiver') # 收货人 province_id = json_dict.get('province_id') # 省份ID city_id = json_dict.get('city_id') # 城市ID district_id = json_dict.get('district_id') # 区县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 http.HttpResponseForbidden('缺少必传参数') if not re.match(r'^1[3-9]\d{9}$', mobile): return http.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 http.HttpResponseForbidden('参数tel有误') if email: if not re.match( r'^[a-z0-9][\w/.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email): return http.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: logger.error(e) return http.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 http.JsonResponse({ 'code': RETCODE.OK, 'errmsg': '新增地址成功', 'address': address_dict })