406 lines
13 KiB
Python
406 lines
13 KiB
Python
import uuid
|
|
import json
|
|
import datetime
|
|
from django.conf import settings
|
|
from django.http import HttpRequest
|
|
|
|
from gvsds.apps.core.models import User, UUIDField
|
|
from gvsds.apps.gerp.models import (
|
|
Tenant, CompanyInfo, Company, Department, Role, UserRole, RoleDept,
|
|
Permission, FileAsset, WorkOrder, Message, Menu,
|
|
)
|
|
from gvsds.apps.crb.models import Enterprise, EnterpriseUser
|
|
from gvsds.apps.doc.models import CommunityDocument, CommunitySeries
|
|
from gvsds.apps.sve.models import SVEBase
|
|
from gvsds.apps.t4.models import T4User
|
|
from gvsds.apps.mc.models import MCUser
|
|
from gvsds.apps.invite.models import InviteConversation
|
|
from gvsds.apps.ccgo.models import PlansNotify, PlansTalentPlan, Link
|
|
from PDAPI_django import UUIDObj, NewBUUID, snake_to_pascal
|
|
|
|
|
|
MODEL_REGISTRY = {
|
|
"User": User,
|
|
"UserAvatar": User,
|
|
"EphemeralTokens": User,
|
|
"Tenant": Tenant,
|
|
"CompanyInfo": CompanyInfo,
|
|
"Company": Company,
|
|
"Dept": Department,
|
|
"Role": Role,
|
|
"UserRole": UserRole,
|
|
"RoleDept": RoleDept,
|
|
"Permission": Permission,
|
|
"FileAsset": FileAsset,
|
|
"WorkOrder": WorkOrder,
|
|
"Message": Message,
|
|
"Menu": Menu,
|
|
"Enterprise": Enterprise,
|
|
"EnterpriseUser": EnterpriseUser,
|
|
"document": CommunityDocument,
|
|
"series": CommunitySeries,
|
|
"sve": SVEBase,
|
|
"computers": T4User,
|
|
"InviteConversation": InviteConversation,
|
|
"notify": PlansNotify,
|
|
"talentplan": PlansTalentPlan,
|
|
"links": Link,
|
|
}
|
|
|
|
|
|
def _pascal_to_snake(name):
|
|
import re
|
|
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
|
|
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
|
|
|
|
|
|
class TableConfig:
|
|
def __init__(self, model_class):
|
|
self.model = model_class
|
|
self._fields = None
|
|
self._row = None
|
|
self.data = self.Get()
|
|
|
|
@property
|
|
def Model(self):
|
|
return self.model
|
|
|
|
@property
|
|
def PrimaryKey(self):
|
|
for item in self.row:
|
|
if "PrimaryKey" in item.get("Groups", []):
|
|
return item["Name"]
|
|
return None
|
|
|
|
@property
|
|
def PrimaryKeys(self):
|
|
return [item["Name"] for item in self.row if "PrimaryKey" in item.get("Groups", [])]
|
|
|
|
@property
|
|
def IsCompositeKey(self):
|
|
return len(self.PrimaryKeys) > 1
|
|
|
|
def RangeItemList(self):
|
|
return [item["Name"] for item in self.row]
|
|
|
|
def RangeItem(self):
|
|
return iter([item["Name"] for item in self.row])
|
|
|
|
def GetPrimaryKeyField(self):
|
|
pk_name = self.PrimaryKey
|
|
if pk_name:
|
|
return self.GetItem(pk_name)
|
|
return None
|
|
|
|
def GetModel(self):
|
|
return self.model()
|
|
|
|
def CheckAllUniqueFieldsDuplicate(self, form_data):
|
|
from django.db.models import Q
|
|
unique_fields = []
|
|
for f in self.model._meta.local_fields:
|
|
if f.unique and not f.primary_key:
|
|
pascal = snake_to_pascal(f.name)
|
|
unique_fields.append((f.name, pascal))
|
|
for db_name, pascal_name in unique_fields:
|
|
val = form_data.get(pascal_name)
|
|
if val is not None and val != '':
|
|
if self.model.objects.filter(**{db_name: val}).exists():
|
|
return False, pascal_name
|
|
return True, None
|
|
|
|
def PrimaryKeyGenerationFunction(self):
|
|
pk_field = None
|
|
for f in self.model._meta.local_fields:
|
|
if f.primary_key:
|
|
pk_field = f
|
|
break
|
|
if pk_field is None:
|
|
return None
|
|
from gvsds.apps.core.models import UUIDField
|
|
if isinstance(pk_field, UUIDField):
|
|
return NewBUUID
|
|
return None
|
|
|
|
@property
|
|
def row(self):
|
|
if self._row is not None:
|
|
return self._row
|
|
self._row = self.Get()
|
|
return self._row
|
|
|
|
def Get(self):
|
|
if self._fields is not None:
|
|
return self._fields
|
|
fields = []
|
|
for f in self.model._meta.get_fields():
|
|
if hasattr(f, 'column'):
|
|
pascal_name = snake_to_pascal(f.name)
|
|
field_info = {
|
|
"Name": pascal_name,
|
|
"Type": self._map_type(f),
|
|
"Required": not f.null and not f.has_default(),
|
|
"AllowedEmpty": f.null,
|
|
"Groups": self._get_groups(f),
|
|
}
|
|
if f.has_default():
|
|
default = f.get_default()
|
|
if default is not None:
|
|
field_info["Default"] = default
|
|
if getattr(f, 'max_length', None):
|
|
field_info["MaxLen"] = f.max_length
|
|
fields.append(field_info)
|
|
self._fields = fields
|
|
return fields
|
|
|
|
def _get_groups(self, field):
|
|
if field.primary_key:
|
|
return ["PrimaryKey"]
|
|
if field.null or field.has_default():
|
|
return ["MechanicalItem"]
|
|
return ["ManualItem"]
|
|
|
|
def _map_type(self, field):
|
|
from django.db import models as dj_models
|
|
if isinstance(field, dj_models.ForeignKey):
|
|
return "UUID"
|
|
if isinstance(field, UUIDField):
|
|
return "UUID"
|
|
if isinstance(field, dj_models.BinaryField):
|
|
return "UUID"
|
|
if isinstance(field, dj_models.SmallIntegerField):
|
|
return "int"
|
|
if isinstance(field, dj_models.IntegerField):
|
|
return "int"
|
|
if isinstance(field, dj_models.BigIntegerField):
|
|
return "int"
|
|
if isinstance(field, dj_models.FloatField):
|
|
return "float"
|
|
if isinstance(field, dj_models.DecimalField):
|
|
return "float"
|
|
if isinstance(field, dj_models.DateTimeField):
|
|
return "timestampstr"
|
|
if isinstance(field, dj_models.JSONField):
|
|
return "json"
|
|
if isinstance(field, dj_models.TextField):
|
|
return "str"
|
|
if isinstance(field, dj_models.BooleanField):
|
|
return "bool"
|
|
return "str"
|
|
|
|
def GetItem(self, field_name):
|
|
for f in self.Get():
|
|
if f["Name"] == field_name:
|
|
return f
|
|
return None
|
|
|
|
def SetRequired(self, fields, required):
|
|
pass
|
|
|
|
def KeyToUUIDConversion(self, field_name, value, target_type):
|
|
if value is None:
|
|
return None
|
|
if hasattr(value, '_meta'):
|
|
pk = value._meta.pk
|
|
if pk:
|
|
value = getattr(value, pk.name)
|
|
if target_type == bytes:
|
|
if isinstance(value, bytes) and len(value) == 16:
|
|
return value
|
|
if isinstance(value, str):
|
|
try:
|
|
return uuid.UUID(value).bytes
|
|
except ValueError:
|
|
return None
|
|
if isinstance(value, uuid.UUID):
|
|
return value.bytes
|
|
elif target_type == str:
|
|
if isinstance(value, bytes) and len(value) == 16:
|
|
return str(uuid.UUID(bytes=value)).upper().replace('-', '')
|
|
if isinstance(value, uuid.UUID):
|
|
return str(value).upper().replace('-', '')
|
|
if isinstance(value, str):
|
|
return value
|
|
return str(value)
|
|
return value
|
|
|
|
|
|
class _PermissionManager:
|
|
def _build_context(self, table, table_name, cleaned_data):
|
|
return {"table": table, "table_name": table_name, "data": cleaned_data}
|
|
|
|
def check_permission(self, action, ctx):
|
|
return True
|
|
|
|
def run_before_add(self, ctx):
|
|
return False, None
|
|
|
|
def run_after_add(self, ctx, result):
|
|
return result, False
|
|
|
|
def run_before_modify(self, ctx):
|
|
return False, None
|
|
|
|
def run_after_modify(self, ctx, result):
|
|
return result, False
|
|
|
|
def run_before_modify_item(self, ctx):
|
|
return False, None
|
|
|
|
def run_after_modify_item(self, ctx, result):
|
|
return result, False
|
|
|
|
def run_before_delete(self, ctx):
|
|
return False, None
|
|
|
|
def run_after_delete(self, ctx, result):
|
|
return result, False
|
|
|
|
def run_before_get(self, ctx):
|
|
return False, None
|
|
|
|
def run_after_get(self, ctx, result):
|
|
return result, False
|
|
|
|
|
|
class FormDataCompat:
|
|
_instance = None
|
|
|
|
TABLE_CODE_DISPLAY = {}
|
|
TABLE_ENUM_LABELS = {}
|
|
TABLE_FK_PICKER = {}
|
|
TABLE_HIDE_IN_FORM = set()
|
|
TABLE_TEXTAREA_FIELDS = set()
|
|
TABLE_FIELD_PLACEHOLDER = {}
|
|
TABLE_DISPLAY_NAMES = {
|
|
"User": "用户", "UserAvatar": "用户头像", "EphemeralTokens": "临时令牌",
|
|
"Tenant": "租户", "TenantCompany": "企业入驻申请", "CompanyInfo": "企业入驻申请",
|
|
"Company": "公司", "Dept": "部门", "Role": "角色", "Permission": "权限",
|
|
"UserRole": "用户角色", "RoleDept": "角色部门", "WorkOrder": "工单",
|
|
"Menu": "菜单", "Message": "消息", "FileAsset": "文件资产",
|
|
}
|
|
TABLE_EXCLUDED_FIELDS = {}
|
|
TABLE_UUID_INPUT_ALLOWED = set()
|
|
data = {}
|
|
PM = _PermissionManager()
|
|
|
|
def __new__(cls):
|
|
if cls._instance is None:
|
|
cls._instance = super().__new__(cls)
|
|
return cls._instance
|
|
|
|
def GetTable(self, table_name):
|
|
model_class = MODEL_REGISTRY.get(table_name)
|
|
if not model_class:
|
|
return None
|
|
return TableConfig(model_class)
|
|
|
|
@staticmethod
|
|
def get_user_models():
|
|
from gvsds.apps.core.models import User, UserAvatar, EphemeralToken
|
|
from gvsds.apps.gerp.models import (
|
|
Tenant, CompanyInfo, Company, Department, Role, Permission,
|
|
UserRole, RoleDept, WorkOrder, Menu, Message,
|
|
)
|
|
return {
|
|
"User": User,
|
|
"UserAvatar": UserAvatar,
|
|
"EphemeralTokens": EphemeralToken,
|
|
"Tenant": Tenant,
|
|
"Company": Company,
|
|
"Dept": Department,
|
|
"Role": Role,
|
|
"Permission": Permission,
|
|
"UserRole": UserRole,
|
|
"RoleDept": RoleDept,
|
|
"WorkOrder": WorkOrder,
|
|
"Menu": Menu,
|
|
"CompanyInfo": CompanyInfo,
|
|
"Message": Message,
|
|
}
|
|
|
|
@staticmethod
|
|
def get_field_display_name(table_name, field_name):
|
|
name_map = {
|
|
"UUID": "UUID", "UserUUID": "用户UUID", "UserName": "用户名",
|
|
"UserEmail": "邮箱", "UserTele": "电话", "UserPassword": "密码",
|
|
"CompanyUUID": "公司UUID", "CompanyName": "公司名称", "CompanyShort": "公司简称",
|
|
"RoleUUID": "角色UUID", "RoleName": "角色名称", "RoleType": "角色类型",
|
|
"RoleStatus": "角色状态", "DeptUUID": "部门UUID", "DeptName": "部门名称",
|
|
"MenuUUID": "菜单UUID", "MenuName": "菜单名称", "MenuTitle": "菜单标题",
|
|
"MenuLink": "菜单链接", "MenuIcon": "菜单图标", "MenuSort": "排序",
|
|
"ParentMenuUUID": "上级菜单UUID", "PermissionKey": "权限键",
|
|
"PermissionName": "权限名称", "PermissionContent": "权限内容",
|
|
"PermissionEnabled": "是否启用", "CreateTime": "创建时间",
|
|
"UpdateTime": "更新时间", "MessageUUID": "消息UUID",
|
|
"MessageTitle": "消息标题", "MessageContent": "消息内容",
|
|
"WorkOrderUUID": "工单UUID", "WorkOrderTitle": "工单标题",
|
|
"WorkOrderContent": "工单内容", "WorkOrderStatus": "工单状态",
|
|
"TenantName": "租户名称", "TenantExpireTime": "过期时间",
|
|
}
|
|
return name_map.get(field_name, field_name)
|
|
|
|
@staticmethod
|
|
def get_code_display(table_name, field_name, value):
|
|
return str(value) if value is not None else ""
|
|
|
|
@staticmethod
|
|
def get_table_extension(table_name):
|
|
return None
|
|
|
|
@staticmethod
|
|
def get_user_timezone():
|
|
return "UTC"
|
|
|
|
@staticmethod
|
|
def utc_to_user_tz(dt, tz=None):
|
|
return dt
|
|
|
|
@staticmethod
|
|
def user_tz_to_utc(value):
|
|
return value
|
|
|
|
@staticmethod
|
|
def RegisterFunctionExtension(*args, **kwargs):
|
|
pass
|
|
|
|
class FormAPIPlugin:
|
|
name = ""
|
|
description = ""
|
|
|
|
def on_before_add(self, ctx):
|
|
return False, None
|
|
|
|
def on_after_add(self, ctx, result):
|
|
pass
|
|
|
|
def on_before_modify(self, ctx):
|
|
return False, None
|
|
|
|
def on_after_modify(self, ctx, result):
|
|
pass
|
|
|
|
def on_before_delete(self, ctx):
|
|
return False, None
|
|
|
|
def on_after_delete(self, ctx, result):
|
|
pass
|
|
|
|
class PluginManager:
|
|
_instance = None
|
|
|
|
def __new__(cls):
|
|
if cls._instance is None:
|
|
cls._instance = super().__new__(cls)
|
|
cls._instance._plugins = {}
|
|
return cls._instance
|
|
|
|
def register(self, plugin):
|
|
self._plugins[plugin.name] = plugin
|
|
|
|
def get_plugin(self, name):
|
|
return self._plugins.get(name)
|
|
|
|
def get_all_plugins(self):
|
|
return list(self._plugins.values())
|