# coding:utf-8 from django.shortcuts import render,redirect from django.http.response import JsonResponse,HttpResponse,Http404 from django.contrib.auth import authenticate,login,logout # 认证相关方法 from django.contrib.auth.models import User # Django默认用户模型 from django.contrib.auth.decorators import login_required # 登录需求装饰器 from django.core.paginator import Paginator,PageNotAnInteger,EmptyPage,InvalidPage # 后端分页 from app_admin.decorators import superuser_only,open_register from django.core.exceptions import ObjectDoesNotExist from django.db.models import Q import datetime import requests from app_doc.models import * from app_admin.models import * from app_admin.utils import * import traceback from loguru import logger import re # 返回验证码图片 def check_code(request): try: import io from . import check_code as CheckCode stream = io.BytesIO() # img图片对象,code在图像中写的内容 img, code = CheckCode.create_validate_code() img.save(stream, "png") # 图片页面中显示,立即把session中的CheckCode更改为目前的随机字符串值 request.session["CheckCode"] = code return HttpResponse(stream.getvalue(), content_type="image/png") except Exception as e: logger.exception("生成验证码图片异常") return HttpResponse("请求异常:{}".format(repr(e))) # 登录视图 def log_in(request): if request.method == 'GET': # 登录用户访问登录页面自动跳转到首页 if request.user.is_authenticated: return redirect('/') else: return render(request,'login.html',locals()) elif request.method == 'POST': try: username = request.POST.get('username','') pwd = request.POST.get('password','') if username != '' and pwd != '': user = authenticate(username=username,password=pwd) if user is not None: if user.is_active: login(request,user) return redirect('/') else: errormsg = '用户被禁用!' return render(request, 'login.html', locals()) else: errormsg = '用户名或密码错误!' return render(request, 'login.html', locals()) else: errormsg = '用户名或密码错误!' return render(request, 'login.html', locals()) except Exception as e: logger.exception("登录异常") return HttpResponse('请求出错') # 注册视图 @open_register @logger.catch() def register(request): # 如果登录用户访问注册页面,跳转到首页 if request.user.is_authenticated: return redirect('/') else: if request.method == 'GET': return render(request,'register.html',locals()) elif request.method == 'POST': username = request.POST.get('username',None) email = request.POST.get('email',None) password = request.POST.get('password',None) checkcode = request.POST.get("check_code",None) register_code = request.POST.get("register_code",None) is_register_code = SysSetting.objects.filter(types='basic', name='enable_register_code', value='on') if is_register_code.count() > 0: # 开启了注册码设置 try: register_code_value = RegisterCode.objects.get(code=register_code,status=1) except ObjectDoesNotExist: errormsg = '注册码无效!' return render(request, 'register.html', locals()) # 判断是否输入了用户名、邮箱和密码 if username and email and password: if '@'in email: email_exit = User.objects.filter(email=email) username_exit = User.objects.filter(username=username) if email_exit.count() > 0: # 验证电子邮箱 errormsg = '此电子邮箱已被注册!' return render(request, 'register.html', locals()) elif username_exit.count() > 0: # 验证用户名 errormsg = '用户名已被使用!' return render(request, 'register.html', locals()) elif re.match('^[0-9a-z]+$',username) is False: errormsg = '用户名只能为英文数字组合' return render(request, 'register.html', locals()) elif len(username) < 6: errormsg = '用户名必须大于等于6位!' return render(request, 'register.html', locals()) elif len(password) < 6: # 验证密码长度 errormsg = '密码必须大于等于6位!' return render(request, 'register.html', locals()) elif checkcode != request.session['CheckCode'].lower(): # 验证验证码 errormsg = "验证码错误" return render(request, 'register.html', locals()) else: # 创建用户 user = User.objects.create_user(username=username, email=email, password=password) user.save() # 登录用户 user = authenticate(username=username, password=password) # 注册码数据更新 if is_register_code.count() > 0: r_all_cnt = register_code_value.all_cnt # 注册码的最大使用次数 r_used_cnt = register_code_value.used_cnt + 1 # 更新注册码的已使用次数 r_use_user = register_code_value.user_list # 注册码的使用用户 if r_used_cnt >= r_all_cnt: # 如果注册码已使用次数大于等于注册码的最大使用次数,则注册码失效 RegisterCode.objects.filter(code=register_code).update( status=0,# 注册码状态设为失效 used_cnt = r_used_cnt, # 更新注册码的已使用次数 user_list = r_use_user + email + ',', ) else: RegisterCode.objects.filter(code=register_code).update( used_cnt=r_used_cnt, # 更新注册码的已使用次数 user_list = r_use_user + email + ',', ) if user.is_active: login(request, user) return redirect('/') else: errormsg = '用户被禁用,请联系管理员!' return render(request, 'register.html', locals()) else: errormsg = '请输入正确的电子邮箱格式!' return render(request, 'register.html', locals()) else: errormsg = "请检查输入值" return render(request, 'register.html', locals()) # 注销 def log_out(request): try: logout(request) except Exception as e: logger.exception("注销异常") return redirect(request.META['HTTP_REFERER']) # 忘记密码 def forget_pwd(request): if request.method == 'GET': return render(request,'forget_pwd.html',locals()) elif request.method == 'POST': email = request.POST.get("email",None) # 邮箱 vcode = request.POST.get("vcode",None) # 验证码 new_pwd= request.POST.get('password',None) # 密码 new_pwd_confirm = request.POST.get('confirm_password') # 查询验证码和邮箱是否匹配 try: data = EmaiVerificationCode.objects.get(email_name=email,verification_code=vcode,verification_type='忘记密码') expire_time = data.expire_time print(expire_time) if expire_time > datetime.datetime.now(): user = User.objects.get(email=email) user.set_password(new_pwd) user.save() errormsg = "修改密码成功,请返回登录!" return render(request, 'forget_pwd.html', locals()) else: errormsg = "验证码已过期" return render(request, 'forget_pwd.html', locals()) except Exception as e: logger.exception("修改密码异常") errormsg = "验证码错误" return render(request,'forget_pwd.html',locals()) # 发送电子邮箱验证码 @logger.catch() def send_email_vcode(request): if request.method == 'POST': email = request.POST.get('email',None) is_email = User.objects.filter(email=email) if is_email.count() != 0: vcode_str = generate_vcode() # 发送邮件 send_status = send_email(to_email=email, vcode_str=vcode_str) if send_status: # 生成过期时间 now_time = datetime.datetime.now() expire_time = now_time + datetime.timedelta(minutes=30) # 创建数据库记录 EmaiVerificationCode.objects.create( email_name = email, verification_type = '忘记密码', verification_code = vcode_str, expire_time = expire_time ) return JsonResponse({'status':True,'data':'发送成功'}) else: return JsonResponse({'status':False,'data':'发送验证码出错,请重试!'}) else: return JsonResponse({'status':False,'data':'电子邮箱不存在!'}) else: return JsonResponse({'status':False,'data':'方法错误'}) # 管理员后台首页 - 用户管理 @superuser_only @logger.catch() def admin_user(request): if request.method == 'GET': # user_list = User.objects.all() return render(request, 'app_admin/admin_user.html', locals()) elif request.method == 'POST': username = request.POST.get('username','') if username == '': user_data = User.objects.all().values_list( 'id','last_login','is_superuser','username','email','date_joined','is_active','first_name' ) else: user_data = User.objects.filter(username__icontains=username).values_list( 'id','last_login','is_superuser','username','email','date_joined','is_active','first_name' ) table_data = [] for i in list(user_data): item = { 'id':i[0], 'last_login':i[1], 'is_superuser':i[2], 'username':i[3], 'email':i[4], 'date_joined':i[5], 'is_active':i[6], 'first_name':i[7] } table_data.append(item) return JsonResponse({'status':True,'data':table_data}) else: return JsonResponse({'status':False,'data':'方法错误'}) # 管理员后台首页 - 创建用户 @superuser_only @logger.catch() def admin_create_user(request): if request.method == 'POST': username = request.POST.get('username','') # 接收用户名参数 email = request.POST.get('email','') # 接收email参数 password = request.POST.get('password','') # 接收密码参数 user_type = request.POST.get('user_type',0) # 用户类型 0为普通用户,1位管理员 if username != '' and password != '' and email != '' and \ '@' in email and re.match(r'^[0-9a-z]',username) and len(username) >= 6 : # 不允许电子邮箱重复 if User.objects.filter(email = email).count() > 0: return JsonResponse({'status':False,'data':'电子邮箱不可重复'}) # 不允许重复的用户名 if User.objects.filter(username = username).count() > 0: return JsonResponse({'status': False,'data':'用户名不可重复'}) try: if user_type == 0: user = User.objects.create_user( username=username, password=password, email=email ) user.save() elif int(user_type) == 1: user = User.objects.create_superuser( username=username, password=password, email=email ) user.save() return JsonResponse({'status':True}) except Exception as e: return JsonResponse({'status':False,'data':'系统异常'}) else: return JsonResponse({'status':False,'data':'请检查参数'}) else: return HttpResponse('方法不允许') # 管理员后台 - 修改密码 @superuser_only @logger.catch() def admin_change_pwd(request): if request.method == 'POST': try: user_id = request.POST.get('user_id',None) password = request.POST.get('password',None) password2 = request.POST.get('password2',None) if user_id and password: if password == password2: user = User.objects.get(id=int(user_id)) user.set_password(password) user.save() return JsonResponse({'status':True,'data':'修改成功'}) else: return JsonResponse({'status':False,'data':'两个密码不一致'}) else: return JsonResponse({'status':False,'data':'参数错误'}) except Exception as e: print(repr(e)) return JsonResponse({'status':False,'data':'请求错误'}) else: return JsonResponse({'status':False,'data':'方法错误'}) # 管理员后台 - 删除用户 @superuser_only @logger.catch() def admin_del_user(request): if request.method == 'POST': try: user_id = request.POST.get('user_id',None) user = User.objects.get(id=int(user_id)) user.delete() return JsonResponse({'status':True,'data':'删除成功'}) except Exception as e: return JsonResponse({'status':False,'data':'删除出错'}) else: return JsonResponse({'status':False,'data':'方法错误'}) # 管理员后台 - 文集管理 @superuser_only @logger.catch() def admin_project(request): if request.method == 'GET': search_kw = request.GET.get('kw','') if search_kw == '': project_list = Project.objects.all().order_by('-create_time') paginator = Paginator(project_list,10) page = request.GET.get('page',1) try: projects = paginator.page(page) except PageNotAnInteger: projects = paginator.page(1) except EmptyPage: projects = paginator.page(paginator.num_pages) else: project_list = Project.objects.filter(intro__icontains=search_kw) paginator = Paginator(project_list, 10) page = request.GET.get('page', 1) try: projects = paginator.page(page) except PageNotAnInteger: projects = paginator.page(1) except EmptyPage: projects = paginator.page(paginator.num_pages) projects.kw = search_kw return render(request,'app_admin/admin_project.html',locals()) else: return HttpResponse('方法错误') # 管理员后台 - 修改文集权限 @superuser_only @logger.catch() def admin_project_role(request,pro_id): pro = Project.objects.get(id=pro_id) if request.method == 'GET': return render(request,'app_admin/admin_project_role.html',locals()) elif request.method == 'POST': role_type = request.POST.get('role','') if role_type != '': if int(role_type) in [0,1]:# 公开或私密 Project.objects.filter(id=int(pro_id)).update( role = role_type, modify_time = datetime.datetime.now() ) if int(role_type) == 2: # 指定用户可见 role_value = request.POST.get('tagsinput','') Project.objects.filter(id=int(pro_id)).update( role=role_type, role_value = role_value, modify_time = datetime.datetime.now() ) if int(role_type) == 3: # 访问码可见 role_value = request.POST.get('viewcode','') Project.objects.filter(id=int(pro_id)).update( role=role_type, role_value=role_value, modify_time=datetime.datetime.now() ) pro = Project.objects.get(id=int(pro_id)) return render(request, 'app_admin/admin_project_role.html', locals()) else: return Http404 # 管理员后台 - 文档管理 @superuser_only @logger.catch() def admin_doc(request): if request.method == 'GET': kw = request.GET.get('kw','') if kw == '': doc_list = Doc.objects.all().order_by('-modify_time') paginator = Paginator(doc_list, 10) page = request.GET.get('page', 1) try: docs = paginator.page(page) except PageNotAnInteger: docs = paginator.page(1) except EmptyPage: docs = paginator.page(paginator.num_pages) else: doc_list = Doc.objects.filter(Q(content__icontains=kw) | Q(name__icontains=kw)).order_by('-modify_time') paginator = Paginator(doc_list, 10) page = request.GET.get('page', 1) try: docs = paginator.page(page) except PageNotAnInteger: docs = paginator.page(1) except EmptyPage: docs = paginator.page(paginator.num_pages) docs.kw = kw return render(request,'app_admin/admin_doc.html',locals()) # 管理员后台 - 文档模板管理 @superuser_only @logger.catch() def admin_doctemp(request): if request.method == 'GET': kw = request.GET.get('kw','') if kw == '': doctemp_list = DocTemp.objects.all() paginator = Paginator(doctemp_list, 10) page = request.GET.get('page', 1) try: doctemps = paginator.page(page) except PageNotAnInteger: doctemps = paginator.page(1) except EmptyPage: doctemps = paginator.page(paginator.num_pages) else: doctemp_list = DocTemp.objects.filter(content__icontains=kw) paginator = Paginator(doctemp_list, 10) page = request.GET.get('page', 1) try: doctemps = paginator.page(page) except PageNotAnInteger: doctemps = paginator.page(1) except EmptyPage: doctemps = paginator.page(paginator.num_pages) doctemps.kw = kw return render(request,'app_admin/admin_doctemp.html',locals()) # 管理员后台 - 注册邀请码管理 @superuser_only @logger.catch() def admin_register_code(request): # 返回注册邀请码管理页面 if request.method == 'GET': register_codes = RegisterCode.objects.all() paginator = Paginator(register_codes, 10) page = request.GET.get('page', 1) try: codes = paginator.page(page) except PageNotAnInteger: codes = paginator.page(1) except EmptyPage: codes = paginator.page(paginator.num_pages) return render(request,'app_admin/admin_register_code.html',locals()) elif request.method == 'POST': types = request.POST.get('types',None) if types is None: return JsonResponse({'status':False,'data':'参数错误'}) # types表示注册码操作的类型,1表示新增、2表示删除 if int(types) == 1: try: all_cnt = int(request.POST.get('all_cnt',1)) # 注册码的最大使用次数 if all_cnt <= 0: return JsonResponse({'status': False, 'data': '最大使用次数不可为负数'}) is_code = False while is_code is False: code_str = '0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM' random_code = ''.join(random.sample(code_str, k=10)) random_code_used = RegisterCode.objects.filter(code=random_code).count() if random_code_used > 0: # 已存在此注册码,继续生成一个注册码 is_code = False else:# 数据库中不存在此注册码,跳出循环 is_code = True # 创建一个注册码 RegisterCode.objects.create( code = random_code, all_cnt = all_cnt, create_user = request.user ) return JsonResponse({'status':True,'data':'新增成功'}) except Exception as e: logger.exception("生成注册码异常") return JsonResponse({'status': False,'data':'系统异常'}) elif int(types) == 2: code_id = request.POST.get('code_id',None) try: register_code = RegisterCode.objects.get(id=int(code_id)) register_code.delete() return JsonResponse({'status':True,'data':'删除成功'}) except ObjectDoesNotExist: return JsonResponse({'status':False,'data':'注册码不存在'}) except: return JsonResponse({'status':False,'data':'系统异常'}) else: return JsonResponse({'status':False,'data':'类型错误'}) else: return JsonResponse({'status': False,'data':'方法错误'}) # 普通用户修改密码 @login_required() @logger.catch() def change_pwd(request): if request.method == 'POST': try: password = request.POST.get('password',None) password2 = request.POST.get('password2',None) print(password, password2) if password and password== password2: if len(password) >= 6: user = User.objects.get(id=request.user.id) user.set_password(password) user.save() return JsonResponse({'status':True,'data':'修改成功'}) else: return JsonResponse({'status':False,'data':'密码不得少于6位数'}) else: return JsonResponse({'status':False,'data':'两个密码不一致'}) except Exception as e: return JsonResponse({'status':False,'data':'修改出错'}) else: return HttpResponse('方法错误') # 管理员后台 - 应用设置 @superuser_only @logger.catch() def admin_setting(request): email_settings = SysSetting.objects.filter(types="email") if email_settings.count() == 6: emailer = email_settings.get(name='send_emailer') email_host = email_settings.get(name='smtp_host') email_port = email_settings.get(name='smtp_port') email_username = email_settings.get(name="username") email_ssl = email_settings.get(name="smtp_ssl") email_pwd = email_settings.get(name="pwd") if request.method == 'GET': return render(request,'app_admin/admin_setting.html',locals()) elif request.method == 'POST': types = request.POST.get('type',None) # 基础设置 if types == 'basic': site_name = request.POST.get('site_name',None) # 站点名称 site_sub_name = request.POST.get('site_sub_name', None) # 站点子标题 site_keywords = request.POST.get('site_keywords', None) # 站点关键词 site_desc = request.POST.get('site_desc', None) # 站点描述 beian_code = request.POST.get('beian_code', None) # 备案号 index_project_sort = request.POST.get('index_project_sort','1') # 首页文集默认排序 close_register = request.POST.get('close_register',None) # 禁止注册 require_login = request.POST.get('require_login',None) # 全站登录 static_code = request.POST.get('static_code',None) # 统计代码 ad_code = request.POST.get('ad_code',None) # 广告位1 ad_code_2 = request.POST.get('ad_code_2',None) # 广告位2 ad_code_3 = request.POST.get('ad_code_3', None) # 广告位3 enbale_email = request.POST.get("enable_email",None) # 启用邮箱 img_scale = request.POST.get('img_scale',None) # 图片缩略 enable_register_code = request.POST.get('enable_register_code',None) # 注册邀请码 enable_project_report = request.POST.get('enable_project_report',None) # 文集导出 # 更新首页文集默认排序 SysSetting.objects.update_or_create( name='index_project_sort', defaults={'value': index_project_sort, 'types': 'basic'} ) # 更新开放注册状态 SysSetting.objects.update_or_create( name='require_login', defaults={'value':require_login,'types':'basic'} ) # 更新全站登录状态 SysSetting.objects.update_or_create( name='close_register', defaults={'value': close_register, 'types': 'basic'} ) # 更新统计代码状态 SysSetting.objects.update_or_create( name = 'static_code', defaults={'value':static_code,'types':'basic'} ) # 更新广告代码状态 SysSetting.objects.update_or_create( name = 'ad_code', defaults={'value':ad_code,'types':'basic'} ) SysSetting.objects.update_or_create( name='ad_code_2', defaults={'value': ad_code_2, 'types': 'basic'} ) SysSetting.objects.update_or_create( name='ad_code_3', defaults={'value': ad_code_3, 'types': 'basic'} ) # 更新备案号 SysSetting.objects.update_or_create( name='beian_code', defaults={'value':beian_code,'types':'basic'} ) # 更新站点名称 SysSetting.objects.update_or_create( name='site_name', defaults={'value': site_name, 'types': 'basic'} ) # 更新站点子标题 SysSetting.objects.update_or_create( name='site_sub_name', defaults={'value': site_sub_name, 'types': 'basic'} ) # 更新站点关键词 SysSetting.objects.update_or_create( name='site_keywords', defaults={'value': site_keywords, 'types': 'basic'} ) # 更新站点描述 SysSetting.objects.update_or_create( name='site_desc', defaults={'value': site_desc, 'types': 'basic'} ) # 更新图片缩略状态 SysSetting.objects.update_or_create( name='img_scale', defaults={'value': img_scale, 'types': 'basic'} ) # 更新邮箱启用状态 SysSetting.objects.update_or_create( name='enable_email', defaults={'value': enbale_email, 'types': 'basic'} ) # 更新注册码启停状态 SysSetting.objects.update_or_create( name = 'enable_register_code', defaults= {'value': enable_register_code, 'types':'basic'} ) # 更新文集导出状态 SysSetting.objects.update_or_create( name = 'enable_project_report', defaults={'value':enable_project_report,'types':'basic'} ) return render(request,'app_admin/admin_setting.html',locals()) # 邮箱设置 elif types == 'email': # 读取上传的参数 emailer = request.POST.get("send_emailer",None) host = request.POST.get("smtp_host",None) port = request.POST.get("smtp_port",None) username = request.POST.get("smtp_username",None) pwd = request.POST.get("smtp_pwd",None) ssl = request.POST.get("smtp_ssl",None) # 对密码进行加密 pwd = enctry(pwd) if emailer != None: # 更新发件箱 SysSetting.objects.update_or_create( name = 'send_emailer', defaults={"value":emailer,"types":'email'} ) if host != None: # 更新邮箱主机 SysSetting.objects.update_or_create( name='smtp_host', defaults={"value": host, "types": 'email'} ) if port != None: # 更新邮箱主机端口 SysSetting.objects.update_or_create( name='smtp_port', defaults={"value": port, "types": 'email'} ) if username != None: # 更新用户名 SysSetting.objects.update_or_create( name='username', defaults={"value": username, "types": 'email'} ) if pwd != None: # 更新密码 SysSetting.objects.update_or_create( name='pwd', defaults={"value": pwd, "types": 'email'} ) # 更新SSL SysSetting.objects.update_or_create( name='smtp_ssl', defaults={"value": ssl, "types": 'email'} ) email_settings = SysSetting.objects.filter(types="email") if email_settings.count() == 6: emailer = email_settings.get(name='send_emailer') email_host = email_settings.get(name='smtp_host') email_port = email_settings.get(name='smtp_port') email_username = email_settings.get(name="username") email_ssl = email_settings.get(name="smtp_ssl") email_pwd = email_settings.get(name="pwd") return render(request, 'app_admin/admin_setting.html',locals()) # 文档全局设置 elif types == 'doc': # iframe白名单 iframe_whitelist = request.POST.get('iframe_whitelist','') SysSetting.objects.update_or_create( name = 'iframe_whitelist', defaults = {'value':iframe_whitelist,'types':'doc'} ) # 上传图片大小 img_size = request.POST.get('img_size', 10) try: if int(img_size) == 0: img_size = 50 else: img_size = abs(int(img_size)) except Exception as e: # print(repr(e)) img_size = 10 SysSetting.objects.update_or_create( name='img_size', defaults={'value': img_size, 'types': 'doc'} ) # 附件格式白名单 attachment_suffix = request.POST.get('attachment_suffix','') SysSetting.objects.update_or_create( name = 'attachment_suffix', defaults = {'value':attachment_suffix,'types':'doc'} ) # 附件大小 attachment_size = request.POST.get('attachment_size',50) try: if int(attachment_size) == 0: attachment_size = 50 else: attachment_size = abs(int(attachment_size)) except Exception as e: # print(repr(e)) attachment_size = 50 SysSetting.objects.update_or_create( name='attachment_size', defaults={'value': attachment_size, 'types': 'doc'} ) return render(request, 'app_admin/admin_setting.html', locals()) # 检测版本更新 def check_update(request): url = 'https://gitee.com/api/v5/repos/zmister/MrDoc/tags' resp = requests.get(url,timeout=5).json() return JsonResponse({'status':True,'data':resp[-1]})