Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
@@ -19,6 +19,20 @@ class UsersInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化获取数信息(用于生成初始化json文件)
|
||||
"""
|
||||
role_key = serializers.SerializerMethodField()
|
||||
dept_key = serializers.SerializerMethodField()
|
||||
|
||||
def get_dept_key(self, obj):
|
||||
if obj.dept:
|
||||
return obj.dept.key
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_role_key(self, obj):
|
||||
if obj.role.all():
|
||||
return [role.key for role in obj.role.all()]
|
||||
else:
|
||||
return []
|
||||
|
||||
def save(self, **kwargs):
|
||||
instance = super().save(**kwargs)
|
||||
@@ -35,7 +49,7 @@ class UsersInitSerializer(CustomModelSerializer):
|
||||
model = Users
|
||||
fields = ["username", "email", 'mobile', 'avatar', "name", 'gender', 'user_type', "dept", 'user_type',
|
||||
'first_name', 'last_name', 'email', 'is_staff', 'is_active', 'creator', 'dept_belong_id',
|
||||
'password', 'last_login', 'is_superuser']
|
||||
'password', 'last_login', 'is_superuser', 'role_key' ,'dept_key']
|
||||
read_only_fields = ['id']
|
||||
extra_kwargs = {
|
||||
'creator': {'write_only': True},
|
||||
@@ -175,15 +189,21 @@ class RoleMenuInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化角色菜单(用于生成初始化json文件)
|
||||
"""
|
||||
role__key = serializers.CharField(max_length=100, required=True)
|
||||
menu__web_path = serializers.CharField(max_length=100, required=True)
|
||||
menu__component_name = serializers.CharField(max_length=100, required=True, allow_blank=True)
|
||||
role__key = serializers.CharField(source='role.key')
|
||||
menu__web_path = serializers.CharField(source='menu.web_path')
|
||||
menu__component_name = serializers.CharField(source='menu.component_name', allow_blank=True)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
init_data = self.initial_data
|
||||
role_id = Role.objects.filter(key=init_data['role__key']).first()
|
||||
menu_id = Menu.objects.filter(web_path=init_data['menu__web_path'], component_name=init_data['menu__component_name']).first()
|
||||
validated_data['role'] = role_id
|
||||
validated_data['menu'] = menu_id
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
|
||||
def create(self, validated_data):
|
||||
init_data = self.initial_data
|
||||
validated_data.pop('menu__web_path')
|
||||
validated_data.pop('menu__component_name')
|
||||
validated_data.pop('role__key')
|
||||
role_id = Role.objects.filter(key=init_data['role__key']).first()
|
||||
menu_id = Menu.objects.filter(web_path=init_data['menu__web_path'], component_name=init_data['menu__component_name']).first()
|
||||
validated_data['role'] = role_id
|
||||
@@ -192,7 +212,7 @@ class RoleMenuInitSerializer(CustomModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = RoleMenuPermission
|
||||
fields = ['role__key', 'menu__web_path', 'menu__component_name', 'creator', 'dept_belong_id']
|
||||
fields = ['role__key', 'menu__web_path', 'menu__component_name','creator', 'dept_belong_id']
|
||||
read_only_fields = ["id"]
|
||||
extra_kwargs = {
|
||||
'role': {'required': False},
|
||||
@@ -206,14 +226,22 @@ class RoleMenuButtonInitSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化角色菜单按钮(用于生成初始化json文件)
|
||||
"""
|
||||
role__key = serializers.CharField(max_length=100, required=True)
|
||||
menu_button__value = serializers.CharField(max_length=100, required=True)
|
||||
role__key = serializers.CharField(source='role.key')
|
||||
menu_button__value = serializers.CharField(source='menu_button.value')
|
||||
data_range = serializers.CharField(max_length=100, required=False)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
init_data = self.initial_data
|
||||
role_id = Role.objects.filter(key=init_data['role__key']).first()
|
||||
menu_button_id = MenuButton.objects.filter(value=init_data['menu_button__value']).first()
|
||||
validated_data['role'] = role_id
|
||||
validated_data['menu_button'] = menu_button_id
|
||||
instance = super().create(validated_data)
|
||||
instance.dept.set([])
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
def create(self, validated_data):
|
||||
init_data = self.initial_data
|
||||
validated_data.pop('menu_button__value')
|
||||
validated_data.pop('role__key')
|
||||
role_id = Role.objects.filter(key=init_data['role__key']).first()
|
||||
menu_button_id = MenuButton.objects.filter(value=init_data['menu_button__value']).first()
|
||||
validated_data['role'] = role_id
|
||||
@@ -223,7 +251,7 @@ class RoleMenuButtonInitSerializer(CustomModelSerializer):
|
||||
return instance
|
||||
|
||||
def save(self, **kwargs):
|
||||
if self.instance and self.initial_data.get('reset'):
|
||||
if not self.instance or self.initial_data.get('reset'):
|
||||
return super().save(**kwargs)
|
||||
return self.instance
|
||||
|
||||
|
||||
@@ -672,6 +672,53 @@
|
||||
"model": "ApiWhiteList"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "下载中心",
|
||||
"icon": "ele-Download",
|
||||
"sort": 9,
|
||||
"is_link": false,
|
||||
"is_catalog": false,
|
||||
"web_path": "/downloadCenter",
|
||||
"component": "system/downloadCenter/index",
|
||||
"component_name": "downloadCenter",
|
||||
"status": true,
|
||||
"cache": false,
|
||||
"visible": true,
|
||||
"parent": 277,
|
||||
"children": [],
|
||||
"menu_button": [
|
||||
{
|
||||
"name": "查询",
|
||||
"value": "Search",
|
||||
"api": "/api/system/downloadCenter/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "详情",
|
||||
"value": "Retrieve",
|
||||
"api": "/api/system/downloadCenter/{id}/",
|
||||
"method": 0
|
||||
},
|
||||
{
|
||||
"name": "新增",
|
||||
"value": "Create",
|
||||
"api": "/api/system/downloadCenter/",
|
||||
"method": 1
|
||||
},
|
||||
{
|
||||
"name": "编辑",
|
||||
"value": "Update",
|
||||
"api": "/api/system/downloadCenter/{id}/",
|
||||
"method": 2
|
||||
},
|
||||
{
|
||||
"name": "删除",
|
||||
"value": "Delete",
|
||||
"api": "/api/system/downloadCenter/{id}/",
|
||||
"method": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"menu_button": [],
|
||||
|
||||
@@ -10,7 +10,7 @@ django.setup()
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from application.settings import BASE_DIR
|
||||
from dvadmin.system.models import Menu, Users, Dept, Role, ApiWhiteList, Dictionary, SystemConfig
|
||||
from dvadmin.system.models import Menu, Users, Dept, Role, ApiWhiteList, Dictionary, SystemConfig, RoleMenuButtonPermission, RoleMenuPermission
|
||||
from dvadmin.system.fixtures.initSerializer import UsersInitSerializer, DeptInitSerializer, RoleInitSerializer, \
|
||||
MenuInitSerializer, ApiWhiteListInitSerializer, DictionaryInitSerializer, SystemConfigInitSerializer, \
|
||||
RoleMenuInitSerializer, RoleMenuButtonInitSerializer
|
||||
@@ -57,6 +57,12 @@ class Command(BaseCommand):
|
||||
def generate_system_config(self):
|
||||
self.serializer_data(SystemConfigInitSerializer, SystemConfig.objects.filter(parent_id__isnull=True))
|
||||
|
||||
def generate_role_menu(self):
|
||||
self.serializer_data(RoleMenuInitSerializer, RoleMenuPermission.objects.all())
|
||||
|
||||
def generate_role_menu_button(self):
|
||||
self.serializer_data(RoleMenuButtonInitSerializer, RoleMenuButtonPermission.objects.all())
|
||||
|
||||
def handle(self, *args, **options):
|
||||
generate_name = options.get('generate_name')
|
||||
generate_name_dict = {
|
||||
@@ -67,6 +73,8 @@ class Command(BaseCommand):
|
||||
"api_white_list": self.generate_api_white_list,
|
||||
"dictionary": self.generate_dictionary,
|
||||
"system_config": self.generate_system_config,
|
||||
"role_menu": self.generate_role_menu,
|
||||
"role_menu_button": self.generate_role_menu_button,
|
||||
}
|
||||
if not generate_name:
|
||||
for ele in generate_name_dict.keys():
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import hashlib
|
||||
import os
|
||||
from time import time
|
||||
from pathlib import PurePosixPath
|
||||
|
||||
from django.contrib.auth.models import AbstractUser, UserManager
|
||||
from django.db import models
|
||||
@@ -7,8 +9,8 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
||||
from application import dispatch
|
||||
from dvadmin.utils.models import CoreModel, table_prefix, get_custom_app_models
|
||||
|
||||
|
||||
class Role(CoreModel):
|
||||
from dvadmin3_flow.base_model import FlowBaseModel
|
||||
class Role(CoreModel,FlowBaseModel):
|
||||
name = models.CharField(max_length=64, verbose_name="角色名称", help_text="角色名称")
|
||||
key = models.CharField(max_length=64, unique=True, verbose_name="权限字符", help_text="权限字符")
|
||||
sort = models.IntegerField(default=1, verbose_name="角色顺序", help_text="角色顺序")
|
||||
@@ -71,6 +73,7 @@ class Users(CoreModel, AbstractUser):
|
||||
help_text="关联部门",
|
||||
)
|
||||
login_error_count = models.IntegerField(default=0, verbose_name="登录错误次数", help_text="登录错误次数")
|
||||
pwd_change_count = models.IntegerField(default=0,blank=True, verbose_name="密码修改次数", help_text="密码修改次数")
|
||||
objects = CustomUserManager()
|
||||
|
||||
def set_password(self, raw_password):
|
||||
@@ -119,6 +122,27 @@ class Dept(CoreModel):
|
||||
help_text="上级部门",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _recursion(cls, instance, parent, result):
|
||||
new_instance = getattr(instance, parent, None)
|
||||
res = []
|
||||
data = getattr(instance, result, None)
|
||||
if data:
|
||||
res.append(data)
|
||||
if new_instance:
|
||||
array = cls._recursion(new_instance, parent, result)
|
||||
res += array
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def get_region_name(cls, obj):
|
||||
"""
|
||||
获取某个用户的递归所有部门名称
|
||||
"""
|
||||
dept_name_all = cls._recursion(obj, "parent", "name")
|
||||
dept_name_all.reverse()
|
||||
return "/".join(dept_name_all)
|
||||
|
||||
@classmethod
|
||||
def recursion_all_dept(cls, dept_id: int, dept_all_list=None, dept_list=None):
|
||||
"""
|
||||
@@ -405,6 +429,18 @@ class FileList(CoreModel):
|
||||
mime_type = models.CharField(max_length=100, blank=True, verbose_name="Mime类型", help_text="Mime类型")
|
||||
size = models.CharField(max_length=36, blank=True, verbose_name="文件大小", help_text="文件大小")
|
||||
md5sum = models.CharField(max_length=36, blank=True, verbose_name="文件md5", help_text="文件md5")
|
||||
UPLOAD_METHOD_CHOIDES = (
|
||||
(0, '默认上传'),
|
||||
(1, '文件选择器上传'),
|
||||
)
|
||||
upload_method = models.SmallIntegerField(default=0, blank=True, null=True, choices=UPLOAD_METHOD_CHOIDES, verbose_name='上传方式', help_text='上传方式')
|
||||
FILE_TYPE_CHOIDES = (
|
||||
(0, '图片'),
|
||||
(1, '视频'),
|
||||
(2, '音频'),
|
||||
(3, '其他'),
|
||||
)
|
||||
file_type = models.SmallIntegerField(default=3, choices=FILE_TYPE_CHOIDES, blank=True, null=True, verbose_name='文件类型', help_text='文件类型')
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.md5sum: # file is new
|
||||
@@ -595,3 +631,41 @@ class MessageCenterTargetUser(CoreModel):
|
||||
db_table = table_prefix + "message_center_target_user"
|
||||
verbose_name = "消息中心目标用户表"
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
|
||||
def media_file_name_downloadcenter(instance:'DownloadCenter', filename):
|
||||
h = instance.md5sum
|
||||
basename, ext = os.path.splitext(filename)
|
||||
return PurePosixPath("files", "dlct", h[:1], h[1:2], basename + '-' + str(time()).replace('.', '') + ext.lower())
|
||||
|
||||
|
||||
class DownloadCenter(CoreModel):
|
||||
TASK_STATUS_CHOICES = [
|
||||
(0, '任务已创建'),
|
||||
(1, '任务进行中'),
|
||||
(2, '任务完成'),
|
||||
(3, '任务失败'),
|
||||
]
|
||||
task_name = models.CharField(max_length=255, verbose_name="任务名称", help_text="任务名称")
|
||||
task_status = models.SmallIntegerField(default=0, choices=TASK_STATUS_CHOICES, verbose_name='是否可下载', help_text='是否可下载')
|
||||
file_name = models.CharField(max_length=255, null=True, blank=True, verbose_name="文件名", help_text="文件名")
|
||||
url = models.FileField(upload_to=media_file_name_downloadcenter, null=True, blank=True)
|
||||
size = models.BigIntegerField(default=0, verbose_name="文件大小", help_text="文件大小")
|
||||
md5sum = models.CharField(max_length=36, null=True, blank=True, verbose_name="文件md5", help_text="文件md5")
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.url:
|
||||
if not self.md5sum: # file is new
|
||||
md5 = hashlib.md5()
|
||||
for chunk in self.url.chunks():
|
||||
md5.update(chunk)
|
||||
self.md5sum = md5.hexdigest()
|
||||
if not self.size:
|
||||
self.size = self.url.size
|
||||
super(DownloadCenter, self).save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
db_table = table_prefix + "download_center"
|
||||
verbose_name = "下载中心"
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ("-create_datetime",)
|
||||
|
||||
12
backend/dvadmin/system/signals.py
Normal file
12
backend/dvadmin/system/signals.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from django.dispatch import Signal
|
||||
# 初始化信号
|
||||
pre_init_complete = Signal()
|
||||
detail_init_complete = Signal()
|
||||
post_init_complete = Signal()
|
||||
# 租户初始化信号
|
||||
pre_tenants_init_complete = Signal()
|
||||
detail_tenants_init_complete = Signal()
|
||||
post_tenants_init_complete = Signal()
|
||||
post_tenants_all_init_complete = Signal()
|
||||
# 租户创建完成信号
|
||||
tenants_create_complete = Signal()
|
||||
107
backend/dvadmin/system/tasks.py
Normal file
107
backend/dvadmin/system/tasks.py
Normal file
@@ -0,0 +1,107 @@
|
||||
from hashlib import md5
|
||||
from io import BytesIO
|
||||
from datetime import datetime
|
||||
from time import sleep
|
||||
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.worksheet.table import Table, TableStyleInfo
|
||||
from openpyxl.utils import get_column_letter
|
||||
from django.core.files.base import ContentFile
|
||||
|
||||
from application.celery import app
|
||||
from dvadmin.system.models import DownloadCenter
|
||||
|
||||
def is_number(num):
|
||||
try:
|
||||
float(num)
|
||||
return True
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
import unicodedata
|
||||
unicodedata.numeric(num)
|
||||
return True
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
return False
|
||||
|
||||
def get_string_len(string):
|
||||
"""
|
||||
获取字符串最大长度
|
||||
:param string:
|
||||
:return:
|
||||
"""
|
||||
length = 4
|
||||
if string is None:
|
||||
return length
|
||||
if is_number(string):
|
||||
return length
|
||||
for char in string:
|
||||
length += 2.1 if ord(char) > 256 else 1
|
||||
return round(length, 1) if length <= 50 else 50
|
||||
|
||||
@app.task
|
||||
def async_export_data(data: list, filename: str, dcid: int, export_field_label: dict):
|
||||
instance = DownloadCenter.objects.get(pk=dcid)
|
||||
instance.task_status = 1
|
||||
instance.save()
|
||||
sleep(2)
|
||||
try:
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
header_data = ["序号", *export_field_label.values()]
|
||||
hidden_header = ["#", *export_field_label.keys()]
|
||||
df_len_max = [get_string_len(ele) for ele in header_data]
|
||||
row = get_column_letter(len(export_field_label) + 1)
|
||||
column = 1
|
||||
ws.append(header_data)
|
||||
for index, results in enumerate(data):
|
||||
results_list = []
|
||||
for h_index, h_item in enumerate(hidden_header):
|
||||
for key, val in results.items():
|
||||
if key == h_item:
|
||||
if val is None or val == "":
|
||||
results_list.append("")
|
||||
elif isinstance(val, datetime):
|
||||
val = val.strftime("%Y-%m-%d %H:%M:%S")
|
||||
results_list.append(val)
|
||||
else:
|
||||
results_list.append(val)
|
||||
# 计算最大列宽度
|
||||
result_column_width = get_string_len(val)
|
||||
if h_index != 0 and result_column_width > df_len_max[h_index]:
|
||||
df_len_max[h_index] = result_column_width
|
||||
ws.append([index + 1, *results_list])
|
||||
column += 1
|
||||
# 更新列宽
|
||||
for index, width in enumerate(df_len_max):
|
||||
ws.column_dimensions[get_column_letter(index + 1)].width = width
|
||||
tab = Table(displayName="Table", ref=f"A1:{row}{column}") # 名称管理器
|
||||
style = TableStyleInfo(
|
||||
name="TableStyleLight11",
|
||||
showFirstColumn=True,
|
||||
showLastColumn=True,
|
||||
showRowStripes=True,
|
||||
showColumnStripes=True,
|
||||
)
|
||||
tab.tableStyleInfo = style
|
||||
ws.add_table(tab)
|
||||
stream = BytesIO()
|
||||
wb.save(stream)
|
||||
stream.seek(0)
|
||||
s = md5()
|
||||
while True:
|
||||
chunk = stream.read(1024)
|
||||
if not chunk:
|
||||
break
|
||||
s.update(chunk)
|
||||
stream.seek(0)
|
||||
instance.md5sum = s.hexdigest()
|
||||
instance.file_name = filename
|
||||
instance.url.save(filename, ContentFile(stream.read()))
|
||||
instance.task_status = 2
|
||||
except Exception as e:
|
||||
instance.task_status = 3
|
||||
instance.description = str(e)[:250]
|
||||
instance.save()
|
||||
@@ -18,6 +18,7 @@ from dvadmin.system.views.role_menu_button_permission import RoleMenuButtonPermi
|
||||
from dvadmin.system.views.system_config import SystemConfigViewSet
|
||||
from dvadmin.system.views.user import UserViewSet
|
||||
from dvadmin.system.views.menu_field import MenuFieldViewSet
|
||||
from dvadmin.system.views.download_center import DownloadCenterViewSet
|
||||
|
||||
system_url = routers.SimpleRouter()
|
||||
system_url.register(r'menu', MenuViewSet)
|
||||
@@ -36,6 +37,7 @@ system_url.register(r'role_menu_button_permission', RoleMenuButtonPermissionView
|
||||
system_url.register(r'role_menu_permission', RoleMenuPermissionViewSet)
|
||||
system_url.register(r'column', MenuFieldViewSet)
|
||||
system_url.register(r'login_log', LoginLogViewSet)
|
||||
system_url.register(r'download_center', DownloadCenterViewSet)
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
@@ -47,7 +49,7 @@ urlpatterns = [
|
||||
path('system_config/get_relation_info/', SystemConfigViewSet.as_view({'get': 'get_relation_info'})),
|
||||
# path('login_log/', LoginLogViewSet.as_view({'get': 'list'})),
|
||||
# path('login_log/<int:pk>/', LoginLogViewSet.as_view({'get': 'retrieve'})),
|
||||
path('dept_lazy_tree/', DeptViewSet.as_view({'get': 'dept_lazy_tree'})),
|
||||
# path('dept_lazy_tree/', DeptViewSet.as_view({'get': 'dept_lazy_tree'})),
|
||||
path('clause/privacy.html', PrivacyView.as_view()),
|
||||
path('clause/terms_service.html', TermsServiceView.as_view()),
|
||||
]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pypinyin
|
||||
from django.db.models import Q
|
||||
from rest_framework import serializers
|
||||
|
||||
@@ -15,6 +16,11 @@ class AreaSerializer(CustomModelSerializer):
|
||||
"""
|
||||
pcode_count = serializers.SerializerMethodField(read_only=True)
|
||||
hasChild = serializers.SerializerMethodField()
|
||||
pcode_info = serializers.SerializerMethodField()
|
||||
|
||||
def get_pcode_info(self, instance):
|
||||
pcode = Area.objects.filter(code=instance.pcode_id).values("name", "code")
|
||||
return pcode
|
||||
|
||||
def get_pcode_count(self, instance: Area):
|
||||
return Area.objects.filter(pcode=instance).count()
|
||||
@@ -36,6 +42,18 @@ class AreaCreateUpdateSerializer(CustomModelSerializer):
|
||||
地区管理 创建/更新时的列化器
|
||||
"""
|
||||
|
||||
def to_internal_value(self, data):
|
||||
pinyin = ''.join([''.join(i) for i in pypinyin.pinyin(data["name"], style=pypinyin.NORMAL)])
|
||||
data["level"] = 1
|
||||
data["pinyin"] = pinyin
|
||||
data["initials"] = pinyin[0].upper() if pinyin else "#"
|
||||
pcode = data["pcode"] if 'pcode' in data else None
|
||||
if pcode:
|
||||
pcode = Area.objects.get(pk=pcode)
|
||||
data["pcode"] = pcode.code
|
||||
data["level"] = pcode.level + 1
|
||||
return super().to_internal_value(data)
|
||||
|
||||
class Meta:
|
||||
model = Area
|
||||
fields = '__all__'
|
||||
@@ -52,20 +70,28 @@ class AreaViewSet(CustomModelViewSet, FieldPermissionMixin):
|
||||
"""
|
||||
queryset = Area.objects.all()
|
||||
serializer_class = AreaSerializer
|
||||
create_serializer_class = AreaCreateUpdateSerializer
|
||||
update_serializer_class = AreaCreateUpdateSerializer
|
||||
extra_filter_class = []
|
||||
|
||||
def get_queryset(self):
|
||||
def list(self, request, *args, **kwargs):
|
||||
self.request.query_params._mutable = True
|
||||
params = self.request.query_params
|
||||
pcode = params.get('pcode', None)
|
||||
page = params.get('page', None)
|
||||
limit = params.get('limit', None)
|
||||
if page:
|
||||
del params['page']
|
||||
if limit:
|
||||
del params['limit']
|
||||
if params and pcode:
|
||||
queryset = self.queryset.filter(enable=True, pcode=pcode)
|
||||
else:
|
||||
known_params = {'page', 'limit', 'pcode'}
|
||||
# 使用集合操作检查是否有未知参数
|
||||
other_params_exist = any(param not in known_params for param in params)
|
||||
if other_params_exist:
|
||||
queryset = self.queryset.filter(enable=True)
|
||||
return queryset
|
||||
else:
|
||||
pcode = params.get('pcode', None)
|
||||
params['limit'] = 999
|
||||
if params and pcode:
|
||||
queryset = self.queryset.filter(enable=True, pcode=pcode)
|
||||
else:
|
||||
queryset = self.queryset.filter(enable=True, level=1)
|
||||
page = self.paginate_queryset(queryset)
|
||||
if page is not None:
|
||||
serializer = self.get_serializer(page, many=True, request=request)
|
||||
return self.get_paginated_response(serializer.data)
|
||||
serializer = self.get_serializer(queryset, many=True, request=request)
|
||||
return SuccessResponse(data=serializer.data, msg="获取成功")
|
||||
|
||||
49
backend/dvadmin/system/views/download_center.py
Normal file
49
backend/dvadmin/system/views/download_center.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from rest_framework import serializers
|
||||
from django.conf import settings
|
||||
from django_filters.rest_framework import FilterSet, CharFilter
|
||||
|
||||
from dvadmin.utils.serializers import CustomModelSerializer
|
||||
from dvadmin.utils.viewset import CustomModelViewSet
|
||||
from dvadmin.system.models import DownloadCenter
|
||||
|
||||
|
||||
class DownloadCenterSerializer(CustomModelSerializer):
|
||||
url = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
def get_url(self, instance):
|
||||
if self.request.query_params.get('prefix'):
|
||||
if settings.ENVIRONMENT in ['local']:
|
||||
prefix = 'http://127.0.0.1:8000'
|
||||
elif settings.ENVIRONMENT in ['test']:
|
||||
prefix = 'http://{host}/api'.format(host=self.request.get_host())
|
||||
else:
|
||||
prefix = 'https://{host}/api'.format(host=self.request.get_host())
|
||||
return (f'{prefix}/media/{str(instance.url)}')
|
||||
return f'media/{str(instance.url)}'
|
||||
|
||||
class Meta:
|
||||
model = DownloadCenter
|
||||
fields = "__all__"
|
||||
read_only_fields = ["id"]
|
||||
|
||||
|
||||
class DownloadCenterFilterSet(FilterSet):
|
||||
task_name = CharFilter(field_name='task_name', lookup_expr='icontains')
|
||||
file_name = CharFilter(field_name='file_name', lookup_expr='icontains')
|
||||
|
||||
class Meta:
|
||||
model = DownloadCenter
|
||||
fields = ['task_status', 'task_name', 'file_name']
|
||||
|
||||
|
||||
class DownloadCenterViewSet(CustomModelViewSet):
|
||||
queryset = DownloadCenter.objects.all()
|
||||
serializer_class = DownloadCenterSerializer
|
||||
filter_class = DownloadCenterFilterSet
|
||||
permission_classes = []
|
||||
extra_filter_class = []
|
||||
|
||||
def get_queryset(self):
|
||||
if self.request.user.is_superuser:
|
||||
return super().get_queryset()
|
||||
return super().get_queryset().filter(creator=self.request.user)
|
||||
@@ -1,12 +1,15 @@
|
||||
import hashlib
|
||||
import mimetypes
|
||||
|
||||
import django_filters
|
||||
from django.conf import settings
|
||||
from django.db import connection
|
||||
from rest_framework import serializers
|
||||
from rest_framework.decorators import action
|
||||
|
||||
from application import dispatch
|
||||
from dvadmin.system.models import FileList
|
||||
from dvadmin.utils.json_response import DetailResponse
|
||||
from dvadmin.utils.json_response import DetailResponse, SuccessResponse
|
||||
from dvadmin.utils.serializers import CustomModelSerializer
|
||||
from dvadmin.utils.viewset import CustomModelViewSet
|
||||
|
||||
@@ -15,8 +18,17 @@ class FileSerializer(CustomModelSerializer):
|
||||
url = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
def get_url(self, instance):
|
||||
base_url = f"{self.request.scheme}://{self.request.get_host()}/"
|
||||
return base_url + (instance.file_url or (f'media/{str(instance.url)}'))
|
||||
if self.request.query_params.get('prefix'):
|
||||
if settings.ENVIRONMENT in ['local']:
|
||||
prefix = 'http://127.0.0.1:8000'
|
||||
elif settings.ENVIRONMENT in ['test']:
|
||||
prefix = 'http://{host}/api'.format(host=self.request.get_host())
|
||||
else:
|
||||
prefix = 'https://{host}/api'.format(host=self.request.get_host())
|
||||
if instance.file_url:
|
||||
return instance.file_url if instance.file_url.startswith('http') else f"{prefix}/{instance.file_url}"
|
||||
return (f'{prefix}/media/{str(instance.url)}')
|
||||
return instance.file_url or (f'media/{str(instance.url)}')
|
||||
|
||||
class Meta:
|
||||
model = FileList
|
||||
@@ -35,6 +47,8 @@ class FileSerializer(CustomModelSerializer):
|
||||
validated_data['md5sum'] = md5.hexdigest()
|
||||
validated_data['engine'] = file_engine
|
||||
validated_data['mime_type'] = file.content_type
|
||||
ft = {'image':0,'video':1,'audio':2}.get(file.content_type.split('/')[0], None)
|
||||
validated_data['file_type'] = 3 if ft is None else ft
|
||||
if file_backup:
|
||||
validated_data['url'] = file
|
||||
if file_engine == 'oss':
|
||||
@@ -64,6 +78,22 @@ class FileSerializer(CustomModelSerializer):
|
||||
return super().create(validated_data)
|
||||
|
||||
|
||||
class FileAllSerializer(CustomModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = FileList
|
||||
fields = ['id', 'name']
|
||||
|
||||
|
||||
class FileFilter(django_filters.FilterSet):
|
||||
name = django_filters.CharFilter(field_name="name", lookup_expr="icontains", help_text="文件名")
|
||||
mime_type = django_filters.CharFilter(field_name="mime_type", lookup_expr="icontains", help_text="文件类型")
|
||||
|
||||
class Meta:
|
||||
model = FileList
|
||||
fields = ['name', 'mime_type', 'upload_method', 'file_type']
|
||||
|
||||
|
||||
class FileViewSet(CustomModelViewSet):
|
||||
"""
|
||||
文件管理接口
|
||||
@@ -75,5 +105,22 @@ class FileViewSet(CustomModelViewSet):
|
||||
"""
|
||||
queryset = FileList.objects.all()
|
||||
serializer_class = FileSerializer
|
||||
filter_fields = ['name', ]
|
||||
permission_classes = []
|
||||
filter_class = FileFilter
|
||||
permission_classes = []
|
||||
|
||||
@action(methods=['GET'], detail=False)
|
||||
def get_all(self, request):
|
||||
data1 = self.get_serializer(self.get_queryset(), many=True).data
|
||||
data2 = []
|
||||
if dispatch.is_tenants_mode():
|
||||
from django_tenants.utils import schema_context
|
||||
with schema_context('public'):
|
||||
data2 = self.get_serializer(FileList.objects.all(), many=True).data
|
||||
return DetailResponse(data=data2+data1)
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
if self.request.query_params.get('system', 'False') == 'True' and dispatch.is_tenants_mode():
|
||||
from django_tenants.utils import schema_context
|
||||
with schema_context('public'):
|
||||
return super().list(request, *args, **kwargs)
|
||||
return super().list(request, *args, **kwargs)
|
||||
|
||||
@@ -4,12 +4,15 @@ from datetime import datetime, timedelta
|
||||
from captcha.views import CaptchaStore, captcha_image
|
||||
from django.contrib import auth
|
||||
from django.contrib.auth import login
|
||||
from django.contrib.auth.hashers import check_password, make_password
|
||||
from django.db.models import Q
|
||||
from django.shortcuts import redirect
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from rest_framework import serializers
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
|
||||
from rest_framework_simplejwt.views import TokenObtainPairView
|
||||
@@ -97,16 +100,17 @@ class LoginSerializer(TokenObtainPairSerializer):
|
||||
# 必须重置用户名为username,否则使用邮箱手机号登录会提示密码错误
|
||||
attrs['username'] = user.username
|
||||
data = super().validate(attrs)
|
||||
data["username"] = self.user.username
|
||||
data["name"] = self.user.name
|
||||
data["userId"] = self.user.id
|
||||
data["avatar"] = self.user.avatar
|
||||
data['user_type'] = self.user.user_type
|
||||
data['pwd_change_count'] = self.user.pwd_change_count
|
||||
dept = getattr(self.user, 'dept', None)
|
||||
if dept:
|
||||
data['dept_info'] = {
|
||||
'dept_id': dept.id,
|
||||
'dept_name': dept.name,
|
||||
|
||||
}
|
||||
role = getattr(self.user, 'role', None)
|
||||
if role:
|
||||
@@ -124,6 +128,7 @@ class LoginSerializer(TokenObtainPairSerializer):
|
||||
user.is_active = False
|
||||
user.save()
|
||||
raise CustomValidationError("账号已被锁定,联系管理员解锁")
|
||||
user.save()
|
||||
count = 5 - user.login_error_count
|
||||
raise CustomValidationError(f"账号/密码错误;重试{count}次后将被锁定~")
|
||||
|
||||
|
||||
@@ -120,11 +120,11 @@ class MenuViewSet(CustomModelViewSet):
|
||||
"""用于前端获取当前角色的路由"""
|
||||
user = request.user
|
||||
if user.is_superuser:
|
||||
queryset = self.queryset.filter(status=1)
|
||||
queryset = self.queryset.filter(status=1).order_by("sort")
|
||||
else:
|
||||
role_list = user.role.values_list('id', flat=True)
|
||||
menu_list = RoleMenuPermission.objects.filter(role__in=role_list).values_list('menu_id', flat=True)
|
||||
queryset = Menu.objects.filter(id__in=menu_list)
|
||||
queryset = Menu.objects.filter(id__in=menu_list).order_by("sort")
|
||||
serializer = WebRouterSerializer(queryset, many=True, request=request)
|
||||
data = serializer.data
|
||||
return SuccessResponse(data=data, total=len(data), msg="获取成功")
|
||||
|
||||
@@ -36,6 +36,8 @@ class MessageCenterSerializer(CustomModelSerializer):
|
||||
return serializer.data
|
||||
|
||||
def get_user_info(self, instance, parsed_query):
|
||||
if instance.target_type in (1,2,3):
|
||||
return []
|
||||
users = instance.target_user.all()
|
||||
# You can do what ever you want in here
|
||||
# `parsed_query` param is passed to BookSerializer to allow further querying
|
||||
@@ -106,6 +108,8 @@ class MessageCenterTargetUserListSerializer(CustomModelSerializer):
|
||||
return serializer.data
|
||||
|
||||
def get_user_info(self, instance, parsed_query):
|
||||
if instance.target_type in (1,2,3):
|
||||
return []
|
||||
users = instance.target_user.all()
|
||||
# You can do what ever you want in here
|
||||
# `parsed_query` param is passed to BookSerializer to allow further querying
|
||||
|
||||
@@ -10,22 +10,29 @@ from rest_framework import serializers
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from dvadmin.system.models import Role, Menu, MenuButton, Dept
|
||||
from dvadmin.system.models import Role, Menu, MenuButton, Dept, Users
|
||||
from dvadmin.system.views.dept import DeptSerializer
|
||||
from dvadmin.system.views.menu import MenuSerializer
|
||||
from dvadmin.system.views.menu_button import MenuButtonSerializer
|
||||
from dvadmin.utils.crud_mixin import FastCrudMixin
|
||||
from dvadmin.utils.field_permission import FieldPermissionMixin
|
||||
from dvadmin.utils.json_response import SuccessResponse, DetailResponse
|
||||
from dvadmin.utils.json_response import SuccessResponse, DetailResponse, ErrorResponse
|
||||
from dvadmin.utils.serializers import CustomModelSerializer
|
||||
from dvadmin.utils.validator import CustomUniqueValidator
|
||||
from dvadmin.utils.viewset import CustomModelViewSet
|
||||
from dvadmin.utils.permission import CustomPermission
|
||||
|
||||
|
||||
class RoleSerializer(CustomModelSerializer):
|
||||
"""
|
||||
角色-序列化器
|
||||
"""
|
||||
users = serializers.SerializerMethodField()
|
||||
|
||||
@staticmethod
|
||||
def get_users(instance):
|
||||
users = instance.users_set.exclude(id=1).values('id', 'name', 'dept__name')
|
||||
return users
|
||||
|
||||
class Meta:
|
||||
model = Role
|
||||
@@ -101,7 +108,6 @@ class MenuButtonPermissionSerializer(CustomModelSerializer):
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
|
||||
class RoleViewSet(CustomModelViewSet, FastCrudMixin,FieldPermissionMixin):
|
||||
"""
|
||||
角色管理接口
|
||||
@@ -116,3 +122,82 @@ class RoleViewSet(CustomModelViewSet, FastCrudMixin,FieldPermissionMixin):
|
||||
create_serializer_class = RoleCreateUpdateSerializer
|
||||
update_serializer_class = RoleCreateUpdateSerializer
|
||||
search_fields = ['name', 'key']
|
||||
|
||||
@action(methods=['PUT'], detail=True, permission_classes=[IsAuthenticated])
|
||||
def set_role_users(self, request, pk):
|
||||
"""
|
||||
设置 角色-用户
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
data = request.data
|
||||
direction = data.get('direction')
|
||||
movedKeys = data.get('movedKeys')
|
||||
role = Role.objects.get(pk=pk)
|
||||
if direction == "left":
|
||||
# left : 移除用户权限
|
||||
role.users_set.remove(*movedKeys)
|
||||
else:
|
||||
# right : 添加用户权限
|
||||
role.users_set.add(*movedKeys)
|
||||
serializer = RoleSerializer(role)
|
||||
return DetailResponse(data=serializer.data, msg="更新成功")
|
||||
|
||||
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated, CustomPermission])
|
||||
def get_role_users(self, request):
|
||||
"""
|
||||
获取角色已授权、未授权的用户
|
||||
已授权的用户:1
|
||||
未授权的用户:0
|
||||
"""
|
||||
role_id = request.query_params.get('role_id', None)
|
||||
|
||||
if not role_id:
|
||||
return ErrorResponse(msg="请选择角色")
|
||||
|
||||
if request.query_params.get('authorized', 0) == "1":
|
||||
queryset = Users.objects.filter(role__id=role_id).exclude(is_superuser=True)
|
||||
else:
|
||||
queryset = Users.objects.exclude(role__id=role_id).exclude(is_superuser=True)
|
||||
|
||||
if name := request.query_params.get('name', None):
|
||||
queryset = queryset.filter(name__icontains=name)
|
||||
|
||||
if dept := request.query_params.get('dept', None):
|
||||
queryset = queryset.filter(dept=dept)
|
||||
|
||||
page = self.paginate_queryset(queryset.values('id', 'name', 'dept__name'))
|
||||
if page is not None:
|
||||
return self.get_paginated_response(page)
|
||||
|
||||
return SuccessResponse(data=page)
|
||||
|
||||
@action(methods=['DELETE'], detail=True, permission_classes=[IsAuthenticated, CustomPermission])
|
||||
def remove_role_user(self, request, pk):
|
||||
"""
|
||||
角色-删除用户
|
||||
"""
|
||||
user_id = request.data.get('user_id', None)
|
||||
|
||||
if not user_id:
|
||||
return ErrorResponse(msg="请选择用户")
|
||||
|
||||
role = self.get_object()
|
||||
role.users_set.remove(*user_id)
|
||||
|
||||
return SuccessResponse(msg="删除成功")
|
||||
|
||||
@action(methods=['POST'], detail=True, permission_classes=[IsAuthenticated, CustomPermission])
|
||||
def add_role_users(self, request, pk):
|
||||
"""
|
||||
角色-添加用户
|
||||
"""
|
||||
users_id = request.data.get('users_id', None)
|
||||
|
||||
if not users_id:
|
||||
return ErrorResponse(msg="请选择用户")
|
||||
|
||||
role = self.get_object()
|
||||
role.users_set.add(*users_id)
|
||||
|
||||
return DetailResponse(msg="添加成功")
|
||||
|
||||
@@ -6,24 +6,20 @@
|
||||
@Created on: 2021/6/3 003 0:30
|
||||
@Remark: 菜单按钮管理
|
||||
"""
|
||||
from django.db.models import F, Subquery, OuterRef, Exists, BooleanField, Q, Case, Value, When
|
||||
from django.db.models.functions import Coalesce
|
||||
from rest_framework import serializers
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import ListField
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from dvadmin.system.models import RoleMenuButtonPermission, Menu, MenuButton, Dept, RoleMenuPermission, FieldPermission, \
|
||||
MenuField
|
||||
from dvadmin.system.views.menu import MenuSerializer
|
||||
from dvadmin.utils.json_response import DetailResponse, ErrorResponse
|
||||
from dvadmin.system.models import RoleMenuButtonPermission, Menu, Dept, MenuButton, RoleMenuPermission, \
|
||||
MenuField, FieldPermission
|
||||
from dvadmin.utils.json_response import DetailResponse
|
||||
from dvadmin.utils.serializers import CustomModelSerializer
|
||||
from dvadmin.utils.viewset import CustomModelViewSet
|
||||
|
||||
|
||||
class RoleMenuButtonPermissionSerializer(CustomModelSerializer):
|
||||
"""
|
||||
菜单按钮-序列化器
|
||||
角色-菜单-按钮-权限 查询序列化
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
@@ -34,7 +30,7 @@ class RoleMenuButtonPermissionSerializer(CustomModelSerializer):
|
||||
|
||||
class RoleMenuButtonPermissionCreateUpdateSerializer(CustomModelSerializer):
|
||||
"""
|
||||
初始化菜单按钮-序列化器
|
||||
角色-菜单-按钮-权限 创建/修改序列化
|
||||
"""
|
||||
menu_button__name = serializers.CharField(source='menu_button.name', read_only=True)
|
||||
menu_button__value = serializers.CharField(source='menu_button.value', read_only=True)
|
||||
@@ -45,63 +41,99 @@ class RoleMenuButtonPermissionCreateUpdateSerializer(CustomModelSerializer):
|
||||
read_only_fields = ["id"]
|
||||
|
||||
|
||||
class RoleButtonPermissionSerializer(CustomModelSerializer):
|
||||
class RoleMenuSerializer(CustomModelSerializer):
|
||||
"""
|
||||
角色按钮权限
|
||||
角色-菜单 序列化
|
||||
"""
|
||||
isCheck = serializers.SerializerMethodField()
|
||||
data_range = serializers.SerializerMethodField()
|
||||
|
||||
def get_isCheck(self, instance):
|
||||
params = self.request.query_params
|
||||
data = self.request.data
|
||||
return RoleMenuPermission.objects.filter(
|
||||
menu_id=instance.id,
|
||||
role_id=params.get('roleId', data.get('roleId')),
|
||||
).exists()
|
||||
|
||||
class Meta:
|
||||
model = Menu
|
||||
fields = ["id", "name", "parent", "is_catalog", "isCheck"]
|
||||
|
||||
|
||||
class RoleMenuButtonSerializer(CustomModelSerializer):
|
||||
"""
|
||||
角色-菜单-按钮 序列化
|
||||
"""
|
||||
isCheck = serializers.SerializerMethodField()
|
||||
data_range = serializers.SerializerMethodField()
|
||||
role_menu_btn_perm_id = serializers.SerializerMethodField()
|
||||
dept = serializers.SerializerMethodField()
|
||||
|
||||
def get_isCheck(self, instance):
|
||||
params = self.request.query_params
|
||||
data = self.request.data
|
||||
return RoleMenuButtonPermission.objects.filter(
|
||||
menu_button__id=instance['id'],
|
||||
role__id=params.get('role'),
|
||||
menu_button_id=instance.id,
|
||||
role_id=params.get('roleId', data.get('roleId')),
|
||||
).exists()
|
||||
|
||||
def get_data_range(self, instance):
|
||||
params = self.request.query_params
|
||||
obj = RoleMenuButtonPermission.objects.filter(
|
||||
menu_button__id=instance['id'],
|
||||
role__id=params.get('role'),
|
||||
).first()
|
||||
obj = self.get_role_menu_btn_prem(instance)
|
||||
if obj is None:
|
||||
return None
|
||||
return obj.data_range
|
||||
|
||||
def get_role_menu_btn_perm_id(self, instance):
|
||||
obj = self.get_role_menu_btn_prem(instance)
|
||||
if obj is None:
|
||||
return None
|
||||
return obj.id
|
||||
|
||||
def get_dept(self, instance):
|
||||
obj = self.get_role_menu_btn_prem(instance)
|
||||
if obj is None:
|
||||
return None
|
||||
return obj.dept.all().values_list('id', flat=True)
|
||||
|
||||
def get_role_menu_btn_prem(self, instance):
|
||||
params = self.request.query_params
|
||||
data = self.request.data
|
||||
obj = RoleMenuButtonPermission.objects.filter(
|
||||
menu_button_id=instance.id,
|
||||
role_id=params.get('roleId', data.get('roleId')),
|
||||
).first()
|
||||
return obj
|
||||
|
||||
class Meta:
|
||||
model = MenuButton
|
||||
fields = ['id', 'name', 'value', 'isCheck', 'data_range']
|
||||
|
||||
|
||||
class RoleFieldPermissionSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = FieldPermission
|
||||
fields = "__all__"
|
||||
fields = ['id', 'menu', 'name', 'isCheck', 'data_range', 'role_menu_btn_perm_id', 'dept']
|
||||
|
||||
|
||||
class RoleMenuFieldSerializer(CustomModelSerializer):
|
||||
"""
|
||||
角色-菜单-字段 序列化
|
||||
"""
|
||||
is_query = serializers.SerializerMethodField()
|
||||
is_create = serializers.SerializerMethodField()
|
||||
is_update = serializers.SerializerMethodField()
|
||||
|
||||
def get_is_query(self, instance):
|
||||
params = self.request.query_params
|
||||
queryset = instance.menu_field.filter(role=params.get('role')).first()
|
||||
queryset = instance.menu_field.filter(role=params.get('roleId')).first()
|
||||
if queryset:
|
||||
return queryset.is_query
|
||||
return False
|
||||
|
||||
def get_is_create(self, instance):
|
||||
params = self.request.query_params
|
||||
queryset = instance.menu_field.filter(role=params.get('role')).first()
|
||||
queryset = instance.menu_field.filter(role=params.get('roleId')).first()
|
||||
if queryset:
|
||||
return queryset.is_create
|
||||
return False
|
||||
|
||||
def get_is_update(self, instance):
|
||||
params = self.request.query_params
|
||||
queryset = instance.menu_field.filter(role=params.get('role')).first()
|
||||
queryset = instance.menu_field.filter(role=params.get('roleId')).first()
|
||||
if queryset:
|
||||
return queryset.is_update
|
||||
return False
|
||||
@@ -111,54 +143,6 @@ class RoleMenuFieldSerializer(CustomModelSerializer):
|
||||
fields = ['id', 'field_name', 'title', 'is_query', 'is_create', 'is_update']
|
||||
|
||||
|
||||
class RoleMenuSerializer(CustomModelSerializer):
|
||||
menus = serializers.SerializerMethodField()
|
||||
|
||||
def get_menus(self, instance):
|
||||
menu_list = Menu.objects.filter(parent=instance['id']).values('id', 'name')
|
||||
serializer = RoleMenuPermissionSerializer(menu_list, many=True, request=self.request)
|
||||
return serializer.data
|
||||
|
||||
class Meta:
|
||||
model = Menu
|
||||
fields = ['id', 'name', 'menus']
|
||||
|
||||
|
||||
class RoleMenuPermissionSerializer(CustomModelSerializer):
|
||||
"""
|
||||
菜单和按钮权限
|
||||
"""
|
||||
# name = serializers.SerializerMethodField()
|
||||
isCheck = serializers.SerializerMethodField()
|
||||
btns = serializers.SerializerMethodField()
|
||||
columns = serializers.SerializerMethodField()
|
||||
|
||||
# def get_name(self, instance):
|
||||
# parent_list = Menu.get_all_parent(instance['id'])
|
||||
# names = [d["name"] for d in parent_list]
|
||||
# return "/".join(names)
|
||||
def get_isCheck(self, instance):
|
||||
params = self.request.query_params
|
||||
return RoleMenuPermission.objects.filter(
|
||||
menu__id=instance['id'],
|
||||
role__id=params.get('role'),
|
||||
).exists()
|
||||
|
||||
def get_btns(self, instance):
|
||||
btn_list = MenuButton.objects.filter(menu__id=instance['id']).values('id', 'name', 'value')
|
||||
serializer = RoleButtonPermissionSerializer(btn_list, many=True, request=self.request)
|
||||
return serializer.data
|
||||
|
||||
def get_columns(self, instance):
|
||||
col_list = MenuField.objects.filter(menu=instance['id'])
|
||||
serializer = RoleMenuFieldSerializer(col_list, many=True, request=self.request)
|
||||
return serializer.data
|
||||
|
||||
class Meta:
|
||||
model = Menu
|
||||
fields = ['id', 'name', 'isCheck', 'btns', 'columns']
|
||||
|
||||
|
||||
class RoleMenuButtonPermissionViewSet(CustomModelViewSet):
|
||||
"""
|
||||
菜单按钮接口
|
||||
@@ -174,202 +158,111 @@ class RoleMenuButtonPermissionViewSet(CustomModelViewSet):
|
||||
update_serializer_class = RoleMenuButtonPermissionCreateUpdateSerializer
|
||||
extra_filter_class = []
|
||||
|
||||
# @action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
|
||||
# def get_role_premission(self, request):
|
||||
# """
|
||||
# 角色授权获取:
|
||||
# :param request: role
|
||||
# :return: menu,btns,columns
|
||||
# """
|
||||
# params = request.query_params
|
||||
# is_superuser = request.user.is_superuser
|
||||
# if is_superuser:
|
||||
# queryset = Menu.objects.filter(status=1, is_catalog=True).values('name', 'id').all()
|
||||
# else:
|
||||
# role_id = request.user.role.values_list('id', flat=True)
|
||||
# menu_list = RoleMenuPermission.objects.filter(role__in=role_id).values_list('menu__id', flat=True)
|
||||
# queryset = Menu.objects.filter(status=1, is_catalog=True, id__in=menu_list).values('name', 'id').all()
|
||||
# serializer = RoleMenuSerializer(queryset, many=True, request=request)
|
||||
# data = serializer.data
|
||||
# return DetailResponse(data=data)
|
||||
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
|
||||
def get_role_menu(self, request):
|
||||
"""
|
||||
获取 角色-菜单
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
menu_queryset = Menu.objects.all()
|
||||
serializer = RoleMenuSerializer(menu_queryset, many=True, request=request)
|
||||
return DetailResponse(data=serializer.data)
|
||||
|
||||
@action(methods=['PUT'], detail=False, permission_classes=[IsAuthenticated])
|
||||
def set_role_menu(self, request):
|
||||
"""
|
||||
设置 角色-菜单
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
data = request.data
|
||||
roleId = data.get('roleId')
|
||||
menuId = data.get('menuId')
|
||||
isCheck = data.get('isCheck')
|
||||
if isCheck:
|
||||
# 添加权限:创建关联记录
|
||||
instance = RoleMenuPermission.objects.create(role_id=roleId, menu_id=menuId)
|
||||
else:
|
||||
# 删除权限:移除关联记录
|
||||
RoleMenuPermission.objects.filter(role_id=roleId, menu_id=menuId).delete()
|
||||
menu_instance = Menu.objects.get(id=menuId)
|
||||
serializer = RoleMenuSerializer(menu_instance, request=request)
|
||||
return DetailResponse(data=serializer.data, msg="更新成功")
|
||||
|
||||
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
|
||||
def get_role_permission(self, request):
|
||||
def get_role_menu_btn_field(self, request):
|
||||
"""
|
||||
获取 角色-菜单-按钮-列字段
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
params = request.query_params
|
||||
# 需要授权的角色信息
|
||||
current_role = params.get('role', None)
|
||||
# 当前登录用户的角色
|
||||
role_list = request.user.role.values_list('id', flat=True)
|
||||
if current_role is None:
|
||||
return ErrorResponse(msg='参数错误')
|
||||
is_superuser = request.user.is_superuser
|
||||
if is_superuser:
|
||||
menu_queryset = Menu.objects.prefetch_related('menuPermission').prefetch_related(
|
||||
'menufield_set')
|
||||
else:
|
||||
role_id_list = request.user.role.values_list('id', flat=True)
|
||||
menu_list = RoleMenuPermission.objects.filter(role__in=role_id_list).values_list('menu__id', flat=True)
|
||||
|
||||
# 当前角色已授权的菜单
|
||||
menu_queryset = Menu.objects.filter(id__in=menu_list).prefetch_related('menuPermission').prefetch_related(
|
||||
'menufield_set')
|
||||
result = []
|
||||
for menu_item in menu_queryset:
|
||||
isCheck = RoleMenuPermission.objects.filter(
|
||||
menu_id=menu_item.id,
|
||||
role_id=current_role
|
||||
).exists()
|
||||
dicts = {
|
||||
'name': menu_item.name,
|
||||
'id': menu_item.id,
|
||||
'parent': menu_item.parent.id if menu_item.parent else None,
|
||||
'isCheck': isCheck,
|
||||
'btns': [],
|
||||
'columns': []
|
||||
}
|
||||
for mb_item in menu_item.menuPermission.all():
|
||||
rolemenubuttonpermission_queryset = RoleMenuButtonPermission.objects.filter(
|
||||
menu_button_id=mb_item.id,
|
||||
role_id=current_role
|
||||
).first()
|
||||
dicts['btns'].append(
|
||||
{
|
||||
'id': mb_item.id,
|
||||
'name': mb_item.name,
|
||||
'value': mb_item.value,
|
||||
'data_range': rolemenubuttonpermission_queryset.data_range
|
||||
if rolemenubuttonpermission_queryset
|
||||
else None,
|
||||
'isCheck': bool(rolemenubuttonpermission_queryset),
|
||||
'dept': rolemenubuttonpermission_queryset.dept.all().values_list('id', flat=True)
|
||||
if rolemenubuttonpermission_queryset
|
||||
else [],
|
||||
}
|
||||
)
|
||||
for column_item in menu_item.menufield_set.all():
|
||||
# 需要授权角色已拥有的列权限
|
||||
fieldpermission_queryset = column_item.menu_field.filter(role_id=current_role).first()
|
||||
is_query = fieldpermission_queryset.is_query if fieldpermission_queryset else False
|
||||
is_create = fieldpermission_queryset.is_create if fieldpermission_queryset else False
|
||||
is_update = fieldpermission_queryset.is_update if fieldpermission_queryset else False
|
||||
# 当前登录用户角色可分配的列权限
|
||||
fieldpermission_queryset_disabled = column_item.menu_field.filter(role_id__in=role_list).first()
|
||||
disabled_query = fieldpermission_queryset_disabled.is_query if fieldpermission_queryset_disabled else True
|
||||
disabled_create = fieldpermission_queryset_disabled.is_create if fieldpermission_queryset_disabled else True
|
||||
disabled_update = fieldpermission_queryset_disabled.is_update if fieldpermission_queryset_disabled else True
|
||||
|
||||
dicts['columns'].append({
|
||||
'id': column_item.id,
|
||||
'field_name': column_item.field_name,
|
||||
'title': column_item.title,
|
||||
'is_query': is_query,
|
||||
'is_create': is_create,
|
||||
'is_update': is_update,
|
||||
'disabled_query': False if is_superuser else not disabled_query,
|
||||
'disabled_create': False if is_superuser else not disabled_create,
|
||||
'disabled_update': False if is_superuser else not disabled_update,
|
||||
})
|
||||
result.append(dicts)
|
||||
return DetailResponse(data=result)
|
||||
menuId = params.get('menuId', None)
|
||||
menu_btn_queryset = MenuButton.objects.filter(menu_id=menuId)
|
||||
menu_btn_serializer = RoleMenuButtonSerializer(menu_btn_queryset, many=True, request=request)
|
||||
menu_field_queryset = MenuField.objects.filter(menu_id=menuId)
|
||||
menu_field_serializer = RoleMenuFieldSerializer(menu_field_queryset, many=True, request=request)
|
||||
return DetailResponse(data={'menu_btn': menu_btn_serializer.data, 'menu_field': menu_field_serializer.data})
|
||||
|
||||
@action(methods=['PUT'], detail=True, permission_classes=[IsAuthenticated])
|
||||
def set_role_premission(self, request, pk):
|
||||
def set_role_menu_field(self, request, pk):
|
||||
"""
|
||||
对角色的菜单和按钮及按钮范围授权:
|
||||
:param request:
|
||||
:param pk: role
|
||||
:return:
|
||||
设置 角色-菜单-列字段
|
||||
"""
|
||||
body = request.data
|
||||
RoleMenuPermission.objects.filter(role=pk).delete()
|
||||
RoleMenuButtonPermission.objects.filter(role=pk).delete()
|
||||
for item in body:
|
||||
if item.get('isCheck'):
|
||||
RoleMenuPermission.objects.create(role_id=pk, menu_id=item["id"])
|
||||
for btn in item.get('btns'):
|
||||
if btn.get('isCheck'):
|
||||
data_range = btn.get('data_range', 0) or 0
|
||||
instance = RoleMenuButtonPermission.objects.create(role_id=pk, menu_button_id=btn.get('id'),
|
||||
data_range=data_range)
|
||||
instance.dept.set(btn.get('dept', []))
|
||||
for col in item.get('columns'):
|
||||
FieldPermission.objects.update_or_create(role_id=pk, field_id=col.get('id'),
|
||||
defaults={
|
||||
'is_query': col.get('is_query'),
|
||||
'is_create': col.get('is_create'),
|
||||
'is_update': col.get('is_update')
|
||||
})
|
||||
return DetailResponse(msg="授权成功")
|
||||
data = request.data
|
||||
for col in data:
|
||||
FieldPermission.objects.update_or_create(
|
||||
role_id=pk, field_id=col.get('id'),
|
||||
defaults={
|
||||
'is_create': col.get('is_create'),
|
||||
'is_update': col.get('is_update'),
|
||||
'is_query': col.get('is_query'),
|
||||
})
|
||||
|
||||
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
|
||||
def role_menu_get_button(self, request):
|
||||
"""
|
||||
当前用户角色和菜单获取可下拉选项的按钮:角色授权页面使用
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
if params := request.query_params:
|
||||
if menu_id := params.get('menu', None):
|
||||
is_superuser = request.user.is_superuser
|
||||
if is_superuser:
|
||||
queryset = MenuButton.objects.filter(menu=menu_id).values('id', 'name')
|
||||
else:
|
||||
role_list = request.user.role.values_list('id', flat=True)
|
||||
queryset = RoleMenuButtonPermission.objects.filter(
|
||||
role__in=role_list, menu_button__menu=menu_id
|
||||
).values(btn_id=F('menu_button__id'), name=F('menu_button__name'))
|
||||
return DetailResponse(data=queryset)
|
||||
return ErrorResponse(msg="参数错误")
|
||||
return DetailResponse(data=[], msg="更新成功")
|
||||
|
||||
@action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
|
||||
def data_scope(self, request):
|
||||
@action(methods=['PUT'], detail=False, permission_classes=[IsAuthenticated])
|
||||
def set_role_menu_btn(self, request):
|
||||
"""
|
||||
获取数据权限范围:角色授权页面使用
|
||||
:param request:
|
||||
:return:
|
||||
设置 角色-菜单-按钮
|
||||
"""
|
||||
is_superuser = request.user.is_superuser
|
||||
if is_superuser:
|
||||
data = [
|
||||
{"value": 0, "label": '仅本人数据权限'},
|
||||
{"value": 1, "label": '本部门及以下数据权限'},
|
||||
{"value": 2, "label": '本部门数据权限'},
|
||||
{"value": 3, "label": '全部数据权限'},
|
||||
{"value": 4, "label": '自定义数据权限'}
|
||||
]
|
||||
return DetailResponse(data=data)
|
||||
data = request.data
|
||||
isCheck = data.get('isCheck', None)
|
||||
roleId = data.get('roleId', None)
|
||||
btnId = data.get('btnId', None)
|
||||
data_range = data.get('data_range', None) or 0 # 默认仅本人权限
|
||||
dept = data.get('dept', None) or [] # 默认空部门
|
||||
|
||||
if isCheck:
|
||||
# 添加权限:创建关联记录
|
||||
instance = RoleMenuButtonPermission.objects.create(role_id=roleId,
|
||||
menu_button_id=btnId,
|
||||
data_range=data_range)
|
||||
# 自定义部门权限
|
||||
if data_range == 4 and dept:
|
||||
instance.dept.set(dept)
|
||||
else:
|
||||
params = request.query_params
|
||||
data = [{"value": 0, "label": '仅本人数据权限'}]
|
||||
role_list = request.user.role.values_list('id', flat=True)
|
||||
# 权限页面进入初始化获取所有的数据权限范围
|
||||
role_queryset = RoleMenuButtonPermission.objects.filter(
|
||||
role__in=role_list
|
||||
).values_list('data_range', flat=True)
|
||||
# 通过按钮小齿轮获取指定按钮的权限
|
||||
if menu_button_id := params.get('menu_button', None):
|
||||
role_queryset = RoleMenuButtonPermission.objects.filter(
|
||||
role__in=role_list, menu_button__id=menu_button_id
|
||||
).values_list('data_range', flat=True)
|
||||
# 删除权限:移除关联记录
|
||||
RoleMenuButtonPermission.objects.filter(role_id=roleId, menu_button_id=btnId).delete()
|
||||
menu_btn_instance = MenuButton.objects.get(id=btnId)
|
||||
serializer = RoleMenuButtonSerializer(menu_btn_instance, request=request)
|
||||
return DetailResponse(data=serializer.data, msg="更新成功")
|
||||
|
||||
data_range_list = list(set(role_queryset))
|
||||
for item in data_range_list:
|
||||
if item == 0:
|
||||
data = data
|
||||
elif item == 1:
|
||||
data.extend([
|
||||
{"value": 1, "label": '本部门及以下数据权限'},
|
||||
{"value": 2, "label": '本部门数据权限'}
|
||||
])
|
||||
elif item == 2:
|
||||
data.extend([{"value": 2, "label": '本部门数据权限'}])
|
||||
elif item == 3:
|
||||
data.extend([{"value": 3, "label": '全部数据权限'}])
|
||||
elif item == 4:
|
||||
data.extend([{"value": 4, "label": '自定义数据权限'}])
|
||||
else:
|
||||
data = []
|
||||
return DetailResponse(data=data)
|
||||
@action(methods=['PUT'], detail=False, permission_classes=[IsAuthenticated])
|
||||
def set_role_menu_btn_data_range(self, request):
|
||||
"""
|
||||
设置 角色-菜单-按钮-权限
|
||||
"""
|
||||
data = request.data
|
||||
instance = RoleMenuButtonPermission.objects.get(id=data.get('role_menu_btn_perm_id'))
|
||||
instance.data_range = data.get('data_range')
|
||||
instance.dept.add(*data.get('dept'))
|
||||
if not data.get('dept'):
|
||||
instance.dept.clear()
|
||||
instance.save()
|
||||
serializer = RoleMenuButtonPermissionSerializer(instance, request=request)
|
||||
return DetailResponse(data=serializer.data, msg="更新成功")
|
||||
|
||||
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated])
|
||||
def role_to_dept_all(self, request):
|
||||
@@ -395,55 +288,3 @@ class RoleMenuButtonPermissionViewSet(CustomModelViewSet):
|
||||
dept["disabled"] = False if is_superuser else dept["id"] not in dept_checked_disabled
|
||||
data.append(dept)
|
||||
return DetailResponse(data=data)
|
||||
|
||||
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated])
|
||||
def menu_to_button(self, request):
|
||||
"""
|
||||
根据所选择菜单获取已配置的按钮/接口权限:角色授权页面使用
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
params = request.query_params
|
||||
menu_id = params.get('menu', None)
|
||||
if menu_id is None:
|
||||
return ErrorResponse(msg="未获取到参数")
|
||||
is_superuser = request.user.is_superuser
|
||||
if is_superuser:
|
||||
queryset = RoleMenuButtonPermission.objects.filter(menu_button__menu=menu_id).values(
|
||||
'id',
|
||||
'data_range',
|
||||
'menu_button',
|
||||
'menu_button__name',
|
||||
'menu_button__value'
|
||||
)
|
||||
return DetailResponse(data=queryset)
|
||||
else:
|
||||
if params:
|
||||
|
||||
role_id = params.get('role', None)
|
||||
if role_id is None:
|
||||
return ErrorResponse(msg="未获取到参数")
|
||||
queryset = RoleMenuButtonPermission.objects.filter(role=role_id, menu_button__menu=menu_id).values(
|
||||
'id',
|
||||
'data_range',
|
||||
'menu_button',
|
||||
'menu_button__name',
|
||||
'menu_button__value'
|
||||
)
|
||||
return DetailResponse(data=queryset)
|
||||
return ErrorResponse(msg="未获取到参数")
|
||||
|
||||
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated])
|
||||
def role_to_menu(self, request):
|
||||
"""
|
||||
获取角色对应的按钮权限
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
params = request.query_params
|
||||
role_id = params.get('role', None)
|
||||
if role_id is None:
|
||||
return ErrorResponse(msg="未获取到参数")
|
||||
queryset = RoleMenuPermission.objects.filter(role_id=role_id).values_list('menu_id', flat=True).distinct()
|
||||
|
||||
return DetailResponse(data=queryset)
|
||||
|
||||
@@ -286,6 +286,7 @@ class UserViewSet(CustomModelViewSet):
|
||||
"dept": user.dept_id,
|
||||
"is_superuser": user.is_superuser,
|
||||
"role": user.role.values_list('id', flat=True),
|
||||
"pwd_change_count":user.pwd_change_count
|
||||
}
|
||||
if hasattr(connection, 'tenant'):
|
||||
result['tenant_id'] = connection.tenant and connection.tenant.id
|
||||
@@ -319,7 +320,6 @@ class UserViewSet(CustomModelViewSet):
|
||||
"""密码修改"""
|
||||
data = request.data
|
||||
old_pwd = data.get("oldPassword")
|
||||
print(old_pwd)
|
||||
new_pwd = data.get("newPassword")
|
||||
new_pwd2 = data.get("newPassword2")
|
||||
if old_pwd is None or new_pwd is None or new_pwd2 is None:
|
||||
@@ -330,13 +330,33 @@ class UserViewSet(CustomModelViewSet):
|
||||
if not verify_password:
|
||||
old_pwd_md5 = hashlib.md5(old_pwd.encode(encoding='UTF-8')).hexdigest()
|
||||
verify_password = check_password(str(old_pwd_md5), request.user.password)
|
||||
# 创建用户时、自定义密码无法修改问题
|
||||
if not verify_password:
|
||||
old_pwd_md5 = hashlib.md5(old_pwd_md5.encode(encoding='UTF-8')).hexdigest()
|
||||
verify_password = check_password(str(old_pwd_md5), request.user.password)
|
||||
if verify_password:
|
||||
# request.user.password = make_password(hashlib.md5(new_pwd.encode(encoding='UTF-8')).hexdigest())
|
||||
request.user.password = make_password(hashlib.md5(new_pwd.encode(encoding='UTF-8')).hexdigest())
|
||||
request.user.pwd_change_count += 1
|
||||
request.user.save()
|
||||
return DetailResponse(data=None, msg="修改成功")
|
||||
else:
|
||||
return ErrorResponse(msg="旧密码不正确")
|
||||
|
||||
@action(methods=["post"], detail=False, permission_classes=[IsAuthenticated])
|
||||
def login_change_password(self, request, *args, **kwargs):
|
||||
"""初次登录进行密码修改"""
|
||||
data = request.data
|
||||
new_pwd = data.get("password")
|
||||
new_pwd2 = data.get("password_regain")
|
||||
if new_pwd != new_pwd2:
|
||||
return ErrorResponse(msg="两次密码不匹配")
|
||||
else:
|
||||
request.user.password = make_password(new_pwd)
|
||||
request.user.pwd_change_count += 1
|
||||
request.user.save()
|
||||
return DetailResponse(data=None, msg="修改成功")
|
||||
|
||||
@action(methods=["PUT"], detail=True, permission_classes=[IsAuthenticated])
|
||||
def reset_to_default_password(self, request,pk):
|
||||
"""恢复默认密码"""
|
||||
|
||||
@@ -5,34 +5,39 @@ from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from dvadmin.system.models import FieldPermission, MenuField
|
||||
from dvadmin.utils.json_response import DetailResponse
|
||||
from dvadmin.utils.models import get_custom_app_models
|
||||
|
||||
|
||||
def merge_permission(data):
|
||||
"""
|
||||
合并权限
|
||||
"""
|
||||
result = {}
|
||||
for item in data:
|
||||
field_name = item.pop('field_name')
|
||||
if field_name not in result:
|
||||
result[field_name] = item
|
||||
else:
|
||||
for key, value in item.items():
|
||||
result[field_name][key] = result[field_name][key] or value
|
||||
return result
|
||||
|
||||
|
||||
class FieldPermissionMixin:
|
||||
@action(methods=['get'], detail=False,permission_classes=[IsAuthenticated])
|
||||
@action(methods=['get'], detail=False, permission_classes=[IsAuthenticated])
|
||||
def field_permission(self, request):
|
||||
"""
|
||||
获取字段权限
|
||||
"""
|
||||
finded = False
|
||||
for model in get_custom_app_models():
|
||||
if model['object'] is self.serializer_class.Meta.model:
|
||||
finded = True
|
||||
break
|
||||
if finded:
|
||||
break
|
||||
if finded is False:
|
||||
return []
|
||||
model = self.serializer_class.Meta.model.__name__
|
||||
user = request.user
|
||||
if user.is_superuser==1:
|
||||
data = MenuField.objects.filter( model=model['model']).values('field_name')
|
||||
for item in data:
|
||||
item['is_create'] = True
|
||||
item['is_query'] = True
|
||||
item['is_update'] = True
|
||||
# 创建一个默认字典来存储最终的结果
|
||||
if user.is_superuser == 1:
|
||||
data = MenuField.objects.filter(model=model).values('field_name')
|
||||
result = {item['field_name']: {"is_create": True, "is_query": True, "is_update": True} for item in data}
|
||||
else:
|
||||
roles = request.user.role.values_list('id', flat=True)
|
||||
data= FieldPermission.objects.filter(
|
||||
field__model=model['model'],role__in=roles
|
||||
).values( 'is_create', 'is_query', 'is_update',field_name=F('field__field_name'))
|
||||
return DetailResponse(data=data)
|
||||
data = FieldPermission.objects.filter(
|
||||
field__model=model, role__in=roles
|
||||
).values('is_create', 'is_query', 'is_update', field_name=F('field__field_name'))
|
||||
result = merge_permission(data)
|
||||
return DetailResponse(data=result)
|
||||
|
||||
@@ -22,7 +22,7 @@ from django_filters.rest_framework import DjangoFilterBackend
|
||||
from django_filters.utils import get_model_field
|
||||
from rest_framework.filters import BaseFilterBackend
|
||||
from django_filters.conf import settings
|
||||
from dvadmin.system.models import Dept, ApiWhiteList, RoleMenuButtonPermission
|
||||
from dvadmin.system.models import Dept, ApiWhiteList, RoleMenuButtonPermission, MenuButton
|
||||
from dvadmin.utils.models import CoreModel
|
||||
|
||||
class CoreModelFilterBankend(BaseFilterBackend):
|
||||
@@ -33,15 +33,15 @@ class CoreModelFilterBankend(BaseFilterBackend):
|
||||
create_datetime_after = request.query_params.get('create_datetime_after', None)
|
||||
create_datetime_before = request.query_params.get('create_datetime_before', None)
|
||||
update_datetime_after = request.query_params.get('update_datetime_after', None)
|
||||
update_datetime_before = request.query_params.get('update_datetime_after', None)
|
||||
update_datetime_before = request.query_params.get('update_datetime_before', None)
|
||||
if any([create_datetime_after, create_datetime_before, update_datetime_after, update_datetime_before]):
|
||||
create_filter = Q()
|
||||
if create_datetime_after and create_datetime_before:
|
||||
create_filter &= Q(create_datetime__gte=create_datetime_after) & Q(create_datetime__lte=create_datetime_before)
|
||||
create_filter &= Q(create_datetime__gte=create_datetime_after) & Q(create_datetime__lte=f'{create_datetime_before} 23:59:59')
|
||||
elif create_datetime_after:
|
||||
create_filter &= Q(create_datetime__gte=create_datetime_after)
|
||||
elif create_datetime_before:
|
||||
create_filter &= Q(create_datetime__lte=create_datetime_before)
|
||||
create_filter &= Q(create_datetime__lte=f'{create_datetime_before} 23:59:59')
|
||||
|
||||
# 更新时间范围过滤条件
|
||||
update_filter = Q()
|
||||
@@ -149,13 +149,16 @@ class DataLevelPermissionsFilter(BaseFilterBackend):
|
||||
if _pk: # 判断是否是单例查询
|
||||
re_api = re.sub(_pk,'{id}', api)
|
||||
role_id_list = request.user.role.values_list('id', flat=True)
|
||||
role_permission_list=RoleMenuButtonPermission.objects.filter(
|
||||
role__in=role_id_list,
|
||||
role__status=1,
|
||||
menu_button__api=re_api,
|
||||
menu_button__method=method).values(
|
||||
'data_range'
|
||||
)
|
||||
# 修复权限获取bug
|
||||
menu_button_ids = MenuButton.objects.filter(api=re_api,method=method).values_list('id', flat=True)
|
||||
role_permission_list = []
|
||||
if menu_button_ids:
|
||||
role_permission_list=RoleMenuButtonPermission.objects.filter(
|
||||
role__in=role_id_list,
|
||||
role__status=1,
|
||||
menu_button_id__in=menu_button_ids).values(
|
||||
'data_range'
|
||||
)
|
||||
dataScope_list = [] # 权限范围列表
|
||||
for ele in role_permission_list:
|
||||
# 判断用户是否为超级管理员角色/如果拥有[全部数据权限]则返回所有数据
|
||||
@@ -340,7 +343,7 @@ class CustomDjangoFilterBackend(DjangoFilterBackend):
|
||||
from timezone_field import TimeZoneField
|
||||
|
||||
# 不进行 过滤的model 类
|
||||
if isinstance(field, (models.JSONField, TimeZoneField)):
|
||||
if isinstance(field, (models.JSONField, TimeZoneField, models.FileField)):
|
||||
continue
|
||||
# warn if the field doesn't exist.
|
||||
if field is None:
|
||||
|
||||
@@ -86,4 +86,5 @@ def import_to_data(file_url, field_data, m2m_fields=None):
|
||||
else:
|
||||
array[key] = cell_value
|
||||
tables.append(array)
|
||||
return tables
|
||||
data = [i for i in tables if len(i) != 0]
|
||||
return data
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from urllib.parse import quote
|
||||
|
||||
from django.db import transaction
|
||||
@@ -11,8 +12,10 @@ from rest_framework.decorators import action
|
||||
from rest_framework.request import Request
|
||||
|
||||
from dvadmin.utils.import_export import import_to_data
|
||||
from dvadmin.utils.json_response import DetailResponse
|
||||
from dvadmin.utils.json_response import DetailResponse, SuccessResponse
|
||||
from dvadmin.utils.request_util import get_verbose_name
|
||||
from dvadmin.system.tasks import async_export_data
|
||||
from dvadmin.system.models import DownloadCenter
|
||||
|
||||
|
||||
class ImportSerializerMixin:
|
||||
@@ -301,6 +304,16 @@ class ExportSerializerMixin:
|
||||
assert self.export_field_label, "'%s' 请配置对应的导出模板字段。" % self.__class__.__name__
|
||||
assert self.export_serializer_class, "'%s' 请配置对应的导出序列化器。" % self.__class__.__name__
|
||||
data = self.export_serializer_class(queryset, many=True, request=request).data
|
||||
try:
|
||||
async_export_data.delay(
|
||||
data,
|
||||
str(f"导出{get_verbose_name(queryset)}-{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}.xlsx"),
|
||||
DownloadCenter.objects.create(creator=request.user, task_name=f'{get_verbose_name(queryset)}数据导出任务', dept_belong_id=request.user.dept_id).pk,
|
||||
self.export_field_label
|
||||
)
|
||||
return SuccessResponse(msg="导入任务已创建,请前往‘下载中心’等待下载")
|
||||
except:
|
||||
pass
|
||||
# 导出excel 表
|
||||
response = HttpResponse(content_type="application/msexcel")
|
||||
response["Access-Control-Expose-Headers"] = f"Content-Disposition"
|
||||
|
||||
@@ -32,6 +32,14 @@ class ApiLoggingMiddleware(MiddlewareMixin):
|
||||
request.request_path = get_request_path(request)
|
||||
|
||||
def __handle_response(self, request, response):
|
||||
|
||||
# 判断有无log_id属性,使用All记录时,会出现此情况
|
||||
if request.request_data.get('log_id', None) is None:
|
||||
return
|
||||
|
||||
# 移除log_id,不记录此ID
|
||||
log_id = request.request_data.pop('log_id')
|
||||
|
||||
# request_data,request_ip由PermissionInterfaceMiddleware中间件中添加的属性
|
||||
body = getattr(request, 'request_data', {})
|
||||
# 请求含有password则用*替换掉(暂时先用于所有接口的password请求参数)
|
||||
@@ -60,7 +68,7 @@ class ApiLoggingMiddleware(MiddlewareMixin):
|
||||
'status': True if response.data.get('code') in [2000, ] else False,
|
||||
'json_result': {"code": response.data.get('code'), "msg": response.data.get('msg')},
|
||||
}
|
||||
operation_log, creat = OperationLog.objects.update_or_create(defaults=info, id=self.operation_log_id)
|
||||
operation_log, creat = OperationLog.objects.update_or_create(defaults=info, id=log_id)
|
||||
if not operation_log.request_modular and settings.API_MODEL_MAP.get(request.request_path, None):
|
||||
operation_log.request_modular = settings.API_MODEL_MAP[request.request_path]
|
||||
operation_log.save()
|
||||
@@ -71,7 +79,8 @@ class ApiLoggingMiddleware(MiddlewareMixin):
|
||||
if self.methods == 'ALL' or request.method in self.methods:
|
||||
log = OperationLog(request_modular=get_verbose_name(view_func.cls.queryset))
|
||||
log.save()
|
||||
self.operation_log_id = log.id
|
||||
# self.operation_log_id = log.id
|
||||
request.request_data['log_id'] = log.id
|
||||
|
||||
return
|
||||
|
||||
|
||||
@@ -61,8 +61,24 @@ class SoftDeleteModel(models.Model):
|
||||
"""
|
||||
重写删除方法,直接开启软删除
|
||||
"""
|
||||
self.is_deleted = True
|
||||
self.save(using=using)
|
||||
if soft_delete:
|
||||
self.is_deleted = True
|
||||
self.save(using=using)
|
||||
# 级联软删除关联对象
|
||||
for related_object in self._meta.related_objects:
|
||||
related_model = getattr(self, related_object.get_accessor_name())
|
||||
# 处理一对多和多对多的关联对象
|
||||
if related_object.one_to_many or related_object.many_to_many:
|
||||
related_objects = related_model.all()
|
||||
elif related_object.one_to_one:
|
||||
related_objects = [related_model]
|
||||
else:
|
||||
continue
|
||||
|
||||
for obj in related_objects:
|
||||
obj.delete(soft_delete=True)
|
||||
else:
|
||||
super().delete(using=using, *args, **kwargs)
|
||||
|
||||
|
||||
class CoreModel(models.Model):
|
||||
@@ -216,9 +232,13 @@ def get_all_models_objects(model_name=None):
|
||||
def get_model_from_app(app_name):
|
||||
"""获取模型里的字段"""
|
||||
model_module = import_module(app_name + '.models')
|
||||
exclude_models = getattr(model_module, 'exclude_models', [])
|
||||
filter_model = [
|
||||
getattr(model_module, item) for item in dir(model_module)
|
||||
if item != 'CoreModel' and issubclass(getattr(model_module, item).__class__, models.base.ModelBase)
|
||||
value for key, value in model_module.__dict__.items()
|
||||
if key != 'CoreModel'
|
||||
and isinstance(value, type)
|
||||
and issubclass(value, models.Model)
|
||||
and key not in exclude_models
|
||||
]
|
||||
model_list = []
|
||||
for model in filter_model:
|
||||
|
||||
@@ -44,6 +44,35 @@ class AnonymousUserPermission(BasePermission):
|
||||
return True
|
||||
|
||||
|
||||
class SuperuserPermission(BasePermission):
|
||||
"""
|
||||
超级管理员权限类
|
||||
"""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
if isinstance(request.user, AnonymousUser):
|
||||
return False
|
||||
# 判断是否是超级管理员
|
||||
if request.user.is_superuser:
|
||||
return True
|
||||
|
||||
|
||||
class AdminPermission(BasePermission):
|
||||
"""
|
||||
普通管理员权限类
|
||||
"""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
if isinstance(request.user, AnonymousUser):
|
||||
return False
|
||||
# 判断是否是超级管理员
|
||||
is_superuser = request.user.is_superuser
|
||||
# 判断是否是管理员角色
|
||||
is_admin = request.user.role.values_list('admin', flat=True)
|
||||
if is_superuser or True in is_admin:
|
||||
return True
|
||||
|
||||
|
||||
def ReUUID(api):
|
||||
"""
|
||||
将接口的uuid替换掉
|
||||
@@ -81,8 +110,9 @@ class CustomPermission(BasePermission):
|
||||
# ********#
|
||||
if not hasattr(request.user, "role"):
|
||||
return False
|
||||
role_id_list = request.user.role.values_list('id',flat=True)
|
||||
userApiList = RoleMenuButtonPermission.objects.filter(role__in=role_id_list).values(permission__api=F('menu_button__api'), permission__method=F('menu_button__method')) # 获取当前用户的角色拥有的所有接口
|
||||
role_id_list = request.user.role.values_list('id', flat=True)
|
||||
userApiList = RoleMenuButtonPermission.objects.filter(role__in=role_id_list).values(
|
||||
permission__api=F('menu_button__api'), permission__method=F('menu_button__method')) # 获取当前用户的角色拥有的所有接口
|
||||
ApiList = [
|
||||
str(item.get('permission__api').replace('{id}', '([a-zA-Z0-9-]+)')) + ":" + str(
|
||||
item.get('permission__method')) + '$' for item in userApiList if item.get('permission__api')]
|
||||
|
||||
@@ -26,7 +26,6 @@ class CustomModelSerializer(DynamicFieldsMixin, ModelSerializer):
|
||||
# 修改人的审计字段名称, 默认modifier, 继承使用时可自定义覆盖
|
||||
modifier_field_id = "modifier"
|
||||
modifier_name = serializers.SerializerMethodField(read_only=True)
|
||||
dept_belong_id = serializers.IntegerField(required=False, allow_null=True)
|
||||
|
||||
def get_modifier_name(self, instance):
|
||||
if not hasattr(instance, "modifier"):
|
||||
@@ -52,7 +51,7 @@ class CustomModelSerializer(DynamicFieldsMixin, ModelSerializer):
|
||||
format="%Y-%m-%d %H:%M:%S", required=False, read_only=True
|
||||
)
|
||||
update_datetime = serializers.DateTimeField(
|
||||
format="%Y-%m-%d %H:%M:%S", required=False
|
||||
format="%Y-%m-%d %H:%M:%S", required=False, read_only=True
|
||||
)
|
||||
|
||||
def __init__(self, instance=None, data=empty, request=None, **kwargs):
|
||||
@@ -71,11 +70,11 @@ class CustomModelSerializer(DynamicFieldsMixin, ModelSerializer):
|
||||
validated_data[self.creator_field_id] = self.request.user
|
||||
|
||||
if (
|
||||
self.dept_belong_id_field_name in self.fields.fields
|
||||
and validated_data.get(self.dept_belong_id_field_name, None) is None
|
||||
self.dept_belong_id_field_name in self.fields.fields
|
||||
and validated_data.get(self.dept_belong_id_field_name, None) is None
|
||||
):
|
||||
validated_data[self.dept_belong_id_field_name] = getattr(
|
||||
self.request.user, "dept_id", None
|
||||
self.request.user, "dept_id", validated_data.get(self.dept_belong_id_field_name, None)
|
||||
)
|
||||
return super().create(validated_data)
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
@Created on: 2021/6/1 001 22:57
|
||||
@Remark: 自定义视图集
|
||||
"""
|
||||
import copy
|
||||
|
||||
from django.db import transaction
|
||||
from django_filters import DateTimeFromToRangeFilter
|
||||
from django_filters.rest_framework import FilterSet
|
||||
@@ -67,12 +69,14 @@ class CustomModelViewSet(ModelViewSet, ImportSerializerMixin, ExportSerializerMi
|
||||
kwargs.setdefault('context', self.get_serializer_context())
|
||||
# 全部以可见字段为准
|
||||
can_see = self.get_menu_field(serializer_class)
|
||||
# 排除掉序列化器级的字段
|
||||
# sub_set = set(serializer_class._declared_fields.keys()) - set(can_see)
|
||||
# for field in sub_set:
|
||||
# serializer_class._declared_fields.pop(field)
|
||||
# 排除掉序列化器级的字段(排除字段权限中未授权的字段)
|
||||
# if not self.request.user.is_superuser:
|
||||
# serializer_class.Meta.fields = can_see
|
||||
# exclude_set = set(serializer_class._declared_fields.keys()) - set(can_see)
|
||||
# for field in exclude_set:
|
||||
# serializer_class._declared_fields.pop(field)
|
||||
# meta = copy.deepcopy(serializer_class.Meta)
|
||||
# meta.fields = list(can_see)
|
||||
# serializer_class.Meta = meta
|
||||
# 在分页器中使用
|
||||
self.request.permission_fields = can_see
|
||||
if isinstance(self.request.data, list):
|
||||
@@ -83,15 +87,17 @@ class CustomModelViewSet(ModelViewSet, ImportSerializerMixin, ExportSerializerMi
|
||||
|
||||
def get_menu_field(self, serializer_class):
|
||||
"""获取字段权限"""
|
||||
finded = False
|
||||
for model in get_custom_app_models():
|
||||
if model['object'] is serializer_class.Meta.model:
|
||||
finded = True
|
||||
break
|
||||
if finded is False:
|
||||
|
||||
if not any(model['object'] is serializer_class.Meta.model for model in get_custom_app_models()):
|
||||
return []
|
||||
return MenuField.objects.filter(model=model['model']
|
||||
).values('field_name', 'title')
|
||||
|
||||
# 匿名用户没有角色
|
||||
ret = FieldPermission.objects.filter(field__model=serializer_class.Meta.model.__name__)
|
||||
if hasattr(self.request.user, 'role'):
|
||||
roles = self.request.user.role.values_list('id', flat=True)
|
||||
ret = ret.filter(is_query=True, role__in=roles)
|
||||
|
||||
return ret.values_list('field__field_name', flat=True)
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
serializer = self.get_serializer(data=request.data, request=request)
|
||||
@@ -131,8 +137,7 @@ class CustomModelViewSet(ModelViewSet, ImportSerializerMixin, ExportSerializerMi
|
||||
instance.delete()
|
||||
return DetailResponse(data=[], msg="删除成功")
|
||||
|
||||
keys = openapi.Schema(description='主键列表', type=openapi.TYPE_ARRAY, items=openapi.TYPE_STRING)
|
||||
|
||||
keys = openapi.Schema(description='主键列表', type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_STRING))
|
||||
@swagger_auto_schema(request_body=openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT,
|
||||
required=['keys'],
|
||||
|
||||
Reference in New Issue
Block a user