import re from allauth.account.views import logout from django.contrib.auth.decorators import login_required from django.contrib.auth.hashers import make_password from django.contrib.auth import login as auth_login from django.core.exceptions import ValidationError from django.core.validators import validate_email import time from django.db import connections from .models import User, UserSource import json import logging import requests from django.http import JsonResponse, HttpResponse from django.views.decorators.csrf import csrf_exempt from .mail import send_verification_email, verify_code from .aliyun_sms import send_verification_sms, verify_sms_code # 定义积分奖励值 REWARD_POINTS = 50 # 例如奖励50积分 def check_and_reward_points(user, openid): """ 根据 openid 查询原系统会员状态,为原系统的用户增加一天会员时长(不论是否为会员)。 同时在新系统中奖励积分,并做好记录防止重复赠送或刷量。 :param user: 当前新系统中的用户 :param openid: 用户的 openid :return: JSON 响应,包含奖励结果 """ try: # 检查当前用户是否已经使用过 openid 获得奖励,防止重复赠送 if user.openid_used: return JsonResponse({'code': 400, 'message': '该用户已经通过 openid 获得过奖励', 'data': {}}) # 检查 openid 是否已被其他用户使用过,防止刷量 if User.objects.filter(openid_used=openid).exists(): return JsonResponse({'code': 400, 'message': '该 openid 已经被使用过', 'data': {}}) # 查询原系统数据库中的会员信息 with connections['external_db'].cursor() as cursor: # 查询用户的 id、is_member 和 member_end_time query = """ SELECT id, is_member, member_end_time FROM user WHERE openid = %s """ cursor.execute(query, [openid]) result = cursor.fetchone() if not result: return JsonResponse({'code': 404, 'message': '未找到此用户', 'data': {}}) user_id, is_member, member_end_time = result # 保存用户原始的会员状态,用于后续判断 original_is_member = is_member # 获取当前时间戳 current_timestamp = int(time.time()) one_day_seconds = 86400 # 一天的秒数 # 不管用户是否是会员,都在原系统中增加一天会员时长 # 如果用户不是会员,需要将 is_member 设置为 1 if is_member == 0: is_member = 1 # 设置为会员 # 计算新的会员结束时间 if member_end_time and member_end_time > current_timestamp: # 会员未过期,延长一天 new_member_end_time = member_end_time + one_day_seconds else: # 会员已过期或从未开通过会员,从当前时间开始加一天 new_member_end_time = current_timestamp + one_day_seconds # 更新原系统用户的会员状态和结束时间 update_query = """ UPDATE user SET is_member = %s, member_end_time = %s WHERE id = %s """ cursor.execute(update_query, [is_member, new_member_end_time, user_id]) # 提交事务 connections['external_db'].commit() # 如果用户在原系统中原本是会员,额外奖励积分 if original_is_member == 1: user.points += REWARD_POINTS user.source = 'old_website_member' # 来源于旧网站会员 else: user.source = 'old_website' # 来源于旧网站非会员 # 标记新系统用户的 openid 已使用 user.openid_used = openid user.save() return JsonResponse({ 'code': 200, 'message': '成功奖励积分,并为原系统用户增加一天会员时长', 'data': { 'points': user.points } }) except Exception as e: return JsonResponse({'code': 500, 'message': f'系统错误: {str(e)}', 'data': {}}) #登录后获取用户信息 @csrf_exempt def user_profile(request): # 验证用户是否已登录 if not request.user.is_authenticated: return JsonResponse({'code': 401, 'message': '用户未登录'}) try: user = request.user openid = request.COOKIES.get('openid', None) if openid: # 调用检查会员状态并奖励积分的函数 reward_response = check_and_reward_points(user, openid) print(f'用户注册登录:{reward_response}') user_data = { 'id': user.id, 'username': user.username, 'email': user.email, 'phone': user.phone, 'is_member': user.is_member, 'points': user.points, 'referral_code': user.referral_code, 'commission_rate': user.commission_rate, 'login_count': user.login_count, 'last_login_ip': user.last_login_ip, 'membership_start': user.membership_start, 'membership_end': user.membership_end } return JsonResponse({'code': 200, 'message': '获取成功', 'data': user_data}) except: return JsonResponse({'code': 400, 'message': '非法参数'}) #邮箱号码发送和核验部分: @csrf_exempt def send_verification_email_view(request): if request.method == 'POST': try: body = json.loads(request.body) email = body.get('email') if not email: return JsonResponse({'code': 400, 'message': '邮箱地址是必须的'}) response = send_verification_email(email) return JsonResponse(response) except json.JSONDecodeError: return JsonResponse({'code': 400, 'message': '无效的请求数据'}) except Exception as e: return JsonResponse({'code': 500, 'message': f'服务器内部错误: {str(e)}'}) else: return JsonResponse({'code': 405, 'message': '方法不允许'}) @csrf_exempt def verify_code_view(request): if request.method == 'POST': try: body = json.loads(request.body) email = body.get('phone_number') code = body.get('code') if not email or not code: return JsonResponse({'code': 400, 'message': '邮箱和验证码是必须的'}) response = verify_code(email, code) return JsonResponse(response) except json.JSONDecodeError: return JsonResponse({'code': 400, 'message': '无效的请求数据'}) except Exception as e: return JsonResponse({'code': 500, 'message': f'服务器内部错误: {str(e)}'}) else: return JsonResponse({'code': 405, 'message': '方法不允许'}) @csrf_exempt def send_verification_sms_view(request): if request.method == 'POST': try: body = json.loads(request.body) phone_number = body.get('phone_number') if not phone_number: return JsonResponse({'code': 400, 'message': '手机号码是必须的'}) sign_name = "光映" # 替换为实际的签名名称 template_code = "SMS_473670066" # 替换为实际的短信模板代码 response = send_verification_sms(phone_number, sign_name, template_code) return JsonResponse(response) except json.JSONDecodeError: return JsonResponse({'code': 400, 'message': '无效的请求数据'}) except Exception as e: return JsonResponse({'code': 500, 'message': f'服务器内部错误: {str(e)}'}) else: return JsonResponse({'code': 405, 'message': '方法不允许'}) @csrf_exempt def verify_sms_code_view(request): if request.method == 'POST': try: body = json.loads(request.body) phone_number = body.get('phone_number') code = body.get('code') if not phone_number or not code: return JsonResponse({'code': 400, 'message': '手机号码和验证码是必须的'}) response = verify_sms_code(phone_number, code) return JsonResponse(response) except json.JSONDecodeError: return JsonResponse({'code': 400, 'message': '无效的请求数据'}) except Exception as e: return JsonResponse({'code': 500, 'message': f'服务器内部错误: {str(e)}'}) else: return JsonResponse({'code': 405, 'message': '方法不允许'}) #邮箱号码发送和核验部分END: #用户注册部分 @csrf_exempt def register_view(request): if request.method == 'POST': try: body = json.loads(request.body) username = body.get('username') password = body.get('password') confirm_password = body.get('confirm_password') email = body.get('email') phone = body.get('phone') code = body.get('code') register_method = body.get('registerMethod') if not username or not password or not confirm_password: return JsonResponse({'code': 400, 'message': '用户名和密码是必须的'}) if password != confirm_password: return JsonResponse({'code': 400, 'message': '两次密码输入不一致'}) if not validate_password_strength(password): return JsonResponse({'code': 400, 'message': '密码强度不够'}) if User.objects.filter(phone=phone).exists(): return JsonResponse({'code': 400, 'message': '手机号已存在'}) if User.objects.filter(email=email).exists(): return JsonResponse({'code': 400, 'message': '此邮箱已存在'}) if User.objects.filter(username=username).exists(): return JsonResponse({'code': 400, 'message': '用户名已存在'}) if register_method == 'email': if not email or not code: return JsonResponse({'code': 400, 'message': '邮箱和验证码是必须的'}) try: validate_email(email) except ValidationError: return JsonResponse({'code': 400, 'message': '无效的邮箱地址'}) email_verification_result = verify_code(email, code) if email_verification_result['code'] != 200: return JsonResponse(email_verification_result) user = User.objects.create(username=username, email=email, password=make_password(password)) else: if not phone or not code: return JsonResponse({'code': 400, 'message': '手机号和验证码是必须的'}) sms_verification_result = verify_sms_code(phone, code) if sms_verification_result['code'] != 200: return JsonResponse(sms_verification_result) user = User.objects.create(username=username, password=make_password(password)) user.phone = phone user.save() user.backend = 'allauth.account.auth_backends.AuthenticationBackend' auth_login(request, user) return JsonResponse({'code': 200, 'message': '注册成功'}) except json.JSONDecodeError: return JsonResponse({'code': 400, 'message': '无效的请求数据'}) except Exception as e: return JsonResponse({'code': 500, 'message': f'服务器内部错误: {str(e)}'}) else: return JsonResponse({'code': 405, 'message': '方法不允许'}) def validate_password_strength(password): if len(password) < 6: return False if not re.search(r"[A-Za-z]", password) or not re.search(r"[0-9]", password): return False return True #注册部分结束 #登录部分开始 @csrf_exempt def login_view(request): if request.method == 'POST': try: body = json.loads(request.body) login_type = body.get('login_type') if login_type == 'password': username = body.get('username') password = body.get('password') if not username or not password: return JsonResponse({'code': 400, 'message': '用户名和密码是必须的'}) # 验证用户名可以是邮箱或手机号 user = None if re.match(r'^\S+@\S+\.\S+$', username): # 判断是否为邮箱 user = User.objects.filter(email=username).first() elif re.match(r'^\d{11}$', username): # 判断是否为手机号 user = User.objects.filter(phone=username).first() if user and user.check_password(password): user.backend = 'allauth.account.auth_backends.AuthenticationBackend' auth_login(request, user) return JsonResponse({'code': 200, 'message': '登录成功'}) else: return JsonResponse({'code': 400, 'message': '用户名或密码错误'}) elif login_type == 'code': phone = body.get('phone') code = body.get('code') if not phone or not code: return JsonResponse({'code': 400, 'message': '手机号和验证码是必须的'}) # 调用验证码核验接口 sms_verification_result = verify_sms_code(phone, code) if sms_verification_result['code'] != 200: return JsonResponse(sms_verification_result) try: user = User.objects.get(phone=phone) if user: user.backend = 'allauth.account.auth_backends.AuthenticationBackend' auth_login(request, user) return JsonResponse({'code': 200, 'message': '登录成功'}) else: return JsonResponse({'code': 400, 'message': '用户不存在'}) except User.DoesNotExist: return JsonResponse({'code': 400, 'message': '用户不存在'}) except Exception as e: return JsonResponse({'code': 500, 'message': f'服务器内部错误: {str(e)}'}) else: return JsonResponse({'code': 400, 'message': '无效的登录类型'}) except json.JSONDecodeError: return JsonResponse({'code': 400, 'message': '无效的请求数据'}) except Exception as e: return JsonResponse({'code': 500, 'message': f'服务器内部错误: {str(e)}'}) else: return JsonResponse({'code': 405, 'message': '方法不允许'}) #找回密码开始 @csrf_exempt def send_verification_code_view(request): if request.method == 'POST': try: body = json.loads(request.body) identifier = body.get('identifier') if not identifier: return JsonResponse({'code': 400, 'message': '手机号或邮箱是必须的'}) if '@' in identifier: response = send_verification_email(identifier) else: response = send_verification_sms(identifier, "光映", "SMS_473670066") return JsonResponse(response) except json.JSONDecodeError: return JsonResponse({'code': 400, 'message': '无效的请求数据'}) except Exception as e: return JsonResponse({'code': 500, 'message': f'服务器内部错误: {str(e)}'}) else: return JsonResponse({'code': 405, 'message': '方法不允许'}) @csrf_exempt def reset_password_view(request): if request.method == 'POST': try: body = json.loads(request.body) identifier = body.get('identifier') code = body.get('code') new_password = body.get('new_password') if not identifier or not code or not new_password: return JsonResponse({'code': 400, 'message': '所有字段都是必须的'}) if '@' in identifier: verification_result = verify_code(identifier, code) else: verification_result = verify_sms_code(identifier, code) if verification_result['code'] != 200: return JsonResponse(verification_result) if not validate_password_strength(new_password): return JsonResponse({'code': 400, 'message': '密码强度不够'}) if '@' in identifier: user = User.objects.get(email=identifier) else: user = User.objects.get(phone=identifier) user.password = make_password(new_password) user.save() return JsonResponse({'code': 200, 'message': '密码重置成功'}) except User.DoesNotExist: return JsonResponse({'code': 400, 'message': '用户不存在'}) except json.JSONDecodeError: return JsonResponse({'code': 400, 'message': '无效的请求数据'}) except Exception as e: return JsonResponse({'code': 500, 'message': f'服务器内部错误: {str(e)}'}) else: return JsonResponse({'code': 405, 'message': '方法不允许'}) #找回密码结束 #退出登录开始 @csrf_exempt def logout_view(request): """ 用户退出登录接口 """ if request.method == 'POST': # 执行 Django 的内置 logout 函数,清除用户的 session logout(request) return JsonResponse({'code': 200, 'message': 'ok','data': {}}) return JsonResponse({'code': 405, 'message': 'no','data': {}}) #退出登录结束