474 lines
16 KiB
Python
Executable File
474 lines
16 KiB
Python
Executable File
import importlib
|
||
import json
|
||
from django.contrib.auth.hashers import check_password, make_password
|
||
from django.db import transaction
|
||
from django_celery_beat.models import (CrontabSchedule, IntervalSchedule,
|
||
PeriodicTask)
|
||
from django_celery_results.models import TaskResult
|
||
from rest_framework.decorators import action
|
||
from rest_framework.exceptions import ParseError, ValidationError
|
||
from rest_framework.mixins import (CreateModelMixin, DestroyModelMixin,
|
||
ListModelMixin, RetrieveModelMixin)
|
||
from rest_framework.parsers import (JSONParser,
|
||
MultiPartParser)
|
||
from rest_framework.permissions import IsAuthenticated
|
||
from rest_framework.response import Response
|
||
from rest_framework.views import APIView
|
||
from apps.system.errors import FUNC_ERROR, OLD_PASSWORD_WRONG, PASSWORD_NOT_SAME, SCHEDULE_WRONG
|
||
# from django_q.models import Task as QTask, Schedule as QSchedule
|
||
from apps.utils.mixins import (CustomCreateModelMixin)
|
||
from django.conf import settings
|
||
from apps.utils.permission import ALL_PERMS, get_user_perms_map
|
||
from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
|
||
from server.celery import app as celery_app
|
||
from .filters import UserFilter
|
||
from .models import (Dept, Dictionary, DictType, File, Permission, Post, PostRole, Role, User,
|
||
UserPost)
|
||
from .serializers import (DeptCreateUpdateSerializer, DeptSerializer, DictCreateUpdateSerializer,
|
||
DictSerializer, DictTypeCreateUpdateSerializer, DictTypeSerializer,
|
||
FileSerializer, PasswordChangeSerializer, PermissionCreateUpdateSerializer,
|
||
PermissionSerializer, PostCreateUpdateSerializer, PostRoleCreateSerializer, PostRoleSerializer, PostSerializer,
|
||
PTaskSerializer, PTaskCreateUpdateSerializer, PTaskResultSerializer,
|
||
RoleCreateUpdateSerializer, RoleSerializer, TaskRunSerializer,
|
||
UserCreateSerializer, UserListSerializer, UserPostCreateSerializer,
|
||
UserPostSerializer, UserUpdateSerializer)
|
||
|
||
|
||
# logger.info('请求成功! response_code:{};response_headers:{};
|
||
# response_body:{}'.format(response_code, response_headers, response_body[:251]))
|
||
# logger.error('请求出错-{}'.format(error))
|
||
|
||
|
||
class TaskList(APIView):
|
||
permission_classes = [IsAuthenticated]
|
||
|
||
def get(self, request):
|
||
"""获取注册任务列表
|
||
|
||
获取注册任务列表
|
||
"""
|
||
tasks = list(
|
||
sorted(name for name in celery_app.tasks if not name.startswith('celery.')))
|
||
return Response(tasks)
|
||
|
||
|
||
# class QScheduleViewSet(CustomModelViewSet):
|
||
# """
|
||
# list:定时任务列表
|
||
|
||
# 定时任务列表
|
||
|
||
# retrieve:定时任务详情
|
||
|
||
# 定时任务详情
|
||
# """
|
||
# queryset = QSchedule.objects.all()
|
||
# serializer_class = QScheduleSerializer
|
||
# search_fields = ['name', 'func']
|
||
# filterset_fields = ['schedule_type']
|
||
# ordering = ['-pk']
|
||
|
||
# @action(methods=['get'], detail=True, perms_map={'post': 'qschedule:run_once'})
|
||
# def run_once(self, request, pk=None):
|
||
# """同步执行一次
|
||
|
||
# 同步执行一次
|
||
# """
|
||
# obj = self.get_object()
|
||
# module, func = obj.func.rsplit(".", 1)
|
||
# m = importlib.import_module(module)
|
||
# f = getattr(m, func)
|
||
# f(*obj.args.split(','), **eval(f"dict({obj.kwargs})"))
|
||
# return Response()
|
||
|
||
|
||
# class QTaskResultViewSet(ListModelMixin, RetrieveModelMixin, CustomGenericViewSet):
|
||
# """
|
||
# list:任务执行结果列表
|
||
|
||
# 任务执行结果列表
|
||
|
||
# retrieve:任务执行结果详情
|
||
|
||
# 任务执行结果详情
|
||
# """
|
||
# perms_map = {'get': '*'}
|
||
# filterset_fields = ['func']
|
||
# queryset = QTask.objects.all()
|
||
# serializer_class = QTaskResultSerializer
|
||
# ordering = ['-started']
|
||
# lookup_field = 'id'
|
||
|
||
class PTaskViewSet(CustomModelViewSet):
|
||
"""
|
||
list:定时任务列表
|
||
|
||
定时任务列表
|
||
|
||
retrieve:定时任务详情
|
||
|
||
定时任务详情
|
||
"""
|
||
queryset = PeriodicTask.objects.exclude(name__contains='celery.')
|
||
serializer_class = PTaskSerializer
|
||
create_serializer_class = PTaskCreateUpdateSerializer
|
||
update_serializer_class = PTaskCreateUpdateSerializer
|
||
partial_update_serializer_class = PTaskCreateUpdateSerializer
|
||
search_fields = ['name', 'task']
|
||
filterset_fields = ['enabled']
|
||
select_related_fields = ['interval', 'crontab']
|
||
ordering = ['-id']
|
||
|
||
@action(methods=['post'], detail=True, perms_map={'get': 'qtask:run_once'},
|
||
serializer_class=TaskRunSerializer)
|
||
def run_once(self, request, pk=None):
|
||
"""执行一次
|
||
|
||
执行一次
|
||
"""
|
||
obj = self.get_object()
|
||
module, func = obj.task.rsplit(".", 1)
|
||
m = importlib.import_module(module)
|
||
f = getattr(m, func)
|
||
if request.data.get('sync', True):
|
||
f(*json.loads(obj.args), **json.loads(obj.kwargs))
|
||
return Response()
|
||
else:
|
||
task_obj = f.delay(*json.loads(obj.args), **json.loads(obj.kwargs))
|
||
return Response({'task_id': task_obj.id})
|
||
|
||
@action(methods=['put'], detail=True, perms_map={'put': 'ptask:update'})
|
||
def toggle(self, request, pk=None):
|
||
"""修改启用禁用状态
|
||
|
||
修改启用禁用状态
|
||
"""
|
||
obj = self.get_object()
|
||
obj.enabled = False if obj.enabled else True
|
||
obj.save()
|
||
return Response()
|
||
|
||
@transaction.atomic
|
||
def create(self, request, *args, **kwargs):
|
||
"""创建定时任务
|
||
|
||
创建定时任务
|
||
"""
|
||
data = request.data
|
||
timetype = data.get('timetype', None)
|
||
interval_ = data.get('interval_', None)
|
||
crontab_ = data.get('crontab_', None)
|
||
if timetype == 'interval' and interval_:
|
||
data['crontab'] = None
|
||
try:
|
||
interval, _ = IntervalSchedule.objects.get_or_create(
|
||
**interval_, defaults=interval_)
|
||
data['interval'] = interval.id
|
||
except Exception:
|
||
raise ParseError(**SCHEDULE_WRONG)
|
||
if timetype == 'crontab' and crontab_:
|
||
data['interval'] = None
|
||
try:
|
||
crontab_['timezone'] = 'Asia/Shanghai'
|
||
crontab, _ = CrontabSchedule.objects.get_or_create(
|
||
**crontab_, defaults=crontab_)
|
||
data['crontab'] = crontab.id
|
||
except Exception:
|
||
raise ParseError(**SCHEDULE_WRONG)
|
||
serializer = self.get_serializer(data=data)
|
||
serializer.is_valid(raise_exception=True)
|
||
serializer.save()
|
||
return Response()
|
||
|
||
@transaction.atomic
|
||
def update(self, request, *args, **kwargs):
|
||
"""更新定时任务
|
||
|
||
更新定时任务
|
||
"""
|
||
data = request.data
|
||
timetype = data.get('timetype', None)
|
||
interval_ = data.get('interval_', None)
|
||
crontab_ = data.get('crontab_', None)
|
||
if timetype == 'interval' and interval_:
|
||
data['crontab'] = None
|
||
try:
|
||
if 'id' in interval_:
|
||
del interval_['id']
|
||
interval, _ = IntervalSchedule.objects.get_or_create(
|
||
**interval_, defaults=interval_)
|
||
data['interval'] = interval.id
|
||
except Exception:
|
||
raise ParseError(**SCHEDULE_WRONG)
|
||
if timetype == 'crontab' and crontab_:
|
||
data['interval'] = None
|
||
try:
|
||
crontab_['timezone'] = 'Asia/Shanghai'
|
||
if 'id' in crontab_:
|
||
del crontab_['id']
|
||
crontab, _ = CrontabSchedule.objects.get_or_create(
|
||
**crontab_, defaults=crontab_)
|
||
data['crontab'] = crontab.id
|
||
except Exception:
|
||
raise ParseError(**SCHEDULE_WRONG)
|
||
instance = self.get_object()
|
||
serializer = self.get_serializer(instance, data=data)
|
||
serializer.is_valid(raise_exception=True)
|
||
serializer.save()
|
||
return Response()
|
||
|
||
|
||
class PTaskResultViewSet(ListModelMixin, RetrieveModelMixin, CustomGenericViewSet):
|
||
"""
|
||
list:任务执行结果列表
|
||
|
||
任务执行结果列表
|
||
|
||
retrieve:任务执行结果详情
|
||
|
||
任务执行结果详情
|
||
"""
|
||
perms_map = {'get': '*'}
|
||
filterset_fields = ['task_name', 'periodic_task_name', 'status']
|
||
queryset = TaskResult.objects.all()
|
||
serializer_class = PTaskResultSerializer
|
||
ordering = ['-date_created']
|
||
lookup_field = 'task_id'
|
||
|
||
|
||
class DictTypeViewSet(CustomModelViewSet):
|
||
"""数据字典类型-增删改查
|
||
|
||
数据字典类型-增删改查
|
||
"""
|
||
queryset = DictType.objects.all()
|
||
serializer_class = DictTypeSerializer
|
||
create_serializer_class = DictTypeCreateUpdateSerializer
|
||
update_serializer_class = DictTypeCreateUpdateSerializer
|
||
partial_update_serializer_class = DictTypeCreateUpdateSerializer
|
||
search_fields = ['name']
|
||
|
||
|
||
class DictViewSet(CustomModelViewSet):
|
||
"""数据字典-增删改查
|
||
|
||
数据字典-增删改查
|
||
"""
|
||
# queryset = Dictionary.objects.get_queryset(all=True) # 获取全部的,包括软删除的
|
||
queryset = Dictionary.objects.all()
|
||
filterset_fields = ['type', 'is_used', 'type__code']
|
||
serializer_class = DictSerializer
|
||
create_serializer_class = DictCreateUpdateSerializer
|
||
update_serializer_class = DictCreateUpdateSerializer
|
||
partial_update_serializer_class = DictCreateUpdateSerializer
|
||
search_fields = ['name']
|
||
|
||
|
||
class PostViewSet(CustomModelViewSet):
|
||
"""岗位-增删改查
|
||
|
||
岗位-增删改查
|
||
"""
|
||
queryset = Post.objects.all()
|
||
serializer_class = PostSerializer
|
||
create_serializer_class = PostCreateUpdateSerializer
|
||
update_serializer_class = PostCreateUpdateSerializer
|
||
partial_update_serializer_class = PostCreateUpdateSerializer
|
||
search_fields = ['name', 'description']
|
||
|
||
|
||
class PermissionViewSet(CustomModelViewSet):
|
||
"""菜单权限-增删改查
|
||
|
||
菜单权限-增删改查
|
||
"""
|
||
queryset = Permission.objects.all()
|
||
filterset_fields = ['type']
|
||
serializer_class = PermissionSerializer
|
||
create_serializer_class = PermissionCreateUpdateSerializer
|
||
update_serializer_class = PermissionCreateUpdateSerializer
|
||
partial_update_serializer_class = PermissionCreateUpdateSerializer
|
||
search_fields = ['name', 'code']
|
||
|
||
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated])
|
||
def codes(self, request, pk=None):
|
||
"""获取全部权限标识
|
||
|
||
需要先请求一次swagger
|
||
"""
|
||
ALL_PERMS.sort()
|
||
return Response(ALL_PERMS)
|
||
|
||
|
||
class DeptViewSet(CustomModelViewSet):
|
||
"""部门-增删改查
|
||
|
||
部门-增删改查
|
||
"""
|
||
queryset = Dept.objects.filter(type__in=['dept', 'company'])
|
||
serializer_class = DeptSerializer
|
||
create_serializer_class = DeptCreateUpdateSerializer
|
||
update_serializer_class = DeptCreateUpdateSerializer
|
||
partial_update_serializer_class = DeptCreateUpdateSerializer
|
||
filterset_fields = ['type']
|
||
search_fields = ['name']
|
||
|
||
|
||
class RoleViewSet(CustomModelViewSet):
|
||
"""角色-增删改查
|
||
|
||
角色-增删改查
|
||
"""
|
||
queryset = Role.objects.all()
|
||
serializer_class = RoleSerializer
|
||
create_serializer_class = RoleCreateUpdateSerializer
|
||
update_serializer_class = RoleCreateUpdateSerializer
|
||
partial_update_serializer_class = RoleCreateUpdateSerializer
|
||
search_fields = ['name', 'code']
|
||
|
||
|
||
class PostRoleViewSet(CreateModelMixin, DestroyModelMixin, ListModelMixin, CustomGenericViewSet):
|
||
"""岗位/角色关系
|
||
|
||
岗位/角色关系
|
||
"""
|
||
perms_map = {'get': '*', 'post': 'post:update', 'delete': 'post:update'}
|
||
queryset = PostRole.objects.select_related('post', 'role').all()
|
||
serializer_class = PostRoleSerializer
|
||
create_serializer_class = PostRoleCreateSerializer
|
||
filterset_fields = ['post', 'role']
|
||
|
||
|
||
class UserPostViewSet(CreateModelMixin, DestroyModelMixin, ListModelMixin, CustomGenericViewSet):
|
||
"""用户/岗位关系
|
||
|
||
用户/岗位关系
|
||
"""
|
||
perms_map = {'get': '*', 'post': 'user:update', 'delete': 'user:update'}
|
||
queryset = UserPost.objects.select_related('user', 'post', 'dept').all()
|
||
serializer_class = UserPostSerializer
|
||
create_serializer_class = UserPostCreateSerializer
|
||
filterset_fields = ['user', 'post', 'dept']
|
||
|
||
def perform_create(self, serializer):
|
||
instance = serializer.save()
|
||
user = instance.user
|
||
adept = UserPost.objects.filter(user=user).order_by('sort', 'create_time').first()
|
||
if adept:
|
||
user.belong_dept = adept
|
||
user.update_by = self.request.user
|
||
user.save()
|
||
|
||
def perform_destroy(self, instance):
|
||
user = instance.user
|
||
instance.delete(update_by=self.request.user)
|
||
fdept = UserPost.objects.filter(user=user).order_by('sort', 'create_time').first()
|
||
if fdept:
|
||
user.belong_dept = fdept
|
||
else:
|
||
user.belong_dept = None
|
||
user.update_by = self.request.user
|
||
user.save()
|
||
|
||
|
||
class UserViewSet(CustomModelViewSet):
|
||
queryset = User.objects.filter(type='employee')
|
||
serializer_class = UserListSerializer
|
||
create_serializer_class = UserCreateSerializer
|
||
update_serializer_class = UserUpdateSerializer
|
||
filterset_class = UserFilter
|
||
search_fields = ['username', 'name', 'phone', 'email']
|
||
select_related_fields = ['superior', 'belong_dept']
|
||
prefetch_related_fields = ['posts']
|
||
|
||
def create(self, request, *args, **kwargs):
|
||
"""创建用户
|
||
|
||
创建用户
|
||
"""
|
||
password = make_password('0000')
|
||
serializer = self.get_serializer(data=request.data)
|
||
serializer.is_valid(raise_exception=True)
|
||
serializer.save(password=password, belong_dept=None)
|
||
return Response(data=serializer.data)
|
||
|
||
@action(methods=['put'], detail=False,
|
||
permission_classes=[IsAuthenticated],
|
||
serializer_class=PasswordChangeSerializer)
|
||
def password(self, request, pk=None):
|
||
"""修改密码
|
||
|
||
修改密码
|
||
"""
|
||
user = request.user
|
||
old_password = request.data['old_password']
|
||
if check_password(old_password, user.password):
|
||
new_password1 = request.data['new_password1']
|
||
new_password2 = request.data['new_password2']
|
||
if new_password1 == new_password2:
|
||
user.set_password(new_password2)
|
||
user.save()
|
||
return Response()
|
||
else:
|
||
raise ParseError(**PASSWORD_NOT_SAME)
|
||
else:
|
||
raise ValidationError(**OLD_PASSWORD_WRONG)
|
||
|
||
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated])
|
||
def info(self, request, pk=None):
|
||
"""登录用户信息
|
||
|
||
获取登录用户信息
|
||
"""
|
||
user = request.user
|
||
perms = get_user_perms_map(user)
|
||
data = {
|
||
'id': user.id,
|
||
'username': user.username,
|
||
'name': user.name,
|
||
'posts': user.posts.values_list('name', flat=True),
|
||
'avatar': user.avatar,
|
||
'perms': perms,
|
||
}
|
||
return Response(data)
|
||
|
||
|
||
class FileViewSet(CustomCreateModelMixin, RetrieveModelMixin, ListModelMixin, CustomGenericViewSet):
|
||
"""文件上传
|
||
|
||
list:
|
||
文件列表
|
||
|
||
文件列表
|
||
|
||
create:
|
||
文件上传
|
||
|
||
文件上传
|
||
"""
|
||
permission_classes = [IsAuthenticated]
|
||
parser_classes = [MultiPartParser, JSONParser]
|
||
queryset = File.objects.all()
|
||
serializer_class = FileSerializer
|
||
filterset_fields = ['type']
|
||
search_fields = ['name']
|
||
|
||
def perform_create(self, serializer):
|
||
file_obj = self.request.data.get('file')
|
||
name = file_obj._name
|
||
size = file_obj.size
|
||
mime = file_obj.content_type
|
||
file_type = '其它'
|
||
if 'image' in mime:
|
||
file_type = '图片'
|
||
elif 'video' in mime:
|
||
file_type = '视频'
|
||
elif 'audio' in mime:
|
||
file_type = '音频'
|
||
elif 'application' or 'text' in mime:
|
||
file_type = '文档'
|
||
instance = serializer.save(
|
||
create_by=self.request.user, name=name, size=size, type=file_type, mime=mime)
|
||
instance.path = settings.MEDIA_URL + instance.file.name
|
||
instance.save()
|