MrDoc/app_doc/views.py
2020-08-02 06:50:57 +08:00

2004 lines
88 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# coding:utf-8
from django.shortcuts import render,redirect
from django.http.response import JsonResponse,Http404,HttpResponseNotAllowed,HttpResponse
from django.http import HttpResponseForbidden
from django.contrib.auth.decorators import login_required # 登录需求装饰器
from django.views.decorators.http import require_http_methods,require_GET,require_POST # 视图请求方法装饰器
from django.core.paginator import Paginator,PageNotAnInteger,EmptyPage,InvalidPage # 后端分页
from django.core.exceptions import PermissionDenied,ObjectDoesNotExist
from app_doc.models import Project,Doc,DocTemp
from django.contrib.auth.models import User
from django.db.models import Q
from django.db import transaction
from loguru import logger
import datetime
import traceback
import re
from app_doc.report_utils import *
from app_admin.decorators import check_headers,allow_report_file
import os.path
# 替换前端传来的非法字符
def validateTitle(title):
rstr = r"[\/\\\:\*\?\"\<\>\|\[\]]" # '/ \ : * ? " < > |'
new_title = re.sub(rstr, "_", title) # 替换为下划线
return new_title
# 文集列表(首页)
@logger.catch()
def project_list(request):
kw = request.GET.get('kw','') # 搜索词
sort = request.GET.get('sort',0) # 排序,0表示按时间升序排序1表示按时间降序排序默认为0
role = request.GET.get('role',-1) # 筛选文集权限,默认为显示所有可显示的文集
# 是否排序
if sort in ['',0,'0']:
sort_str = ''
else:
sort_str = '-'
# 是否搜索
if kw == '':
is_kw = False
else:
is_kw = True
# 是否认证
if request.user.is_authenticated:
is_auth = True
else:
is_auth = False
# 是否筛选
if role in ['',-1,'-1']:
is_role = False
role_list = [0,3]
else:
is_role = True
# 没有搜索 and 认证用户 and 没有筛选
if (is_kw is False) and (is_auth) and (is_role is False):
colla_list = [i.project.id for i in ProjectCollaborator.objects.filter(user=request.user)] # 用户的协作文集列表
project_list = Project.objects.filter(
Q(role__in=role_list) | \
Q(role=2,role_value__contains=str(request.user.username)) | \
Q(create_user=request.user) | \
Q(id__in=colla_list)
).order_by("{}create_time".format(sort_str))
# 没有搜索 and 认证用户 and 有筛选
elif (is_kw is False ) and (is_auth) and (is_role):
if role in ['0',0]:
project_list = Project.objects.filter(role=0).order_by("{}create_time".format(sort_str))
elif role in ['1',1]:
project_list = Project.objects.filter(create_user=request.user,role=1).order_by("{}create_time".format(sort_str))
elif role in ['2',2]:
project_list = Project.objects.filter(role=2,role_value__contains=str(request.user.username)).order_by("{}create_time".format(sort_str))
elif role in ['3',3]:
project_list = Project.objects.filter(role=3).order_by("{}create_time".format(sort_str))
elif role in ['99',99]:
colla_list = [i.project.id for i in ProjectCollaborator.objects.filter(user=request.user)] # 用户的协作文集列表
project_list = Project.objects.filter(id__in=colla_list).order_by("{}create_time".format(sort_str))
else:
return render(request,'404.html')
# 没有搜索 and 游客 and 没有筛选
elif (is_kw is False) and (is_auth is False) and (is_role is False):
project_list = Project.objects.filter(role__in=[0,3]).order_by("{}create_time".format(sort_str))
# 没有搜索 and 游客 and 有筛选
elif (is_kw is False) and (is_auth is False) and (is_role):
if role in ['0',0]:
project_list = Project.objects.filter(role=0).order_by("{}create_time".format(sort_str))
elif role in ['3',3]:
project_list = Project.objects.filter(role=3).order_by("{}create_time".format(sort_str))
else:
return render(request,'404.html')
# 有搜索 and 认证用户 and 没有筛选
elif (is_kw) and (is_auth) and (is_role is False):
colla_list = [i.project.id for i in ProjectCollaborator.objects.filter(user=request.user)] # 用户的协作文集
# 查询所有可显示的文集
project_list = Project.objects.filter(
Q(role__in=[0, 3]) | \
Q(role=2, role_value__contains=str(request.user.username)) | \
Q(create_user=request.user) | \
Q(id__in=colla_list),
Q(name__icontains=kw) | Q(intro__icontains=kw)
).order_by('{}create_time'.format(sort_str))
# 有搜索 and 认证用户 and 有筛选
elif (is_kw) and (is_auth) and (is_role):
if role in ['0',0]:
project_list = Project.objects.filter(
Q(name__icontains=kw)|Q(intro__icontains=kw),
role=0
).order_by("{}create_time".format(sort_str))
elif role in ['1',1]:
project_list = Project.objects.filter(
Q(name__icontains=kw) | Q(intro__icontains=kw),
create_user=request.user
).order_by("{}create_time".format(sort_str))
elif role in ['2',2]:
project_list = Project.objects.filter(
Q(name__icontains=kw) | Q(intro__icontains=kw),
role=2,
role_value__contains=str(request.user.username)
).order_by("{}create_time".format(sort_str))
elif role in ['3',3]:
project_list = Project.objects.filter(
Q(name__icontains=kw) | Q(intro__icontains=kw),
role=3
).order_by("{}create_time".format(sort_str))
elif role in ['99',99]:
colla_list = [i.project.id for i in ProjectCollaborator.objects.filter(user=request.user)] # 用户的协作文集列表
project_list = Project.objects.filter(
Q(name__icontains=kw) | Q(intro__icontains=kw),
id__in=colla_list
).order_by("{}create_time".format(sort_str))
else:
return render(request,'404.html')
# 有搜索 and 游客 and 没有筛选
elif (is_kw) and (is_auth is False) and (is_role is False):
project_list = Project.objects.filter(
Q(name__icontains=kw) | Q(intro__icontains=kw),
role__in=[0, 3]
).order_by("{}create_time".format(sort_str))
# 有搜索 and 游客 and 有筛选
elif (is_kw) and (is_auth is False) and (is_role):
if role in ['0',0]:
project_list = Project.objects.filter(
Q(name__icontains=kw) | Q(intro__icontains=kw),
role=0
).order_by("{}create_time".format(sort_str))
elif role in ['3',3]:
project_list = Project.objects.filter(
Q(name__icontains=kw) | Q(intro__icontains=kw),
role=3
).order_by("{}create_time".format(sort_str))
else:
return render(request,'404.html')
# 分页处理
paginator = Paginator(project_list, 12)
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)
return render(request, 'app_doc/pro_list.html', locals())
# 创建文集
@login_required()
@require_http_methods(['POST'])
def create_project(request):
try:
name = request.POST.get('pname','')
name = validateTitle(name)
desc = request.POST.get('desc','')
role = request.POST.get('role',0)
role_list = ['0','1','2','3',0,1,2,3]
if name != '':
project = Project.objects.create(
name=validateTitle(name),
intro=desc[:100],
create_user=request.user,
role = int(role) if role in role_list else 0
)
project.save()
return JsonResponse({'status':True,'data':{'id':project.id,'name':project.name}})
else:
return JsonResponse({'status':False,'data':'文集名称不能为空!'})
except Exception as e:
logger.exception("创建文集出错")
return JsonResponse({'status':False,'data':'出现异常,请检查输入值!'})
# 文集页
@require_http_methods(['GET'])
@check_headers
def project_index(request,pro_id):
# 获取文集
try:
# 获取文集信息
project = Project.objects.get(id=int(pro_id))
# 获取文集的协作用户信息
if request.user.is_authenticated: # 对登陆用户查询其协作文档信息
colla_user = ProjectCollaborator.objects.filter(project=project,user=request.user).count()
else:
colla_user = 0
# 获取文集前台下载权限
try:
allow_download = ProjectReport.objects.get(project=project)
except ObjectDoesNotExist:
allow_download = False
# 私密文集并且访问者非创建者非协作者
if (project.role == 1) and (request.user != project.create_user) and (colla_user == 0):
return render(request,'404.html')
# 指定用户可见文集
elif project.role == 2:
user_list = project.role_value
if request.user.is_authenticated: # 认证用户判断是否在许可用户列表中
if (request.user.username not in user_list) and \
(request.user != project.create_user) and \
(colla_user == 0): # 访问者不在指定用户之中
return render(request, '404.html')
else:# 游客直接返回404
return render(request, '404.html')
# 访问码可见
elif project.role == 3:
# 浏览用户不为创建者、协作者
if request.user != project.create_user and colla_user == 0:
viewcode = project.role_value
viewcode_name = 'viewcode-{}'.format(project.id)
r_viewcode = request.COOKIES[viewcode_name] if viewcode_name in request.COOKIES.keys() else 0 # 从cookie中获取访问码
if viewcode != r_viewcode: # cookie中的访问码不等于文集访问码跳转到访问码认证界面
return redirect('/check_viewcode/?to={}'.format(request.path))
# 获取搜索词
kw = request.GET.get('kw','')
# 获取文集下所有一级文档
# project_docs = Doc.objects.filter(
# top_doc=int(pro_id),
# parent_doc=0,
# status=1
# ).values('id','name','top_doc').order_by('sort')
if kw != '':
search_result = Doc.objects.filter(top_doc=int(pro_id),pre_content__icontains=kw)
return render(request,'app_doc/project_doc_search.html',locals())
return render(request, 'app_doc/project.html', locals())
except Exception as e:
logger.exception("文集页访问异常")
return render(request,'404.html')
# 修改文集
@login_required()
@require_http_methods(['POST'])
def modify_project(request):
try:
pro_id = request.POST.get('pro_id',None)
project = Project.objects.get(id=pro_id)
# 验证用户有权限修改文集
if (request.user == project.create_user) or request.user.is_superuser:
name = request.POST.get('name',None)
content = request.POST.get('desc',None)
project.name = validateTitle(name)
project.intro = content
project.save()
return JsonResponse({'status':True,'data':'修改成功'})
else:
return JsonResponse({'status':False,'data':'非法请求'})
except Exception as e:
logger.exception("修改文集出错")
return JsonResponse({'status':False,'data':'请求出错'})
# 修改文集权限
@login_required()
@require_http_methods(['GET',"POST"])
@logger.catch()
def modify_project_role(request,pro_id):
try:
pro = Project.objects.get(id=pro_id)
except ObjectDoesNotExist:
return Http404
if (pro.create_user != request.user) and (request.user.is_superuser is False):
return render(request,'403.html')
else:
if request.method == 'GET':
return render(request,'app_doc/manage_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_doc/manage_project_role.html', locals())
else:
return Http404
# 验证文集访问码
@require_http_methods(['GET',"POST"])
def check_viewcode(request):
try:
if request.method == 'GET':
project_id = request.GET.get('to','').split("/")[1].split('-')[1]
project = Project.objects.get(id=int(project_id))
return render(request,'app_doc/check_viewcode.html',locals())
else:
viewcode = request.POST.get('viewcode','')
project_id = request.POST.get('project_id','')
project = Project.objects.get(id=int(project_id))
if project.role == 3 and project.role_value == viewcode:
obj = redirect("pro_index",pro_id=project_id)
obj.set_cookie('viewcode-{}'.format(project_id),viewcode)
return obj
else:
errormsg = "访问码错误"
return render(request, 'app_doc/check_viewcode.html', locals())
except Exception as e:
logger.exception("验证文集访问码出错")
return render(request,'404.html')
# 删除文集
@login_required()
@require_http_methods(["POST"])
def del_project(request):
try:
pro_id = request.POST.get('pro_id','')
if pro_id != '':
pro = Project.objects.get(id=pro_id)
if (request.user == pro.create_user) or request.user.is_superuser:
# 删除文集下的文档
pro_doc_list = Doc.objects.filter(top_doc=int(pro_id))
pro_doc_list.delete()
# 删除文集
pro.delete()
return JsonResponse({'status':True})
else:
return JsonResponse({'status':False,'data':'非法请求'})
else:
return JsonResponse({'status':False,'data':'参数错误'})
except Exception as e:
logger.exception("删除文集出错")
return JsonResponse({'status':False,'data':'请求出错'})
# 管理文集
@login_required()
@require_http_methods(['GET'])
def manage_project(request):
try:
search_kw = request.GET.get('kw', None)
if search_kw:
pro_list = Project.objects.filter(create_user=request.user,intro__icontains=search_kw).order_by('-create_time')
paginator = Paginator(pro_list, 15)
page = request.GET.get('page', 1)
try:
pros = paginator.page(page)
except PageNotAnInteger:
pros = paginator.page(1)
except EmptyPage:
pros = paginator.page(paginator.num_pages)
pros.kw = search_kw
else:
pro_list = Project.objects.filter(create_user=request.user).order_by('-create_time')
paginator = Paginator(pro_list, 15)
page = request.GET.get('page', 1)
try:
pros = paginator.page(page)
except PageNotAnInteger:
pros = paginator.page(1)
except EmptyPage:
pros = paginator.page(paginator.num_pages)
return render(request,'app_doc/manage_project.html',locals())
except Exception as e:
logger.exception("管理文集出错")
return render(request,'404.html')
# 修改文集前台下载权限
@login_required()
@require_http_methods(['GET',"POST"])
@logger.catch()
def modify_project_download(request,pro_id):
try:
pro = Project.objects.get(id=pro_id)
except ObjectDoesNotExist:
return Http404
if (pro.create_user != request.user) and (request.user.is_superuser is False):
return render(request,'403.html')
else:
project_files = ProjectReportFile.objects.filter(project=pro)
if request.method == 'GET':
return render(request,'app_doc/manage_project_download.html',locals())
elif request.method == 'POST':
download_epub = request.POST.get('download_epub',None)
download_pdf = request.POST.get('download_pdf', None)
# print("epub状态:",download_epub)
# EPUB下载权限
if download_epub == 'on':
epub_status = 1
else:
epub_status = 0
# PDF下载权限
if download_pdf == 'on':
pdf_status = 1
else:
pdf_status = 0
# 写入数据库
ProjectReport.objects.update_or_create(
project = pro,defaults={'allow_epub':epub_status}
)
ProjectReport.objects.update_or_create(
project=pro, defaults={'allow_pdf': pdf_status}
)
return render(request,'app_doc/manage_project_download.html',locals())
# 文集协作管理
@login_required()
@require_http_methods(['GET',"POST"])
@logger.catch()
def manage_project_collaborator(request,pro_id):
project = Project.objects.filter(id=pro_id, create_user=request.user)
if project.exists() is False:
return Http404
if request.method == 'GET':
pro = project[0]
collaborator = ProjectCollaborator.objects.filter(project=pro)
return render(request, 'app_doc/manage_project_collaborator.html', locals())
elif request.method == 'POST':
# type类型0表示新增协作者、1表示删除协作者、2表示修改协作者
types = request.POST.get('types','')
try:
types = int(types)
except:
return JsonResponse({'status':False,'data':'参数错误'})
# 添加文集协作者
if int(types) == 0:
colla_user = request.POST.get('username','')
role = request.POST.get('role',0)
user = User.objects.filter(username=colla_user)
if user.exists():
if user[0] == project[0].create_user: # 用户为文集的创建者
return JsonResponse({'status':False,'data':'文集创建者无需添加'})
elif ProjectCollaborator.objects.filter(user=user[0],project=project[0]).exists():
return JsonResponse({'status':False,'data':'用户已存在'})
else:
ProjectCollaborator.objects.create(
project = project[0],
user = user[0],
role = role if role in ['1',1] else 0
)
return JsonResponse({'status':True,'data':'添加成功'})
else:
return JsonResponse({'status':False,'data':'用户不存在'})
# 删除文集协作者
elif int(types) == 1:
username = request.POST.get('username','')
try:
user = User.objects.get(username=username)
pro_colla = ProjectCollaborator.objects.get(project=project[0],user=user)
pro_colla.delete()
return JsonResponse({'status':True,'data':'删除成功'})
except:
logger.exception("删除协作者出错")
return JsonResponse({'status':False,'data':'删除出错'})
# 修改协作权限
elif int(types) == 2:
username = request.POST.get('username', '')
role = request.POST.get('role','')
try:
user = User.objects.get(username=username)
pro_colla = ProjectCollaborator.objects.filter(project=project[0], user=user)
pro_colla.update(role=role)
return JsonResponse({'status':True,'data':'修改成功'})
except:
logger.exception("修改协作权限出错")
return JsonResponse({'status':False,'data':'修改失败'})
else:
return JsonResponse({'status':False,'data':'无效的类型'})
# 我协作的文集
@login_required()
@logger.catch()
def manage_pro_colla_self(request):
colla_pros = ProjectCollaborator.objects.filter(user=request.user)
return render(request,'app_doc/manage_project_self_colla.html',locals())
# 文档浏览页
@require_http_methods(['GET'])
def doc(request,pro_id,doc_id):
try:
if pro_id != '' and doc_id != '':
# 获取文集信息
project = Project.objects.get(id=int(pro_id))
# 获取文集的协作用户信息
if request.user.is_authenticated:
colla_user = ProjectCollaborator.objects.filter(project=project,user=request.user)
if colla_user.exists():
colla_user_role = colla_user[0].role
colla_user = colla_user.count()
else:
colla_user = colla_user.count()
else:
colla_user = 0
# 私密文集且访问者非创建者、协作者 - 不能访问
if (project.role == 1) and (request.user != project.create_user) and (colla_user == 0):
return render(request, '404.html')
# 指定用户可见文集
elif project.role == 2:
user_list = project.role_value
if request.user.is_authenticated: # 认证用户判断是否在许可用户列表中
if (request.user.username not in user_list) and \
(request.user != project.create_user) and \
(colla_user == 0): # 访问者不在指定用户之中,也不是协作者
return render(request, '404.html')
else: # 游客直接返回404
return render(request, '404.html')
# 访问码可见
elif project.role == 3:
# 浏览用户不为创建者和协作者 - 需要访问码
if (request.user != project.create_user) and (colla_user == 0):
viewcode = project.role_value
viewcode_name = 'viewcode-{}'.format(project.id)
r_viewcode = request.COOKIES[
viewcode_name] if viewcode_name in request.COOKIES.keys() else 0 # 从cookie中获取访问码
if viewcode != r_viewcode: # cookie中的访问码不等于文集访问码跳转到访问码认证界面
return redirect('/check_viewcode/?to={}'.format(request.path))
# 获取文档内容
try:
doc = Doc.objects.get(id=int(doc_id),status=1)
except ObjectDoesNotExist:
return render(request, '404.html')
# 获取文集下一级文档
# project_docs = Doc.objects.filter(top_doc=doc.top_doc, parent_doc=0, status=1).order_by('sort')
return render(request,'app_doc/doc.html',locals())
else:
return HttpResponse('参数错误')
except Exception as e:
logger.exception("文集浏览出错")
return render(request,'404.html')
# 创建文档
@login_required()
@require_http_methods(['GET',"POST"])
@logger.catch()
def create_doc(request):
if request.method == 'GET':
try:
pid = request.GET.get('pid',-999)
project_list = Project.objects.filter(create_user=request.user) # 自己创建的文集列表
colla_project_list = ProjectCollaborator.objects.filter(user=request.user) # 协作的文集列表
doctemp_list = DocTemp.objects.filter(create_user=request.user).values('id','name','create_time')
return render(request,'app_doc/create_doc.html',locals())
except Exception as e:
logger.exception("访问创建文档页面出错")
return render(request,'404.html')
elif request.method == 'POST':
try:
project = request.POST.get('project','')
parent_doc = request.POST.get('parent_doc','')
doc_name = request.POST.get('doc_name','')
doc_content = request.POST.get('content','')
pre_content = request.POST.get('pre_content','')
sort = request.POST.get('sort','')
status = request.POST.get('status',1)
if project != '' and doc_name != '' and project != '-1':
# 验证请求者是否有文集的权限
check_project = Project.objects.filter(id=project,create_user=request.user)
colla_project = ProjectCollaborator.objects.filter(project=project,user=request.user)
if check_project.count() > 0 or colla_project.count() > 0:
# 创建文档
doc = Doc.objects.create(
name=doc_name,
content = doc_content,
pre_content= pre_content,
parent_doc= int(parent_doc) if parent_doc != '' else 0,
top_doc= int(project),
sort = sort if sort != '' else 99,
create_user=request.user,
status = status
)
return JsonResponse({'status':True,'data':{'pro':project,'doc':doc.id}})
else:
return JsonResponse({'status':False,'data':'无权操作此文集'})
else:
return JsonResponse({'status':False,'data':'请确认文档标题、文集正确'})
except Exception as e:
logger.exception("创建文档出错")
return JsonResponse({'status':False,'data':'请求出错'})
else:
return JsonResponse({'status':False,'data':'方法不允许'})
# 修改文档
@login_required()
@require_http_methods(['GET',"POST"])
def modify_doc(request,doc_id):
if request.method == 'GET':
try:
doc = Doc.objects.get(id=doc_id) # 查询文档信息
project = Project.objects.get(id=doc.top_doc) # 查询文档所属的文集信息
pro_colla = ProjectCollaborator.objects.filter(project=project,user=request.user) # 查询用户的协作文集信息
project_list = Project.objects.filter(create_user=request.user) # 自己创建的文集列表
colla_project_list = ProjectCollaborator.objects.filter(user=request.user) # 协作的文集列表
if (request.user == doc.create_user) or (pro_colla[0].role == 1):
doc_list = Doc.objects.filter(top_doc=project.id)
doctemp_list = DocTemp.objects.filter(create_user=request.user)
history_list = DocHistory.objects.filter(doc=doc).order_by('-create_time')
return render(request,'app_doc/modify_doc.html',locals())
else:
return render(request,'403.html')
except Exception as e:
logger.exception("修改文档页面访问出错")
return render(request,'404.html')
elif request.method == 'POST':
try:
doc_id = request.POST.get('doc_id','') # 文档ID
project = request.POST.get('project', '') # 文集ID
parent_doc = request.POST.get('parent_doc', '') # 上级文档ID
doc_name = request.POST.get('doc_name', '') # 文档名称
doc_content = request.POST.get('content', '') # 文档内容
pre_content = request.POST.get('pre_content', '') # 文档Markdown格式内容
sort = request.POST.get('sort', '') # 文档排序
status = request.POST.get('status',1) # 文档状态
if doc_id != '' and project != '' and doc_name != '' and project != '-1':
doc = Doc.objects.get(id=doc_id)
pro_colla = ProjectCollaborator.objects.filter(project=project, user=request.user)
# 验证用户有权限修改文档 - 文档的创建者或文集的高级协作者
if (request.user == doc.create_user) or (pro_colla[0].role == 1):
# 将现有文档内容写入到文档历史中
DocHistory.objects.create(
doc = doc,
pre_content = doc.pre_content,
create_user = request.user
)
# 更新文档内容
Doc.objects.filter(id=int(doc_id)).update(
name=doc_name,
content=doc_content,
pre_content=pre_content,
parent_doc=int(parent_doc) if parent_doc != '' else 0,
sort=sort if sort != '' else 99,
modify_time = datetime.datetime.now(),
status = status
)
return JsonResponse({'status': True,'data':'修改成功'})
else:
return JsonResponse({'status':False,'data':'未授权请求'})
else:
return JsonResponse({'status': False,'data':'参数错误'})
except Exception as e:
logger.exception("修改文档出错")
return JsonResponse({'status':False,'data':'请求出错'})
# 删除文档 - 软删除 - 进入回收站
@login_required()
@require_http_methods(["POST"])
def del_doc(request):
try:
# 获取文档ID
doc_id = request.POST.get('doc_id',None)
if doc_id:
# 查询文档
try:
doc = Doc.objects.get(id=doc_id)
project = Project.objects.get(id=doc.top_doc) # 查询文档所属的文集
# 获取文档所属文集的协作信息
pro_colla = ProjectCollaborator.objects.filter(project=project,user=request.user) #
if pro_colla.exists():
colla_user_role = pro_colla[0].role
else:
colla_user_role = 0
except ObjectDoesNotExist:
return JsonResponse({'status': False, 'data': '文档不存在'})
# 如果请求用户为文档创建者、高级权限的协作者、文集的创建者,可以删除
if (request.user == doc.create_user) or (colla_user_role == 1) or (request.user == project.create_user):
# 修改状态为删除
doc.status = 3
doc.modify_time = datetime.datetime.now()
doc.save()
# 修改其下级所有文档状态为删除
chr_doc = Doc.objects.filter(parent_doc=doc_id) # 获取下级文档
chr_doc_ids = chr_doc.values_list('id',flat=True) # 提取下级文档的ID
chr_doc.update(status=3,modify_time=datetime.datetime.now()) # 修改下级文档的状态为删除
Doc.objects.filter(parent_doc__in=chr_doc_ids).update(status=3,modify_time=datetime.datetime.now()) # 修改下级文档的下级文档状态
return JsonResponse({'status': True, 'data': '删除完成'})
else:
return JsonResponse({'status': False, 'data': '非法请求'})
else:
return JsonResponse({'status':False,'data':'参数错误'})
except Exception as e:
logger.exception("删除文档出错")
return JsonResponse({'status':False,'data':'请求出错'})
# 管理文档
@login_required()
@require_http_methods(['GET'])
@logger.catch()
def manage_doc(request):
# 文档内容搜索参数
search_kw = request.GET.get('kw','')
# 文档状态筛选参数
doc_status = request.GET.get('status', 'all')
# 文档文集筛选参数
doc_pro_id = request.GET.get('pid','')
is_search = True if search_kw != '' else False
is_status = doc_status
is_project = True if doc_pro_id != '' else False
# 无搜索 - 无状态 - 无文集
if (is_search is False) and (is_status == 'all') and (is_project is False):
doc_list = Doc.objects.filter(create_user=request.user,status__in=[0,1]).order_by('-modify_time')
# 无搜索 - 无状态 - 有文集
elif (is_search is False) and (is_status == 'all') and (is_project):
doc_list = Doc.objects.filter(
create_user=request.user,
top_doc=int(doc_pro_id),
status__in=[0,1]
).order_by('-modify_time')
# 无搜索 - 有状态 - 无文集
elif (is_search is False) and (is_status != 'all') and (is_project is False):
# 返回已发布文档
if doc_status == 'published':
doc_list = Doc.objects.filter(create_user=request.user, status=1).order_by('-modify_time')
# 返回草稿文档
elif doc_status == 'draft':
doc_list = Doc.objects.filter(create_user=request.user, status=0).order_by('-modify_time')
else:
doc_list = Doc.objects.filter(create_user=request.user, status__in=[0,1]).order_by('-modify_time')
# 无搜索 - 有状态 - 有文集
elif (is_search is False) and (is_status != 'all') and (is_project):
# 返回已发布文档
if doc_status == 'published':
doc_list = Doc.objects.filter(
create_user=request.user,
status=1,
top_doc=int(doc_pro_id)
).order_by('-modify_time')
# 返回草稿文档
elif doc_status == 'draft':
doc_list = Doc.objects.filter(
create_user=request.user,
status=0,
top_doc = int(doc_pro_id)
).order_by('-modify_time')
else:
doc_list = Doc.objects.filter(
create_user=request.user,
top_doc=int(doc_pro_id),
status__in=[0,1]
).order_by('-modify_time')
# 有搜索 - 无状态 - 无文集
elif (is_search) and (is_status == 'all') and (is_project is False):
doc_list = Doc.objects.filter(
Q(content__icontains=search_kw) | Q(name__icontains=search_kw), # 文本或文档标题包含搜索词
create_user=request.user,
status__in=[0,1]
).order_by('-modify_time')
# 有搜索 - 无状态 - 有文集
elif (is_search) and (is_status == 'all') and (is_project):
doc_list = Doc.objects.filter(
Q(content__icontains=search_kw) | Q(name__icontains=search_kw), # 文本或文档标题包含搜索词
create_user=request.user,top_doc=int(doc_pro_id),status__in=[0,1]
).order_by('-modify_time')
# 有搜索 - 有状态 - 无文集
elif (is_search) and (is_status != 'all') and (is_project is False):
if doc_status == 'published':
doc_list = Doc.objects.filter(
Q(content__icontains=search_kw) | Q(name__icontains=search_kw),
create_user=request.user,
status = 1
).order_by('-modify_time')
elif doc_status == 'draft':
doc_list = Doc.objects.filter(
Q(content__icontains=search_kw) | Q(name__icontains=search_kw), # 文本或文档标题包含搜索词
create_user=request.user,
status = 0
).order_by('-modify_time')
else:
doc_list = Doc.objects.filter(
Q(content__icontains=search_kw) | Q(name__icontains=search_kw), # 文本或文档标题包含搜索词
create_user=request.user,status__in=[0,1]
).order_by('-modify_time')
# 有搜索 - 有状态 - 有文集
elif (is_search) and (is_status != 'all') and (is_project):
if doc_status == 'published':
doc_list = Doc.objects.filter(
Q(content__icontains=search_kw) | Q(name__icontains=search_kw),
create_user=request.user,
status = 1,
top_doc=int(doc_pro_id)
).order_by('-modify_time')
elif doc_status == 'draft':
doc_list = Doc.objects.filter(
Q(content__icontains=search_kw) | Q(name__icontains=search_kw), # 文本或文档标题包含搜索词
create_user=request.user,
status = 0,
top_doc=int(doc_pro_id)
).order_by('-modify_time')
else:
doc_list = Doc.objects.filter(
Q(content__icontains=search_kw) | Q(name__icontains=search_kw), # 文本或文档标题包含搜索词
create_user=request.user,
top_doc=int(doc_pro_id),status__in=[0,1]
).order_by('-modify_time')
# 文集列表
project_list = Project.objects.filter(create_user=request.user) # 自己创建的文集列表
colla_project_list = ProjectCollaborator.objects.filter(user=request.user) # 协作的文集列表
# 文档数量
# 已发布文档数量
published_doc_cnt = Doc.objects.filter(create_user=request.user, status=1).count()
# 草稿文档数量
draft_doc_cnt = Doc.objects.filter(create_user=request.user, status=0).count()
# 所有文档数量
all_cnt = published_doc_cnt + draft_doc_cnt
# 分页处理
paginator = Paginator(doc_list, 15)
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.status = doc_status
docs.pid = doc_pro_id
docs.kw = search_kw
return render(request,'app_doc/manage_doc.html',locals())
# 移动文档
@login_required()
@require_http_methods(['POST'])
def move_doc(request):
doc_id = request.POST.get('doc_id','') # 文档ID
pro_id = request.POST.get('pro_id','') # 移动的文集ID
move_type = request.POST.get('move_type','') # 移动的类型 0复制 1移动 2连同下级文档移动
parent_id = request.POST.get('parent_id',0)
# 判断文集是否存在且有权限
try:
project = Project.objects.get(id=int(pro_id)) # 自己的文集
colla = ProjectCollaborator.objects.filter(project=project, user=request.user) # 协作文集
if (project.create_user is not request.user) and (colla.count()): # 请求者不是文集创建者和协作者返回错误
return JsonResponse({'status':False,'data':'文集无权限'})
except ObjectDoesNotExist:
return JsonResponse({'status':False,'data':'文集不存在'})
# 判断文档是否存在
try:
doc = Doc.objects.get(id=int(doc_id),create_user=request.user)
except ObjectDoesNotExist:
return JsonResponse({'status':False,'data':'文档不存在'})
# 判断上级文档是否存在
try:
if parent_id != '0':
parent = Doc.objects.get(id=int(parent_id),create_user=request.user)
except ObjectDoesNotExist:
return JsonResponse({'status':False,'data':'上级文档不存在'})
# 复制文档
if move_type == '0':
copy_doc = Doc.objects.create(
name = doc.name,
pre_content = doc.pre_content,
content = doc.content,
parent_doc = parent_id,
top_doc = int(pro_id),
create_user = request.user,
create_time = datetime.datetime.now(),
modify_time = datetime.datetime.now(),
# 文档状态说明0表示草稿状态1表示发布状态
status = doc.status
)
return JsonResponse({'status':True,'data':{'pro_id':pro_id,'doc_id':copy_doc.id}})
# 移动文档,下级文档更改到根目录
elif move_type == '1':
try:
# 修改文档的所属文集和上级文档实现移动文档
Doc.objects.filter(id=int(doc_id)).update(parent_doc=int(parent_id),top_doc=int(pro_id))
# 修改其子文档为顶级文档
Doc.objects.filter(parent_doc=doc_id).update(parent_doc=0)
return JsonResponse({'status':True,'data':{'pro_id':pro_id,'doc_id':doc_id}})
except:
logger.exception("移动文档异常")
return JsonResponse({'status':False,'data':'移动文档失败'})
# 包含下级文档一起移动
elif move_type == '2':
try:
# 修改文档的所属文集和上级文档实现移动文档
Doc.objects.filter(id=int(doc_id)).update(parent_doc=int(parent_id), top_doc=int(pro_id))
# 修改其子文档的文集归属
child_doc = Doc.objects.filter(parent_doc=doc_id)
child_doc.update(top_doc=int(pro_id))
# 遍历子文档,如果其存在下级文档,那么继续修改所属文集
for child in child_doc:
Doc.objects.filter(parent_doc=child.id).update(top_doc=int(pro_id))
return JsonResponse({'status': True, 'data':{'pro_id':pro_id,'doc_id':doc_id}})
except:
logger.exception("移动包含下级的文档异常")
return JsonResponse({'status': False, 'data': '移动文档失败'})
else:
return JsonResponse({'status':False,'data':'移动类型错误'})
# 查看对比文档历史版本
@login_required()
@require_http_methods(['GET',"POST"])
def diff_doc(request,doc_id,his_id):
if request.method == 'GET':
try:
doc = Doc.objects.get(id=doc_id) # 查询文档信息
project = Project.objects.get(id=doc.top_doc) # 查询文档所属的文集信息
pro_colla = ProjectCollaborator.objects.filter(project=project, user=request.user) # 查询用户的协作文集信息
if (request.user == doc.create_user) or (pro_colla[0].role == 1):
history = DocHistory.objects.get(id=his_id)
history_list = DocHistory.objects.filter(doc=doc).order_by('-create_time')
if history.doc == doc:
return render(request, 'app_doc/diff_doc.html', locals())
else:
return render(request, '403.html')
else:
return render(request, '403.html')
except Exception as e:
logger.exception("文档历史版本页面访问出错")
return render(request, '404.html')
elif request.method == 'POST':
try:
doc = Doc.objects.get(id=doc_id) # 查询文档信息
project = Project.objects.get(id=doc.top_doc) # 查询文档所属的文集信息
pro_colla = ProjectCollaborator.objects.filter(project=project, user=request.user) # 查询用户的协作文集信息
if (request.user == doc.create_user) or (pro_colla[0].role == 1):
history = DocHistory.objects.get(id=his_id)
if history.doc == doc:
return JsonResponse({'status':True,'data':history.pre_content})
else:
return JsonResponse({'status': False, 'data': '非法请求'})
else:
return JsonResponse({'status':False,'data':'非法请求'})
except Exception as e:
logger.exception("文档历史版本获取出错")
return JsonResponse({'status':False,'data':'获取异常'})
# 管理文档历史版本
@login_required()
@require_http_methods(['GET',"POST"])
def manage_doc_history(request,doc_id):
if request.method == 'GET':
try:
doc = Doc.objects.get(id=doc_id,create_user=request.user)
history_list = DocHistory.objects.filter(create_user=request.user,doc=doc_id).order_by('-create_time')
paginator = Paginator(history_list, 15)
page = request.GET.get('page', 1)
try:
historys = paginator.page(page)
except PageNotAnInteger:
historys = paginator.page(1)
except EmptyPage:
historys = paginator.page(paginator.num_pages)
return render(request, 'app_doc/manage_doc_history.html', locals())
except Exception as e:
logger.exception("管理文档历史版本页面访问出错")
return render(request, '404.html')
elif request.method == 'POST':
try:
history_id = request.POST.get('history_id','')
DocHistory.objects.filter(id=history_id,doc=doc_id,create_user=request.user).delete()
return JsonResponse({'status':True,'data':'删除成功'})
except:
logger.exception("操作文档历史版本出错")
return JsonResponse({'status':False,'data':'出现异常'})
# 文档回收站
@login_required()
@require_http_methods(['GET','POST'])
def doc_recycle(request):
if request.method == 'GET':
# 获取状态为删除的文档
doc_list = Doc.objects.filter(status=3,create_user=request.user).order_by('-modify_time')
# 分页处理
paginator = Paginator(doc_list, 15)
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)
return render(request,'app_doc/manage_doc_recycle.html',locals())
elif request.method == 'POST':
try:
# 获取参数
doc_id = request.POST.get('doc_id', None) # 文档ID
types = request.POST.get('type',None) # 操作类型
if doc_id:
# 查询文档
try:
doc = Doc.objects.get(id=doc_id)
project = Project.objects.get(id=doc.top_doc) # 查询文档所属的文集
# 获取文档所属文集的协作信息
pro_colla = ProjectCollaborator.objects.filter(project=project, user=request.user) #
if pro_colla.exists():
colla_user_role = pro_colla[0].role
else:
colla_user_role = 0
except ObjectDoesNotExist:
return JsonResponse({'status': False, 'data': '文档不存在'})
# 如果请求用户为文档创建者、高级权限的协作者、文集的创建者,可以操作
if (request.user == doc.create_user) or (colla_user_role == 1) or (request.user == project.create_user):
# 还原文档
if types == 'restore':
# 修改状态为草稿
doc.status = 0
doc.modify_time = datetime.datetime.now()
doc.save()
# 删除文档
elif types == 'del':
# 删除文档
doc.delete()
else:
return JsonResponse({'status':False,'data':'无效请求'})
return JsonResponse({'status': True, 'data': '删除完成'})
else:
return JsonResponse({'status': False, 'data': '非法请求'})
# 清空回收站
elif types == 'empty':
docs = Doc.objects.filter(status=3,create_user=request.user)
docs.delete()
return JsonResponse({'status': True, 'data': '清空成功'})
# 还原回收站
elif types == 'restoreAll':
Doc.objects.filter(status=3,create_user=request.user).update(status=0)
return JsonResponse({'status': True, 'data': '还原成功'})
else:
return JsonResponse({'status': False, 'data': '参数错误'})
except Exception as e:
logger.exception("处理文档出错")
return JsonResponse({'status': False, 'data': '请求出错'})
# 一键发布文档
@login_required()
@require_http_methods(['POST'])
def fast_publish_doc(request):
doc_id = request.POST.get('doc_id',None)
# 查询文档
try:
doc = Doc.objects.get(id=doc_id)
project = Project.objects.get(id=doc.top_doc) # 查询文档所属的文集
# 获取文档所属文集的协作信息
pro_colla = ProjectCollaborator.objects.filter(project=project, user=request.user) #
if pro_colla.exists():
colla_user_role = pro_colla[0].role
else:
colla_user_role = 0
except ObjectDoesNotExist:
return JsonResponse({'status': False, 'data': '文档不存在'})
# 判断请求者是否有权限(文档创建者、文集创建者、文集高级协作者)
# 如果请求用户为文档创建者、高级权限的协作者、文集的创建者,可以删除
if (request.user == doc.create_user) or (colla_user_role == 1) or (request.user == project.create_user):
try:
doc.status = 1
doc.modify_time = datetime.datetime.now()
doc.save()
return JsonResponse({'status':True,'data':'发布成功'})
except:
logger.exception("文档一键发布失败")
return JsonResponse({'status':False,'data':'发布失败'})
else:
return JsonResponse({'status':False,'data':'非法请求'})
# 创建文档模板
@login_required()
@require_http_methods(['GET',"POST"])
def create_doctemp(request):
if request.method == 'GET':
doctemps = DocTemp.objects.filter(create_user=request.user)
return render(request,'app_doc/create_doctemp.html',locals())
elif request.method == 'POST':
try:
name = request.POST.get('name','')
content = request.POST.get('content','')
if name != '':
doctemp = DocTemp.objects.create(
name = name,
content = content,
create_user=request.user
)
doctemp.save()
return JsonResponse({'status':True,'data':'创建成功'})
else:
return JsonResponse({'status':False,'data':'模板标题不能为空'})
except Exception as e:
logger.exception("创建文档模板出错")
return JsonResponse({'status':False,'data':'请求出错'})
# 修改文档模板
@login_required()
@require_http_methods(['GET',"POST"])
def modify_doctemp(request,doctemp_id):
if request.method == 'GET':
try:
doctemp = DocTemp.objects.get(id=doctemp_id)
if request.user.id == doctemp.create_user.id:
doctemps = DocTemp.objects.filter(create_user=request.user)
return render(request,'app_doc/modify_doctemp.html',locals())
else:
return HttpResponse('非法请求')
except Exception as e:
logger.exception("访问文档模板修改页面出错")
return render(request, '404.html')
elif request.method == 'POST':
try:
doctemp_id = request.POST.get('doctemp_id','')
name = request.POST.get('name','')
content = request.POST.get('content','')
if doctemp_id != '' and name !='':
doctemp = DocTemp.objects.get(id=doctemp_id)
if request.user.id == doctemp.create_user.id:
doctemp.name = name
doctemp.content = content
doctemp.save()
return JsonResponse({'status':True,'data':'修改成功'})
else:
return JsonResponse({'status':False,'data':'非法操作'})
else:
return JsonResponse({'status':False,'data':'参数错误'})
except Exception as e:
logger.exception("修改文档模板出错")
return JsonResponse({'status':False,'data':'请求出错'})
# 删除文档模板
@login_required()
def del_doctemp(request):
try:
doctemp_id = request.POST.get('doctemp_id','')
if doctemp_id != '':
doctemp = DocTemp.objects.get(id=doctemp_id)
if request.user.id == doctemp.create_user.id:
doctemp.delete()
return JsonResponse({'status':True,'data':'删除完成'})
else:
return JsonResponse({'status':False,'data':'非法请求'})
else:
return JsonResponse({'status': False, 'data': '参数错误'})
except Exception as e:
logger.exception("删除文档模板出错")
return JsonResponse({'status':False,'data':'请求出错'})
# 管理文档模板
@login_required()
@require_http_methods(['GET'])
def manage_doctemp(request):
try:
search_kw = request.GET.get('kw', None)
if search_kw:
doctemp_list = DocTemp.objects.filter(
create_user=request.user,
content__icontains=search_kw
).order_by('-modify_time')
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 = search_kw
else:
doctemp_list = DocTemp.objects.filter(create_user=request.user).order_by('-modify_time')
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)
return render(request, 'app_doc/manage_doctemp.html', locals())
except Exception as e:
logger.exception("管理文档模板页面访问出错")
return render(request, '404.html')
# 获取指定文档模板
@login_required()
@require_http_methods(["POST"])
def get_doctemp(request):
try:
doctemp_id = request.POST.get('doctemp_id','')
if doctemp_id != '':
content = DocTemp.objects.get(id=int(doctemp_id)).serializable_value('content')
return JsonResponse({'status':True,'data':content})
else:
return JsonResponse({'status':False,'data':'参数错误'})
except Exception as e:
logger.exception("获取指定文档模板出错")
return JsonResponse({'status':False,'data':'请求出错'})
# 获取指定文集的所有文档
@require_http_methods(["POST"])
@logger.catch()
def get_pro_doc(request):
pro_id = request.POST.get('pro_id','')
if pro_id != '':
# 获取文集所有文档的id、name和parent_doc3个字段
doc_list = Doc.objects.filter(top_doc=int(pro_id),status=1).values_list('id','name','parent_doc').order_by('parent_doc')
item_list = []
# 遍历文档
for doc in doc_list:
# 如果文档为顶级文档
if doc[2] == 0:
# 将其数据添加到列表中
item = [
doc[0],doc[1],doc[2],''
]
item_list.append(item)
# 如果文档不是顶级文档
else:
# 查询文档的上级文档
try:
parent = Doc.objects.get(id=doc[2])
except ObjectDoesNotExist:
return JsonResponse({'status':False,'data':'文档id不存在'})
# 如果文档上级文档的上级是顶级文档,那么将其添加到列表
if parent.parent_doc == 0: # 只要二级目录
item = [
doc[0],doc[1],doc[2],parent.name+' --> '
]
item_list.append(item)
return JsonResponse({'status':True,'data':list(item_list)})
else:
return JsonResponse({'status':False,'data':'参数错误'})
# 获取指定文集的文档树数据
# @login_required()
@require_http_methods(['POST'])
@logger.catch()
def get_pro_doc_tree(request):
pro_id = request.POST.get('pro_id', None)
if pro_id:
# 查询存在上级文档的文档
parent_id_list = Doc.objects.filter(top_doc=pro_id,status=1).exclude(parent_doc=0).values_list('parent_doc',flat=True)
# 获取存在上级文档的上级文档ID
# print(parent_id_list)
doc_list = []
# 获取一级文档
top_docs = Doc.objects.filter(top_doc=pro_id,parent_doc=0,status=1).values('id','name').order_by('sort')
# 遍历一级文档
for doc in top_docs:
top_item = {
'id':doc['id'],
'field':doc['name'],
'title':doc['name'],
'spread':True,
'level':1
}
# 如果一级文档存在下级文档,查询其二级文档
if doc['id'] in parent_id_list:
# 获取二级文档
sec_docs = Doc.objects.filter(top_doc=pro_id,parent_doc=doc['id'],status=1).values('id','name').order_by('sort')
top_item['children'] = []
for doc in sec_docs:
sec_item = {
'id': doc['id'],
'field': doc['name'],
'title': doc['name'],
'level':2
}
# 如果二级文档存在下级文档,查询第三级文档
if doc['id'] in parent_id_list:
# 获取三级文档
thr_docs = Doc.objects.filter(top_doc=pro_id,parent_doc=doc['id'],status=1).values('id','name').order_by('sort')
sec_item['children'] = []
for doc in thr_docs:
item = {
'id': doc['id'],
'field': doc['name'],
'title': doc['name'],
'level': 3
}
sec_item['children'].append(item)
top_item['children'].append(sec_item)
else:
top_item['children'].append(sec_item)
doc_list.append(top_item)
# 如果一级文档没有下级文档,直接保存
else:
doc_list.append(top_item)
return JsonResponse({'status':True,'data':doc_list})
else:
return JsonResponse({'status':False,'data':'参数错误'})
# 404页面
def handle_404(request):
return render(request,'404.html')
# 导出文集MD文件
@login_required()
@require_http_methods(["POST"])
def report_md(request):
pro_id = request.POST.get('project_id','')
user = request.user
try:
project = Project.objects.get(id=int(pro_id))
if project.create_user == user:
project_md = ReportMD(
project_id=int(pro_id)
)
md_file_path = project_md.work() # 生成并获取MD文件压缩包绝对路径
md_file_filename = os.path.split(md_file_path)[-1] # 提取文件名
md_file = "/media/reportmd_temp/"+ md_file_filename # 拼接相对链接
return JsonResponse({'status':True,'data':md_file})
else:
return JsonResponse({'status':False,'data':'无权限'})
except Exception as e:
logger.exception("导出文集MD文件出错")
return JsonResponse({'status':False,'data':'文集不存在'})
# 生成文集文件 - 个人中心 - 文集管理
@login_required()
@require_http_methods(["POST"])
def genera_project_file(request):
report_type = request.POST.get('types',None) # 获取前端传入到导出文件类型参数
# 导出EPUB文件
pro_id = request.POST.get('pro_id')
try:
project = Project.objects.get(id=int(pro_id))
# 获取文集的协作用户信息
if request.user.is_authenticated:
colla_user = ProjectCollaborator.objects.filter(project=project, user=request.user)
if colla_user.exists():
colla_user_role = colla_user[0].role
colla_user = colla_user.count()
else:
colla_user = colla_user.count()
else:
colla_user = 0
# 公开的文集 - 可以直接导出
if project.role == 0:
allow_export = True
# 私密文集 - 非创建者和协作者不可导出
elif (project.role == 1):
if (request.user != project.create_user) and (colla_user == 0):
allow_export = False
else:
allow_export = True
# 指定用户可见文集 - 指定用户、文集创建者和协作者可导出
elif project.role == 2:
user_list = project.role_value
if request.user.is_authenticated: # 认证用户判断是否在许可用户列表中
if (request.user.username not in user_list) and \
(request.user != project.create_user) and \
(colla_user == 0): # 访问者不在指定用户之中,也不是协作者
allow_export = False
else:
allow_export = True
else: # 游客直接返回404
allow_export = False
# 访问码可见文集 - 文集创建者、协作者和通过验证即可导出
elif project.role == 3:
# 浏览用户不为创建者和协作者 - 需要访问码
if (request.user != project.create_user) and (colla_user == 0):
viewcode = project.role_value
viewcode_name = 'viewcode-{}'.format(project.id)
r_viewcode = request.COOKIES[
viewcode_name] if viewcode_name in request.COOKIES.keys() else 0 # 从cookie中获取访问码
if viewcode != r_viewcode: # cookie中的访问码不等于文集访问码不可导出
allow_export = False
else:
allow_export = True
else:
allow_export = True
else:
allow_export = False
# 允许被导出
if allow_export:
# 导出EPUB
if report_type in ['epub']:
try:
report_project = ReportEPUB(
project_id=project.id
).work()
# print(report_project)
report_file_path = report_project.split('media', maxsplit=1)[-1] # 导出文件的路径
epub_file = '/media' + report_file_path + '.epub' # 文件相对路径
# 查询文集是否存在导出文件
report_cnt = ProjectReportFile.objects.filter(project=project,file_type='epub')
# 存在文件删除
if report_cnt.count() != 0:
for r in report_cnt:
is_exist = os.path.exists(settings.BASE_DIR + r.file_path)
if is_exist:
os.remove(settings.BASE_DIR + r.file_path)
report_cnt.delete() # 删除数据库记录
# 创建数据库记录
ProjectReportFile.objects.create(
project=project,
file_type='epub',
file_name=epub_file,
file_path=epub_file
)
return JsonResponse({'status': True, 'data': epub_file})
except Exception as e:
logger.exception("生成EPUB出错")
return JsonResponse({'status': False, 'data': '生成出错'})
# 导出PDF
elif report_type in ['pdf']:
try:
report_project = ReportPDF(
project_id=project.id
).work()
if report_project is False:
return JsonResponse({'status':False,'data':'生成出错'})
report_file_path = report_project.split('media', maxsplit=1)[-1] # 导出文件的路径
pdf_file = '/media' + report_file_path # 文件相对路径
# 查询文集是否存在导出文件
report_cnt = ProjectReportFile.objects.filter(project=project, file_type='pdf')
# 存在文件删除
if report_cnt.count() != 0:
for r in report_cnt:
is_exist = os.path.exists(settings.BASE_DIR + r.file_path)
if is_exist:
os.remove(settings.BASE_DIR + r.file_path)
report_cnt.delete() # 删除数据库记录
# 创建数据库记录
ProjectReportFile.objects.create(
project=project,
file_type='pdf',
file_name=pdf_file,
file_path=pdf_file
)
return JsonResponse({'status': True, 'data': pdf_file})
except Exception as e:
return JsonResponse({'status': False, 'data': '生成出错'})
else:
return JsonResponse({'status': False, 'data': '不支持的类型'})
# 不允许被导出
else:
return JsonResponse({'status':False,'data':'无权限导出'})
except ObjectDoesNotExist:
return JsonResponse({'status':False,'data':'文集不存在'})
except Exception as e:
logger.exception("生成文集文件出错")
return JsonResponse({'status':False,'data':'系统异常'})
# 获取文集前台导出文件
@allow_report_file
@require_http_methods(["POST"])
def report_file(request):
report_type = request.POST.get('types',None) # 获取前端传入到导出文件类型参数
pro_id = request.POST.get('pro_id')
try:
project = Project.objects.get(id=int(pro_id))
# 获取文集的协作用户信息
if request.user.is_authenticated:
colla_user = ProjectCollaborator.objects.filter(project=project, user=request.user)
if colla_user.exists():
colla_user_role = colla_user[0].role
colla_user = colla_user.count()
else:
colla_user = colla_user.count()
else:
colla_user = 0
# 公开的文集 - 可以直接导出
if project.role == 0:
allow_export = True
# 私密文集 - 非创建者和协作者不可导出
elif (project.role == 1):
if (request.user != project.create_user) and (colla_user == 0):
allow_export = False
else:
allow_export = True
# 指定用户可见文集 - 指定用户、文集创建者和协作者可导出
elif project.role == 2:
user_list = project.role_value
if request.user.is_authenticated: # 认证用户判断是否在许可用户列表中
if (request.user.username not in user_list) and \
(request.user != project.create_user) and \
(colla_user == 0): # 访问者不在指定用户之中,也不是协作者
allow_export = False
else:
allow_export = True
else: # 游客直接返回404
allow_export = False
# 访问码可见文集 - 文集创建者、协作者和通过验证即可导出
elif project.role == 3:
# 浏览用户不为创建者和协作者 - 需要访问码
if (request.user != project.create_user) and (colla_user == 0):
viewcode = project.role_value
viewcode_name = 'viewcode-{}'.format(project.id)
r_viewcode = request.COOKIES[
viewcode_name] if viewcode_name in request.COOKIES.keys() else 0 # 从cookie中获取访问码
if viewcode != r_viewcode: # cookie中的访问码不等于文集访问码不可导出
allow_export = False
else:
allow_export = True
else:
allow_export = True
else:
allow_export = False
# return JsonResponse({'status':False,'data':'不存在的文集权限'})
if allow_export:
# 导出EPUB文件
if report_type in ['epub']:
try:
try:
report_project = ProjectReportFile.objects.get(project=project,file_type='epub')
except ObjectDoesNotExist:
return JsonResponse({'status':False,'data':'无可用文件,请联系文集创建者'})
# print(report_project)
return JsonResponse({'status': True, 'data': report_project.file_path})
except Exception as e:
return JsonResponse({'status': False, 'data': '导出出错'})
# 导出PDF
elif report_type in ['pdf']:
try:
try:
report_project = ProjectReportFile.objects.get(project=project,file_type='pdf')
except ObjectDoesNotExist:
return JsonResponse({'status':False,'data':'无可用文件,请联系文集创建者'})
# print(report_project)
return JsonResponse({'status': True, 'data': report_project.file_path})
except Exception as e:
return JsonResponse({'status': False, 'data': '导出出错'})
else:
return JsonResponse({'status': False, 'data': '不支持的类型'})
else:
return JsonResponse({'status':False,'data':'无权限导出'})
except ObjectDoesNotExist:
return JsonResponse({'status':False,'data':'文集不存在'})
except Exception as e:
logger.exception("获取文集前台导出文件出错")
return JsonResponse({'status':False,'data':'系统异常'})
# 图片素材管理
@login_required()
@require_http_methods(['GET',"POST"])
def manage_image(request):
# 获取图片
if request.method == 'GET':
try:
groups = ImageGroup.objects.filter(user=request.user) # 获取所有分组
all_img_cnt = Image.objects.filter(user=request.user).count()
no_group_cnt = Image.objects.filter(user=request.user,group_id=None).count() # 获取所有未分组的图片数量
g_id = int(request.GET.get('group', 0)) # 图片分组id
if int(g_id) == 0:
image_list = Image.objects.filter(user=request.user).order_by('-create_time') # 查询所有图片
elif int(g_id) == -1:
image_list = Image.objects.filter(user=request.user,group_id=None).order_by('-create_time') # 查询指定分组的图片
else:
image_list = Image.objects.filter(user=request.user,group_id=g_id).order_by('-create_time') # 查询指定分组的图片
paginator = Paginator(image_list, 18)
page = request.GET.get('page', 1)
try:
images = paginator.page(page)
except PageNotAnInteger:
images = paginator.page(1)
except EmptyPage:
images = paginator.page(paginator.num_pages)
images.group = g_id
return render(request,'app_doc/manage_image.html',locals())
except:
logger.exception("图片素材管理出错")
return render(request,'404.html')
elif request.method == 'POST':
try:
img_id = request.POST.get('img_id','')
types = request.POST.get('types','') # 操作类型0表示删除1表示修改2表示获取
# 删除图片
if int(types) == 0:
img = Image.objects.get(id=img_id)
if img.user != request.user:
return JsonResponse({'status': False, 'data': '未授权请求'})
file_path = settings.BASE_DIR+img.file_path
is_exist = os.path.exists(file_path)
if is_exist:
os.remove(file_path)
img.delete() # 删除记录
return JsonResponse({'status':True,'data':'删除完成'})
# 移动图片分组
elif int(types) == 1:
group_id = request.POST.get('group_id',None)
if group_id is None:
Image.objects.filter(id=img_id,user=request.user).update(group_id=None)
else:
group = ImageGroup.objects.get(id=group_id,user=request.user)
Image.objects.filter(id=img_id,user=request.user).update(group_id=group)
return JsonResponse({'status':True,'data':'移动完成'})
# 获取图片
elif int(types) == 2:
group_id = request.POST.get('group_id', None) # 接受分组ID参数
if group_id is None: #
return JsonResponse({'status':False,'data':'参数错误'})
elif int(group_id) == 0:
imgs = Image.objects.filter(user=request.user).order_by('-create_time')
elif int(group_id) == -1:
imgs = Image.objects.filter(user=request.user,group_id=None).order_by('-create_time')
else:
imgs = Image.objects.filter(user=request.user,group_id=group_id).order_by('-create_time')
img_list = []
for img in imgs:
item = {
'path':img.file_path,
'name':img.file_name,
}
img_list.append(item)
return JsonResponse({'status':True,'data':img_list})
else:
return JsonResponse({'status':False,'data':'非法参数'})
except ObjectDoesNotExist:
return JsonResponse({'status':False,'data':'图片不存在'})
except:
logger.exception("操作图片素材出错")
return JsonResponse({'status':False,'data':'程序异常'})
# 图片分组管理
@login_required()
@require_http_methods(['GET',"POST"])
@logger.catch()
def manage_img_group(request):
if request.method == 'GET':
groups = ImageGroup.objects.filter(user=request.user)
return render(request,'app_doc/manage_image_group.html',locals())
# 操作分组
elif request.method == 'POST':
types = request.POST.get('types',None) # 请求类型0表示创建分组1表示修改分组2表示删除分组3表示获取分组
# 创建分组
if int(types) == 0:
group_name = request.POST.get('group_name', '')
if group_name not in ['','默认分组','未分组']:
ImageGroup.objects.create(
user = request.user,
group_name = group_name
)
return JsonResponse({'status':True,'data':'ok'})
else:
return JsonResponse({'status':False,'data':'名称无效'})
# 修改分组
elif int(types) == 1:
group_name = request.POST.get("group_name",'')
if group_name not in ['','默认分组','未分组']:
group_id = request.POST.get('group_id', '')
ImageGroup.objects.filter(id=group_id,user=request.user).update(group_name=group_name)
return JsonResponse({'status':True,'data':'修改成功'})
else:
return JsonResponse({'status':False,'data':'名称无效'})
# 删除分组
elif int(types) == 2:
try:
group_id = request.POST.get('group_id','')
group = ImageGroup.objects.get(id=group_id,user=request.user) # 查询分组
images = Image.objects.filter(group_id=group_id,user=request.user).update(group_id=None) # 移动图片到未分组
group.delete() # 删除分组
return JsonResponse({'status':True,'data':'删除完成'})
except:
logger.exception("删除图片分组出错")
return JsonResponse({'status':False,'data':'删除错误'})
# 获取分组
elif int(types) == 3:
try:
group_list = []
all_cnt = Image.objects.filter(user=request.user).count()
non_group_cnt = Image.objects.filter(group_id=None,user=request.user).count()
group_list.append({'group_name':'全部图片','group_cnt':all_cnt,'group_id':0})
group_list.append({'group_name':'未分组','group_cnt':non_group_cnt,'group_id':-1})
groups = ImageGroup.objects.filter(user=request.user) # 查询所有分组
for group in groups:
group_cnt = Image.objects.filter(group_id=group).count()
item = {
'group_id':group.id,
'group_name':group.group_name,
'group_cnt':group_cnt
}
group_list.append(item)
return JsonResponse({'status':True,'data':group_list})
except:
logger.exception("获取图片分组出错")
return JsonResponse({'status':False,'data':'出现错误'})
# 附件管理
@login_required()
@require_http_methods(['GET',"POST"])
def manage_attachment(request):
# 文件大小 字节转换
def sizeFormat(size, is_disk=False, precision=2):
'''
size format for human.
byte ---- (B)
kilobyte ---- (KB)
megabyte ---- (MB)
gigabyte ---- (GB)
terabyte ---- (TB)
petabyte ---- (PB)
exabyte ---- (EB)
zettabyte ---- (ZB)
yottabyte ---- (YB)
'''
formats = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
unit = 1000.0 if is_disk else 1024.0
if not (isinstance(size, float) or isinstance(size, int)):
raise TypeError('a float number or an integer number is required!')
if size < 0:
raise ValueError('number must be non-negative')
for i in formats:
size /= unit
if size < unit:
r = '{}{}'.format(round(size, precision),i)
return r
if request.method == 'GET':
try:
search_kw = request.GET.get('kw', None)
if search_kw:
attachment_list = Attachment.objects.filter(
user=request.user,
file_name__icontains=search_kw
).order_by('-create_time')
paginator = Paginator(attachment_list, 15)
page = request.GET.get('page', 1)
try:
attachments = paginator.page(page)
except PageNotAnInteger:
attachments = paginator.page(1)
except EmptyPage:
attachments = paginator.page(paginator.num_pages)
attachments.kw = search_kw
else:
attachment_list = Attachment.objects.filter(user=request.user).order_by('-create_time')
paginator = Paginator(attachment_list, 15)
page = request.GET.get('page', 1)
try:
attachments = paginator.page(page)
except PageNotAnInteger:
attachments = paginator.page(1)
except EmptyPage:
attachments = paginator.page(paginator.num_pages)
return render(request, 'app_doc/manage_attachment.html', locals())
except Exception as e:
logger.exception("附件管理访问出错")
return render(request,'404.html')
elif request.method == 'POST':
# types参数0表示上传、1表示删除、2表示获取附件列表
types = request.POST.get('types','')
if types in ['0',0]:
attachment = request.FILES.get('attachment_upload',None)
if attachment:
attachment_name = attachment.name
attachment_size = sizeFormat(attachment.size)
# 限制附件大小在50mb以内
if attachment.size > 52428800:
return JsonResponse({'status':False,'data':'文件大小超出限制'})
# 限制附件为ZIP格式文件
if attachment_name.endswith('.zip'):
a = Attachment.objects.create(
file_name = attachment_name,
file_size = attachment_size,
file_path = attachment,
user = request.user
)
return JsonResponse({'status':True,'data':{'name':attachment_name,'url':a.file_path.name}})
else:
return JsonResponse({'status':False,'data':'不支持的格式'})
else:
return JsonResponse({'status':False,'data':'无效文件'})
elif types in ['1',1]:
attach_id = request.POST.get('attach_id','')
attachment = Attachment.objects.filter(id=attach_id,user=request.user) # 查询附件
for a in attachment: # 遍历附件
a.file_path.delete() # 删除文件
attachment.delete() # 删除数据库记录
return JsonResponse({'status':True,'data':'删除成功'})
elif types in [2,'2']:
attachment_list = []
attachments = Attachment.objects.filter(user=request.user)
for a in attachments:
item = {
'filename':a.file_name,
'filesize':a.file_size,
'filepath':a.file_path.name,
'filetime':a.create_time
}
attachment_list.append(item)
return JsonResponse({'status':True,'data':attachment_list})
else:
return JsonResponse({'status':False,'data':'无效参数'})
# 搜索
def search(request):
kw = request.GET.get('kw', None)
search_type = request.GET.get('type', 'doc') # 搜索类型默认文档doc
date_type = request.GET.get('d_type', 'recent')
date_range = request.GET.get('d_range', 'all') # 时间范围默认不限all
project_range = request.GET.get('p_range', 0) # 文集范围默认不限all
# 处理时间范围
if date_type == 'recent':
if date_range == 'recent1': # 最近1天
start_date = datetime.datetime.now() - datetime.timedelta(days=1)
elif date_range == 'recent7': # 最近7天
start_date = datetime.datetime.now() - datetime.timedelta(days=7)
elif date_range == 'recent30': # 最近30天
start_date = datetime.datetime.now() - datetime.timedelta(days=30)
elif date_range == 'recent365': # 最近一年
start_date = datetime.datetime.now() - datetime.timedelta(days=365)
else:
start_date = datetime.datetime.strptime('1900-01-01', '%Y-%m-%d')
end_date = datetime.datetime.now()
elif date_type == 'day':
try:
date_list = date_range.split('|')
start_date = datetime.datetime.strptime(date_list[0], '%Y-%m-%d')
end_date = datetime.datetime.strptime(date_list[1], '%Y-%m-%d')
except:
start_date = datetime.datetime.now() - datetime.timedelta(days=1)
end_date = datetime.datetime.now()
# 是否时间筛选
if date_range == 'all':
is_date_range = False
else:
is_date_range = True
# 是否认证
if request.user.is_authenticated:
is_auth = True
else:
is_auth = False
# 存在搜索关键词
if kw:
# 搜索文档
if search_type == 'doc':
if is_auth:
colla_list = [i.project.id for i in ProjectCollaborator.objects.filter(user=request.user)] # 用户的协作文集
open_list = [i.id for i in Project.objects.filter(
Q(role=0) | Q(create_user=request.user)
)] # 公开文集
view_list = list(set(open_list).union(set(colla_list))) # 合并上述两个文集ID列表
data_list = Doc.objects.filter(
Q(top_doc__in=view_list), # 包含用户可浏览到的文集
Q(create_time__gte=start_date, create_time__lte=end_date), # 筛选创建时间
Q(name__icontains=kw) | Q(content__icontains=kw) # 筛选文档标题和内容中包含搜索词
).order_by('-create_time')
else:
view_list = [i.id for i in Project.objects.filter(role=0)]
data_list = Doc.objects.filter(
Q(top_doc__in=view_list),
Q(create_time__gte=start_date, create_time__lte=end_date), # 筛选创建时间
Q(name__icontains=kw) | Q(content__icontains=kw) # 筛选文档标题和内容中包含搜索词
).order_by('-create_time')
# 搜索文集
elif search_type == 'pro':
# 认证用户
if is_auth:
colla_list = [i.project.id for i in ProjectCollaborator.objects.filter(user=request.user)] # 用户的协作文集
# 查询所有可显示的文集
data_list = Project.objects.filter(
Q(role=0) | \
Q(role=2, role_value__contains=str(request.user.username)) | \
Q(create_user=request.user) | \
Q(id__in=colla_list),
Q(create_time__gte=start_date, create_time__lte=end_date), # 筛选创建时间
Q(name__icontains=kw) | Q(intro__icontains=kw) # 筛选文集名称和简介包含搜索词
).order_by('-create_time')
# 游客
else:
data_list = Project.objects.filter(
Q(role=0),
Q(name__icontains=kw) | Q(intro__icontains=kw),
Q(create_time__gte=start_date, create_time__lte=end_date), # 筛选创建时间
).order_by("-create_time")
# 搜索标签
# elif search_type == 'tag':
# pass
else:
return render(request, 'app_doc/search.html')
# 分页处理
paginator = Paginator(data_list, 12)
page = request.GET.get('page', 1)
try:
datas = paginator.page(page)
except PageNotAnInteger:
datas = paginator.page(1)
except EmptyPage:
datas = paginator.page(paginator.num_pages)
return render(request, 'app_doc/search_result.html', locals())
# 否则跳转到搜索首页
else:
return render(request,'app_doc/search.html')
# 文档Markdown文件下载
@require_http_methods(['GET',"POST"])
def download_doc_md(request,doc_id):
if request.user.is_authenticated:
if request.user.is_superuser:
try:
doc = Doc.objects.get(id=doc_id)
except ObjectDoesNotExist:
return JsonResponse({'status':False,'data':'文档不存在'})
else:
try:
doc = Doc.objects.get(id=doc_id,create_user = request.user)
except ObjectDoesNotExist:
return JsonResponse({'status':False,'data':'文档不存在'})
else:
return render(request,'404.html')
response = HttpResponse(content_type='text/plain')
response['Content-Disposition'] = 'attachment; filename={}.md'.format(doc.name)
response.write(doc.pre_content)
return response