修改知识库为表中数据,完善了权限通知功能
This commit is contained in:
commit
c6065dbc71
47
.idea/.gitignore
generated
vendored
Normal file
47
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
|
||||
# Python 虚拟环境
|
||||
venv/
|
||||
env/
|
||||
.env/
|
||||
.venv/
|
||||
ENV/
|
||||
|
||||
# Python 编译文件
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
|
||||
# 包分发相关
|
||||
dist/
|
||||
build/
|
||||
*.egg-info/
|
||||
|
||||
# 测试覆盖率报告
|
||||
.coverage
|
||||
htmlcov/
|
||||
.tox/
|
||||
.pytest_cache/
|
||||
|
||||
# IDE 相关
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
.DS_Store
|
||||
|
||||
# 日志文件
|
||||
*.log
|
||||
logs/
|
||||
|
||||
# 本地配置文件
|
||||
config.local.ini
|
||||
.env.local
|
93
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
93
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@ -0,0 +1,93 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="myValues">
|
||||
<value>
|
||||
<list size="6">
|
||||
<item index="0" class="java.lang.String" itemvalue="folder" />
|
||||
<item index="1" class="java.lang.String" itemvalue="selected_folder" />
|
||||
<item index="2" class="java.lang.String" itemvalue="%}selected{%" />
|
||||
<item index="3" class="java.lang.String" itemvalue="{%" />
|
||||
<item index="4" class="java.lang.String" itemvalue="endif" />
|
||||
<item index="5" class="java.lang.String" itemvalue="%}" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
<option name="myCustomValuesEnabled" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredPackages">
|
||||
<value>
|
||||
<list size="50">
|
||||
<item index="0" class="java.lang.String" itemvalue="tensorflow" />
|
||||
<item index="1" class="java.lang.String" itemvalue="ntplib" />
|
||||
<item index="2" class="java.lang.String" itemvalue="sklearn" />
|
||||
<item index="3" class="java.lang.String" itemvalue="mysqlclient" />
|
||||
<item index="4" class="java.lang.String" itemvalue="async-timeout" />
|
||||
<item index="5" class="java.lang.String" itemvalue="cffi" />
|
||||
<item index="6" class="java.lang.String" itemvalue="python-dotenv" />
|
||||
<item index="7" class="java.lang.String" itemvalue="pycparser" />
|
||||
<item index="8" class="java.lang.String" itemvalue="alibabacloud-openapi-util" />
|
||||
<item index="9" class="java.lang.String" itemvalue="frozenlist" />
|
||||
<item index="10" class="java.lang.String" itemvalue="alibabacloud-credentials" />
|
||||
<item index="11" class="java.lang.String" itemvalue="rest-framework-simplejwt" />
|
||||
<item index="12" class="java.lang.String" itemvalue="alibabacloud-tea-console" />
|
||||
<item index="13" class="java.lang.String" itemvalue="certifi" />
|
||||
<item index="14" class="java.lang.String" itemvalue="urllib3" />
|
||||
<item index="15" class="java.lang.String" itemvalue="alibabacloud-market20151101" />
|
||||
<item index="16" class="java.lang.String" itemvalue="django-cors-headers" />
|
||||
<item index="17" class="java.lang.String" itemvalue="alibabacloud-tea-util" />
|
||||
<item index="18" class="java.lang.String" itemvalue="alibabacloud-endpoint-util" />
|
||||
<item index="19" class="java.lang.String" itemvalue="tzdata" />
|
||||
<item index="20" class="java.lang.String" itemvalue="cryptography" />
|
||||
<item index="21" class="java.lang.String" itemvalue="alibabacloud-darabonba-env" />
|
||||
<item index="22" class="java.lang.String" itemvalue="alibabacloud-tea-openapi" />
|
||||
<item index="23" class="java.lang.String" itemvalue="attrs" />
|
||||
<item index="24" class="java.lang.String" itemvalue="jmespath" />
|
||||
<item index="25" class="java.lang.String" itemvalue="alibabacloud-tea" />
|
||||
<item index="26" class="java.lang.String" itemvalue="alibabacloud-gateway-spi" />
|
||||
<item index="27" class="java.lang.String" itemvalue="django-rest-framework" />
|
||||
<item index="28" class="java.lang.String" itemvalue="Django" />
|
||||
<item index="29" class="java.lang.String" itemvalue="typing_extensions" />
|
||||
<item index="30" class="java.lang.String" itemvalue="alibabacloud-tea-xml" />
|
||||
<item index="31" class="java.lang.String" itemvalue="aiohttp" />
|
||||
<item index="32" class="java.lang.String" itemvalue="multidict" />
|
||||
<item index="33" class="java.lang.String" itemvalue="yarl" />
|
||||
<item index="34" class="java.lang.String" itemvalue="aiosignal" />
|
||||
<item index="35" class="java.lang.String" itemvalue="idna" />
|
||||
<item index="36" class="java.lang.String" itemvalue="PyJWT" />
|
||||
<item index="37" class="java.lang.String" itemvalue="rsa" />
|
||||
<item index="38" class="java.lang.String" itemvalue="msal" />
|
||||
<item index="39" class="java.lang.String" itemvalue="django-sslserver" />
|
||||
<item index="40" class="java.lang.String" itemvalue="six" />
|
||||
<item index="41" class="java.lang.String" itemvalue="asgiref" />
|
||||
<item index="42" class="java.lang.String" itemvalue="ecdsa" />
|
||||
<item index="43" class="java.lang.String" itemvalue="pyasn1" />
|
||||
<item index="44" class="java.lang.String" itemvalue="requests" />
|
||||
<item index="45" class="java.lang.String" itemvalue="sqlparse" />
|
||||
<item index="46" class="java.lang.String" itemvalue="charset-normalizer" />
|
||||
<item index="47" class="java.lang.String" itemvalue="pytz" />
|
||||
<item index="48" class="java.lang.String" itemvalue="djangorestframework" />
|
||||
<item index="49" class="java.lang.String" itemvalue="python-jose" />
|
||||
</list>
|
||||
</value>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoredErrors">
|
||||
<list>
|
||||
<option value="N806" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredIdentifiers">
|
||||
<list>
|
||||
<option value="MarKet.urls.Market" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
7
.idea/misc.xml
generated
Normal file
7
.idea/misc.xml
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.10 (role_based_system)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (role_based_system) (2)" project-jdk-type="Python SDK" />
|
||||
</project>
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/role_based_system.iml" filepath="$PROJECT_DIR$/.idea/role_based_system.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
30
.idea/role_based_system.iml
generated
Normal file
30
.idea/role_based_system.iml
generated
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="django" name="Django">
|
||||
<configuration>
|
||||
<option name="rootFolder" value="$MODULE_DIR$" />
|
||||
<option name="settingsModule" value="role_based_system/settings.py" />
|
||||
<option name="manageScript" value="$MODULE_DIR$/manage.py" />
|
||||
<option name="environment" value="<map/>" />
|
||||
<option name="doNotUseTestRunner" value="false" />
|
||||
<option name="trackFilePattern" value="migrations" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.10 (role_based_system) (2)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="TemplatesService">
|
||||
<option name="TEMPLATE_CONFIGURATION" value="Django" />
|
||||
<option name="TEMPLATE_FOLDERS">
|
||||
<list>
|
||||
<option value="$MODULE_DIR$/../role_based_system\templates" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
</module>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
22
manage.py
Normal file
22
manage.py
Normal file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'role_based_system.settings')
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
BIN
requirements.txt
Normal file
BIN
requirements.txt
Normal file
Binary file not shown.
0
role_based_system/__init__.py
Normal file
0
role_based_system/__init__.py
Normal file
BIN
role_based_system/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
role_based_system/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
BIN
role_based_system/__pycache__/asgi.cpython-310.pyc
Normal file
BIN
role_based_system/__pycache__/asgi.cpython-310.pyc
Normal file
Binary file not shown.
BIN
role_based_system/__pycache__/settings.cpython-310.pyc
Normal file
BIN
role_based_system/__pycache__/settings.cpython-310.pyc
Normal file
Binary file not shown.
BIN
role_based_system/__pycache__/urls.cpython-310.pyc
Normal file
BIN
role_based_system/__pycache__/urls.cpython-310.pyc
Normal file
Binary file not shown.
28
role_based_system/asgi.py
Normal file
28
role_based_system/asgi.py
Normal file
@ -0,0 +1,28 @@
|
||||
"""
|
||||
ASGI config for role_based_system project.
|
||||
|
||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
import django
|
||||
|
||||
# 首先设置 Django 设置模块
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'role_based_system.settings')
|
||||
django.setup() # 添加这行来初始化 Django
|
||||
|
||||
# 然后再导入其他模块
|
||||
from django.core.asgi import get_asgi_application
|
||||
from channels.routing import ProtocolTypeRouter, URLRouter
|
||||
from channels.auth import AuthMiddlewareStack
|
||||
from user_management.routing import websocket_urlpatterns
|
||||
|
||||
application = ProtocolTypeRouter({
|
||||
"http": get_asgi_application(),
|
||||
"websocket": AuthMiddlewareStack(
|
||||
URLRouter(websocket_urlpatterns)
|
||||
),
|
||||
})
|
277
role_based_system/settings.py
Normal file
277
role_based_system/settings.py
Normal file
@ -0,0 +1,277 @@
|
||||
"""
|
||||
Django settings for role_based_system project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 5.1.5.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/5.1/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/5.1/ref/settings/
|
||||
"""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# API 配置
|
||||
API_BASE_URL = 'http://81.69.223.133:48329'
|
||||
|
||||
DEPARTMENT_GROUPS = {
|
||||
"技术部": ["开发组", "测试组", "运维组"],
|
||||
"产品部": ["产品组", "设计组"],
|
||||
"市场部": ["销售组", "推广组"],
|
||||
"行政部": ["人事组", "财务组"]
|
||||
}
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = 'django-insecure-5f*=0_2did)e(()n58=e#vd5gaf&y$thgt(h6&=p+wm1*r6mb='
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
# 开发配置
|
||||
# DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ['*'] # 仅在开发环境使用
|
||||
# 服务器配置
|
||||
DEBUG = False
|
||||
|
||||
# ALLOWED_HOSTS = ['frptx.chiyong.fun', 'localhost', '127.0.0.1']
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'rest_framework',
|
||||
'rest_framework.authtoken',
|
||||
'channels',
|
||||
'user_management',
|
||||
'channels_redis',
|
||||
'corsheaders',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'corsheaders.middleware.CorsMiddleware', # CORS中间件要放在CommonMiddleware前面
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
# 'django.middleware.csrf.CsrfViewMiddleware', # WebSocket不需要CSRF
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'user_management.middleware.UserActivityMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'role_based_system.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [BASE_DIR / 'templates']
|
||||
,
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'role_based_system.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
|
||||
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'NAME': 'rolebasedfilemanagement',
|
||||
'USER': 'root',
|
||||
'PASSWORD': '123456',
|
||||
'HOST': 'localhost',
|
||||
'PORT': '3306',
|
||||
}
|
||||
}
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
|
||||
STATIC_URL = 'static/'
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
AUTH_USER_MODEL = 'user_management.User'
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': [
|
||||
'rest_framework.authentication.TokenAuthentication',
|
||||
'rest_framework.authentication.SessionAuthentication',
|
||||
],
|
||||
'DEFAULT_PERMISSION_CLASSES': [
|
||||
'rest_framework.permissions.IsAuthenticated',
|
||||
]
|
||||
}
|
||||
|
||||
# Channels 配置
|
||||
ASGI_APPLICATION = "role_based_system.asgi.application"
|
||||
|
||||
# Channel Layers 配置
|
||||
CHANNEL_LAYERS = {
|
||||
"default": {
|
||||
"BACKEND": "channels_redis.core.RedisChannelLayer",
|
||||
"CONFIG": {
|
||||
"hosts": [("127.0.0.1", 6379)],
|
||||
"capacity": 1500, # 消息队列容量
|
||||
"expiry": 10, # 消息过期时间(秒)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
# CORS 配置
|
||||
CORS_ALLOW_ALL_ORIGINS = True
|
||||
CORS_ALLOW_CREDENTIALS = True
|
||||
CORS_ALLOWED_ORIGINS = [
|
||||
"http://localhost:8000",
|
||||
"http://127.0.0.1:8000",
|
||||
"ws://localhost:8000", # 添加 WebSocket
|
||||
"ws://127.0.0.1:8000" # 添加 WebSocket
|
||||
]
|
||||
# 允许的请求头
|
||||
CORS_ALLOWED_HEADERS = [
|
||||
'accept',
|
||||
'accept-encoding',
|
||||
'authorization',
|
||||
'content-type',
|
||||
'dnt',
|
||||
'origin',
|
||||
'user-agent',
|
||||
'x-csrftoken',
|
||||
'x-requested-with',
|
||||
]
|
||||
|
||||
# 允许的请求方法
|
||||
CORS_ALLOWED_METHODS = [
|
||||
'DELETE',
|
||||
'GET',
|
||||
'OPTIONS',
|
||||
'PATCH',
|
||||
'POST',
|
||||
'PUT',
|
||||
]
|
||||
|
||||
|
||||
|
||||
# WebSocket 允许的来源
|
||||
CSRF_TRUSTED_ORIGINS = [
|
||||
'http://localhost:8000',
|
||||
'http://127.0.0.1:8000',
|
||||
'ws://localhost:8000', # 添加 WebSocket
|
||||
'ws://127.0.0.1:8000', # 添加 WebSocket
|
||||
]
|
||||
# 服务器配置
|
||||
# 静态文件配置
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
||||
|
||||
# 媒体文件配置
|
||||
MEDIA_URL = '/media/'
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||
|
||||
# 文件上传配置
|
||||
FILE_UPLOAD_MAX_MEMORY_SIZE = 10 * 1024 * 1024 # 10MB
|
||||
MAX_UPLOAD_SIZE = 10 * 1024 * 1024 # 10MB
|
||||
|
||||
# 日志配置
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'handlers': {
|
||||
'console': {
|
||||
'class': 'logging.StreamHandler',
|
||||
},
|
||||
'file': {
|
||||
'class': 'logging.FileHandler',
|
||||
'filename': 'debug.log',
|
||||
},
|
||||
},
|
||||
'root': {
|
||||
'handlers': ['console', 'file'],
|
||||
'level': 'DEBUG',
|
||||
},
|
||||
}
|
||||
|
||||
# CSRF 配置
|
||||
CSRF_COOKIE_SECURE = False # 开发环境设置为 False
|
||||
CSRF_COOKIE_HTTPONLY = False
|
||||
CSRF_USE_SESSIONS = False
|
||||
CSRF_COOKIE_SAMESITE = 'Lax'
|
||||
CSRF_TRUSTED_ORIGINS = [
|
||||
'http://localhost:8000',
|
||||
'http://127.0.0.1:8000',
|
||||
'ws://localhost:8000', # 添加 WebSocket
|
||||
'ws://127.0.0.1:8000' # 添加 WebSocket
|
||||
]
|
||||
|
||||
# Session 配置
|
||||
SESSION_COOKIE_SECURE = False # 开发环境设置为 False
|
||||
SESSION_COOKIE_HTTPONLY = True
|
||||
SESSION_COOKIE_SAMESITE = 'Lax'
|
||||
|
||||
# REST Framework 配置
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': [
|
||||
'rest_framework.authentication.TokenAuthentication',
|
||||
'rest_framework.authentication.SessionAuthentication', # WebSocket 需要
|
||||
],
|
||||
'DEFAULT_PERMISSION_CLASSES': [
|
||||
'rest_framework.permissions.IsAuthenticated',
|
||||
],
|
||||
'DEFAULT_PARSER_CLASSES': [
|
||||
'rest_framework.parsers.JSONParser',
|
||||
'rest_framework.parsers.FormParser',
|
||||
'rest_framework.parsers.MultiPartParser'
|
||||
],
|
||||
}
|
41
role_based_system/urls.py
Normal file
41
role_based_system/urls.py
Normal file
@ -0,0 +1,41 @@
|
||||
"""
|
||||
URL configuration for role_based_system project.
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/5.1/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path, include
|
||||
from django.conf import settings
|
||||
from django.conf.urls.static import static
|
||||
|
||||
urlpatterns = [
|
||||
# 管理后台
|
||||
path('admin/', admin.site.urls),
|
||||
|
||||
# API路由
|
||||
path('api/', include('user_management.urls')),
|
||||
|
||||
# 媒体文件服务
|
||||
*static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT),
|
||||
|
||||
# 静态文件服务(仅在DEBUG模式下)
|
||||
*static(settings.STATIC_URL, document_root=settings.STATIC_ROOT),
|
||||
]
|
||||
|
||||
# 添加调试工具栏(仅在DEBUG模式下)
|
||||
if settings.DEBUG:
|
||||
import debug_toolbar
|
||||
urlpatterns = [
|
||||
path('__debug__/', include(debug_toolbar.urls)),
|
||||
] + urlpatterns
|
16
role_based_system/wsgi.py
Normal file
16
role_based_system/wsgi.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""
|
||||
WSGI config for role_based_system project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'role_based_system.settings')
|
||||
|
||||
application = get_wsgi_application()
|
0
user_management/__init__.py
Normal file
0
user_management/__init__.py
Normal file
BIN
user_management/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
user_management/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
BIN
user_management/__pycache__/admin.cpython-310.pyc
Normal file
BIN
user_management/__pycache__/admin.cpython-310.pyc
Normal file
Binary file not shown.
BIN
user_management/__pycache__/apps.cpython-310.pyc
Normal file
BIN
user_management/__pycache__/apps.cpython-310.pyc
Normal file
Binary file not shown.
BIN
user_management/__pycache__/consumers.cpython-310.pyc
Normal file
BIN
user_management/__pycache__/consumers.cpython-310.pyc
Normal file
Binary file not shown.
BIN
user_management/__pycache__/exceptions.cpython-310.pyc
Normal file
BIN
user_management/__pycache__/exceptions.cpython-310.pyc
Normal file
Binary file not shown.
BIN
user_management/__pycache__/middleware.cpython-310.pyc
Normal file
BIN
user_management/__pycache__/middleware.cpython-310.pyc
Normal file
Binary file not shown.
BIN
user_management/__pycache__/models.cpython-310.pyc
Normal file
BIN
user_management/__pycache__/models.cpython-310.pyc
Normal file
Binary file not shown.
BIN
user_management/__pycache__/permissions.cpython-310.pyc
Normal file
BIN
user_management/__pycache__/permissions.cpython-310.pyc
Normal file
Binary file not shown.
BIN
user_management/__pycache__/routing.cpython-310.pyc
Normal file
BIN
user_management/__pycache__/routing.cpython-310.pyc
Normal file
Binary file not shown.
BIN
user_management/__pycache__/serializers.cpython-310.pyc
Normal file
BIN
user_management/__pycache__/serializers.cpython-310.pyc
Normal file
Binary file not shown.
BIN
user_management/__pycache__/signals.cpython-310.pyc
Normal file
BIN
user_management/__pycache__/signals.cpython-310.pyc
Normal file
Binary file not shown.
BIN
user_management/__pycache__/urls.cpython-310.pyc
Normal file
BIN
user_management/__pycache__/urls.cpython-310.pyc
Normal file
Binary file not shown.
BIN
user_management/__pycache__/views.cpython-310.pyc
Normal file
BIN
user_management/__pycache__/views.cpython-310.pyc
Normal file
Binary file not shown.
70
user_management/admin.py
Normal file
70
user_management/admin.py
Normal file
@ -0,0 +1,70 @@
|
||||
from django.contrib import admin
|
||||
from .models import User, Data, KnowledgeBase, Permission, ChatHistory, KnowledgeBasePermission
|
||||
|
||||
@admin.register(User)
|
||||
class UserAdmin(admin.ModelAdmin):
|
||||
list_display = ('username', 'email', 'role', 'department', 'date_joined')
|
||||
list_filter = ('role', 'department', 'is_active')
|
||||
search_fields = ('username', 'email', 'department')
|
||||
|
||||
@admin.register(Data)
|
||||
class DataAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'type', 'user_id', 'department', 'create_time')
|
||||
list_filter = ('type', 'department', 'create_time')
|
||||
search_fields = ('name', 'desc', 'user_id')
|
||||
readonly_fields = ('id', 'create_time', 'update_time')
|
||||
|
||||
@admin.register(KnowledgeBase)
|
||||
class KnowledgeBaseAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'type', 'user_id', 'document_count', 'create_time')
|
||||
list_filter = ('type', 'create_time')
|
||||
search_fields = ('name', 'desc', 'user_id')
|
||||
readonly_fields = ('id', 'create_time', 'update_time', 'document_count')
|
||||
|
||||
@admin.register(Permission)
|
||||
class PermissionAdmin(admin.ModelAdmin):
|
||||
list_display = [
|
||||
'knowledge_base',
|
||||
'applicant',
|
||||
'status',
|
||||
'get_permissions_display', # 显示具体的权限
|
||||
'expires_at', # 显示过期时间
|
||||
'created_at'
|
||||
]
|
||||
list_filter = [
|
||||
'status',
|
||||
'created_at',
|
||||
'expires_at'
|
||||
]
|
||||
search_fields = [
|
||||
'knowledge_base__name',
|
||||
'applicant__username',
|
||||
'reason',
|
||||
'response_message'
|
||||
]
|
||||
readonly_fields = [
|
||||
'created_at',
|
||||
'updated_at'
|
||||
]
|
||||
|
||||
def get_permissions_display(self, obj):
|
||||
"""格式化显示权限"""
|
||||
perms = []
|
||||
permissions = obj.permissions
|
||||
if permissions.get('can_read'):
|
||||
perms.append('读取')
|
||||
if permissions.get('can_edit'):
|
||||
perms.append('编辑')
|
||||
if permissions.get('can_delete'):
|
||||
perms.append('删除')
|
||||
return '、'.join(perms) if perms else '无权限'
|
||||
get_permissions_display.short_description = '权限'
|
||||
|
||||
@admin.register(ChatHistory)
|
||||
class ChatHistoryAdmin(admin.ModelAdmin):
|
||||
list_display = ('user', 'role', 'conversation_id', 'created_at')
|
||||
list_filter = ('role', 'created_at')
|
||||
search_fields = ('user__username', 'content', 'conversation_id')
|
||||
readonly_fields = ('created_at',)
|
||||
|
||||
admin.site.register(KnowledgeBasePermission)
|
9
user_management/apps.py
Normal file
9
user_management/apps.py
Normal file
@ -0,0 +1,9 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class UserManagementConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'user_management'
|
||||
verbose_name = '用户管理系统'
|
||||
|
||||
# 完全移除 ready 方法
|
67
user_management/consumers.py
Normal file
67
user_management/consumers.py
Normal file
@ -0,0 +1,67 @@
|
||||
import json
|
||||
from channels.generic.websocket import AsyncWebsocketConsumer
|
||||
from channels.db import database_sync_to_async
|
||||
from channels.exceptions import StopConsumer
|
||||
import logging
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class NotificationConsumer(AsyncWebsocketConsumer):
|
||||
async def connect(self):
|
||||
"""建立WebSocket连接"""
|
||||
try:
|
||||
# 获取token
|
||||
headers = dict(self.scope['headers'])
|
||||
auth_header = headers.get(b'authorization', b'').decode()
|
||||
|
||||
if not auth_header.startswith('Token '):
|
||||
await self.close()
|
||||
return
|
||||
|
||||
token_key = auth_header.split(' ')[1]
|
||||
|
||||
# 验证token
|
||||
self.user = await self.get_user_from_token(token_key)
|
||||
if not self.user:
|
||||
await self.close()
|
||||
return
|
||||
|
||||
# 为用户创建专属房间
|
||||
self.room_name = f"notification_user_{self.user.id}"
|
||||
await self.channel_layer.group_add(
|
||||
self.room_name,
|
||||
self.channel_name
|
||||
)
|
||||
await self.accept()
|
||||
|
||||
except Exception as e:
|
||||
await self.close()
|
||||
|
||||
@database_sync_to_async
|
||||
def get_user_from_token(self, token_key):
|
||||
try:
|
||||
token = Token.objects.select_related('user').get(key=token_key)
|
||||
return token.user
|
||||
except Token.DoesNotExist:
|
||||
return None
|
||||
|
||||
async def disconnect(self, close_code):
|
||||
"""断开WebSocket连接"""
|
||||
try:
|
||||
if hasattr(self, 'room_name'):
|
||||
await self.channel_layer.group_discard(
|
||||
self.room_name,
|
||||
self.channel_name
|
||||
)
|
||||
logger.info(f"用户 {self.user.username} 已断开连接,关闭代码: {close_code}")
|
||||
except Exception as e:
|
||||
logger.error(f"断开连接时发生错误: {str(e)}")
|
||||
|
||||
async def notification(self, event):
|
||||
"""处理并发送通知消息"""
|
||||
try:
|
||||
await self.send(text_data=json.dumps(event))
|
||||
logger.info(f"已发送通知给用户 {self.user.username}")
|
||||
except Exception as e:
|
||||
logger.error(f"发送通知消息时发生错误: {str(e)}")
|
15
user_management/exceptions.py
Normal file
15
user_management/exceptions.py
Normal file
@ -0,0 +1,15 @@
|
||||
from rest_framework.exceptions import APIException
|
||||
from rest_framework import status
|
||||
|
||||
class ExternalAPIError(APIException):
|
||||
"""外部 API 调用错误"""
|
||||
status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
default_detail = '外部 API 调用失败'
|
||||
default_code = 'external_api_error'
|
||||
|
||||
def __init__(self, detail=None, code=None):
|
||||
if detail is None:
|
||||
detail = self.default_detail
|
||||
if code is None:
|
||||
code = self.default_code
|
||||
super().__init__(detail, code)
|
0
user_management/management/__init__.py
Normal file
0
user_management/management/__init__.py
Normal file
BIN
user_management/management/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
user_management/management/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
0
user_management/management/commands/__init__.py
Normal file
0
user_management/management/commands/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
55
user_management/management/commands/create_test_chat_data.py
Normal file
55
user_management/management/commands/create_test_chat_data.py
Normal file
@ -0,0 +1,55 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.auth import get_user_model
|
||||
from user_management.models import ChatHistory
|
||||
from django.utils import timezone
|
||||
import uuid
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '创建聊天测试数据'
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
try:
|
||||
# 获取测试用户
|
||||
user = User.objects.first()
|
||||
if not user:
|
||||
self.stdout.write(self.style.ERROR('没有找到用户,请先创建用户'))
|
||||
return
|
||||
|
||||
# 创建3个不同的对话
|
||||
for i in range(3):
|
||||
conversation_id = f"conv_{uuid.uuid4().hex[:10]}"
|
||||
dataset_id = f"dataset_{i+1}"
|
||||
dataset_name = f"测试数据集_{i+1}"
|
||||
|
||||
# 每个对话创建3轮问答
|
||||
for j in range(3):
|
||||
# 用户问题
|
||||
ChatHistory.objects.create(
|
||||
user=user,
|
||||
dataset_id=dataset_id,
|
||||
dataset_name=dataset_name,
|
||||
conversation_id=conversation_id,
|
||||
role='user',
|
||||
content=f"这是第{i+1}个数据集的第{j+1}个问题?",
|
||||
question=f"这是第{i+1}个数据集的第{j+1}个问题?",
|
||||
answer="",
|
||||
)
|
||||
|
||||
# AI回答
|
||||
ChatHistory.objects.create(
|
||||
user=user,
|
||||
dataset_id=dataset_id,
|
||||
dataset_name=dataset_name,
|
||||
conversation_id=conversation_id,
|
||||
role='assistant',
|
||||
content=f"这是第{i+1}个数据集的第{j+1}个回答。",
|
||||
question="",
|
||||
answer=f"这是第{i+1}个数据集的第{j+1}个回答。",
|
||||
)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS('成功创建测试聊天数据'))
|
||||
|
||||
except Exception as e:
|
||||
self.stdout.write(self.style.ERROR(f'创建测试数据失败: {str(e)}'))
|
139
user_management/management/commands/create_test_users.py
Normal file
139
user_management/management/commands/create_test_users.py
Normal file
@ -0,0 +1,139 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.utils import timezone
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '创建测试用户:1个管理员,2个组长,4个组员'
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
# 创建管理员 - 技术部管理员
|
||||
admin, created = User.objects.get_or_create(
|
||||
username='admin',
|
||||
defaults={
|
||||
'email': 'admin@example.com',
|
||||
'name': '张管理',
|
||||
'role': 'admin',
|
||||
'is_staff': True,
|
||||
'is_superuser': True,
|
||||
'last_login': timezone.now()
|
||||
}
|
||||
)
|
||||
if created:
|
||||
admin.set_password('admin123')
|
||||
admin.save()
|
||||
token = Token.objects.create(user=admin)
|
||||
self.stdout.write(self.style.SUCCESS(
|
||||
f'成功创建管理员用户: {admin.username}({admin.name}), Token: {token.key}'
|
||||
))
|
||||
else:
|
||||
self.stdout.write(self.style.WARNING(f'管理员用户已存在: {admin.username}'))
|
||||
|
||||
# 创建组长 - 研发部组长和测试部组长
|
||||
leaders = [
|
||||
{
|
||||
'username': 'leader1',
|
||||
'password': 'leader123',
|
||||
'email': 'leader1@example.com',
|
||||
'name': '李研发',
|
||||
'department': '研发部',
|
||||
'role': 'leader'
|
||||
},
|
||||
{
|
||||
'username': 'leader2',
|
||||
'password': 'leader123',
|
||||
'email': 'leader2@example.com',
|
||||
'name': '王测试',
|
||||
'department': '测试部',
|
||||
'role': 'leader'
|
||||
}
|
||||
]
|
||||
|
||||
for leader_data in leaders:
|
||||
leader, created = User.objects.get_or_create(
|
||||
username=leader_data['username'],
|
||||
defaults={
|
||||
'email': leader_data['email'],
|
||||
'name': leader_data['name'],
|
||||
'role': leader_data['role'],
|
||||
'department': leader_data['department'],
|
||||
'is_staff': False,
|
||||
'last_login': timezone.now()
|
||||
}
|
||||
)
|
||||
if created:
|
||||
leader.set_password(leader_data['password'])
|
||||
leader.save()
|
||||
token = Token.objects.create(user=leader)
|
||||
self.stdout.write(self.style.SUCCESS(
|
||||
f'成功创建组长用户: {leader.username}({leader.name}), Token: {token.key}'
|
||||
))
|
||||
else:
|
||||
self.stdout.write(self.style.WARNING(f'组长用户已存在: {leader.username}'))
|
||||
|
||||
# 创建组员 - 2个开发组员,2个测试组员
|
||||
members = [
|
||||
{
|
||||
'username': 'member1',
|
||||
'password': 'member123',
|
||||
'email': 'member1@example.com',
|
||||
'name': '赵开发',
|
||||
'department': '研发部',
|
||||
'role': 'member',
|
||||
'group': '前端组'
|
||||
},
|
||||
{
|
||||
'username': 'member2',
|
||||
'password': 'member123',
|
||||
'email': 'member2@example.com',
|
||||
'name': '钱开发',
|
||||
'department': '研发部',
|
||||
'role': 'member',
|
||||
'group': '后端组'
|
||||
},
|
||||
{
|
||||
'username': 'member3',
|
||||
'password': 'member123',
|
||||
'email': 'member3@example.com',
|
||||
'name': '孙测试',
|
||||
'department': '测试部',
|
||||
'role': 'member',
|
||||
'group': '功能测试组'
|
||||
},
|
||||
{
|
||||
'username': 'member4',
|
||||
'password': 'member123',
|
||||
'email': 'member4@example.com',
|
||||
'name': '周测试',
|
||||
'department': '测试部',
|
||||
'role': 'member',
|
||||
'group': '自动化测试组'
|
||||
}
|
||||
]
|
||||
|
||||
for member_data in members:
|
||||
member, created = User.objects.get_or_create(
|
||||
username=member_data['username'],
|
||||
defaults={
|
||||
'email': member_data['email'],
|
||||
'name': member_data['name'],
|
||||
'role': member_data['role'],
|
||||
'department': member_data['department'],
|
||||
'group': member_data['group'],
|
||||
'is_staff': False,
|
||||
'last_login': timezone.now()
|
||||
}
|
||||
)
|
||||
if created:
|
||||
member.set_password(member_data['password'])
|
||||
member.save()
|
||||
token = Token.objects.create(user=member)
|
||||
self.stdout.write(self.style.SUCCESS(
|
||||
f'成功创建组员用户: {member.username}({member.name}), Token: {token.key}'
|
||||
))
|
||||
else:
|
||||
self.stdout.write(self.style.WARNING(f'组员用户已存在: {member.username}'))
|
||||
|
||||
self.stdout.write(self.style.SUCCESS('所有测试用户创建完成!'))
|
54
user_management/middleware.py
Normal file
54
user_management/middleware.py
Normal file
@ -0,0 +1,54 @@
|
||||
from channels.middleware import BaseMiddleware
|
||||
from channels.db import database_sync_to_async
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from rest_framework.authtoken.models import Token
|
||||
from django.contrib.auth import get_user_model
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
User = get_user_model() # 获取当前项目的用户模型
|
||||
|
||||
@database_sync_to_async
|
||||
def get_user(token_key):
|
||||
"""异步获取用户信息"""
|
||||
try:
|
||||
token = Token.objects.get(key=token_key)
|
||||
logger.info(f"用户认证成功: {token.user.username}")
|
||||
return token.user
|
||||
except Token.DoesNotExist:
|
||||
logger.warning(f"无效的token: {token_key}")
|
||||
return AnonymousUser()
|
||||
except Exception as e:
|
||||
logger.error(f"认证错误: {str(e)}")
|
||||
return AnonymousUser()
|
||||
|
||||
class TokenAuthMiddleware(BaseMiddleware):
|
||||
"""Token认证中间件"""
|
||||
async def __call__(self, scope, receive, send):
|
||||
try:
|
||||
# 从请求头获取token
|
||||
headers = dict(scope['headers'])
|
||||
if b'authorization' in headers:
|
||||
token_name, token_key = headers[b'authorization'].decode().split()
|
||||
if token_name == 'Token':
|
||||
scope['user'] = await get_user(token_key)
|
||||
return await super().__call__(scope, receive, send)
|
||||
|
||||
# 如果没有token或token无效
|
||||
scope['user'] = AnonymousUser()
|
||||
return await super().__call__(scope, receive, send)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"WebSocket认证错误: {str(e)}")
|
||||
scope['user'] = AnonymousUser()
|
||||
return await super().__call__(scope, receive, send)
|
||||
|
||||
class UserActivityMiddleware:
|
||||
"""用户活动中间件"""
|
||||
def __init__(self, get_response):
|
||||
self.get_response = get_response
|
||||
|
||||
def __call__(self, request):
|
||||
response = self.get_response(request)
|
||||
return response
|
220
user_management/migrations/0001_initial.py
Normal file
220
user_management/migrations/0001_initial.py
Normal file
@ -0,0 +1,220 @@
|
||||
# Generated by Django 5.1.5 on 2025-02-26 09:23
|
||||
|
||||
import django.contrib.auth.models
|
||||
import django.contrib.auth.validators
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
import uuid
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='User',
|
||||
fields=[
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
||||
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
|
||||
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
||||
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
|
||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||
('name', models.CharField(default='未设置', max_length=150, verbose_name='真实姓名')),
|
||||
('role', models.CharField(choices=[('admin', '管理员'), ('leader', '组长'), ('member', '组员')], default='member', max_length=20, verbose_name='角色')),
|
||||
('department', models.CharField(default='未分配', max_length=100, verbose_name='部门')),
|
||||
('group', models.CharField(blank=True, max_length=100, null=True, verbose_name='小组')),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '用户',
|
||||
'verbose_name_plural': '用户',
|
||||
'db_table': 'users',
|
||||
},
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Data',
|
||||
fields=[
|
||||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||
('name', models.CharField(help_text='数据名称', max_length=100)),
|
||||
('desc', models.TextField(blank=True, help_text='数据描述')),
|
||||
('type', models.CharField(choices=[('admin', '管理员数据'), ('leader', '组长数据'), ('member', '组员数据')], max_length=10)),
|
||||
('meta', models.JSONField(blank=True, default=dict, help_text='元数据')),
|
||||
('user_id', models.UUIDField(help_text='创建者ID')),
|
||||
('department', models.CharField(blank=True, max_length=50)),
|
||||
('char_length', models.IntegerField(blank=True, help_text='字符长度', null=True)),
|
||||
('document_count', models.IntegerField(blank=True, help_text='文档数量', null=True)),
|
||||
('application_mapping_count', models.IntegerField(default=0, help_text='应用映射数量')),
|
||||
('create_time', models.DateTimeField(auto_now_add=True)),
|
||||
('update_time', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'user_data',
|
||||
'indexes': [models.Index(fields=['type', 'user_id'], name='user_data_type_37f45e_idx'), models.Index(fields=['create_time'], name='user_data_create__675afa_idx')],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='KnowledgeBase',
|
||||
fields=[
|
||||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='知识库名称')),
|
||||
('desc', models.TextField(blank=True, null=True, verbose_name='知识库描述')),
|
||||
('type', models.CharField(choices=[('admin', '管理级知识库'), ('leader', '部门级知识库'), ('member', '成员级知识库'), ('private', '私有知识库'), ('secret', '公司级别私密知识库')], default='private', max_length=20, verbose_name='知识库类型')),
|
||||
('department', models.CharField(blank=True, max_length=50, null=True)),
|
||||
('group', models.CharField(blank=True, max_length=50, null=True)),
|
||||
('user_id', models.CharField(max_length=50, verbose_name='创建者ID')),
|
||||
('documents', models.JSONField(default=list)),
|
||||
('char_length', models.IntegerField(default=0)),
|
||||
('document_count', models.IntegerField(default=0)),
|
||||
('external_id', models.UUIDField(blank=True, null=True)),
|
||||
('create_time', models.DateTimeField(auto_now_add=True)),
|
||||
('update_time', models.DateTimeField(auto_now=True)),
|
||||
('owners', models.ManyToManyField(related_name='owned_knowledge_bases', to=settings.AUTH_USER_MODEL, verbose_name='所有者')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'knowledge_bases',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ChatHistory',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('conversation_id', models.CharField(db_index=True, max_length=100)),
|
||||
('parent_id', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('role', models.CharField(choices=[('user', '用户'), ('assistant', 'AI助手'), ('system', '系统')], max_length=20)),
|
||||
('content', models.TextField()),
|
||||
('tokens', models.IntegerField(default=0, help_text='消息token数')),
|
||||
('metadata', models.JSONField(blank=True, default=dict)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('is_deleted', models.BooleanField(default=False)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
('knowledge_base', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='user_management.knowledgebase')),
|
||||
],
|
||||
options={
|
||||
'db_table': 'chat_history',
|
||||
'ordering': ['created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='KnowledgeBasePermission',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('can_read', models.BooleanField(default=False, verbose_name='查看权限')),
|
||||
('can_edit', models.BooleanField(default=False, verbose_name='修改权限')),
|
||||
('can_delete', models.BooleanField(default=False, verbose_name='删除权限')),
|
||||
('status', models.CharField(choices=[('active', '生效中'), ('expired', '已过期'), ('revoked', '已撤销')], default='active', max_length=10, verbose_name='状态')),
|
||||
('granted_at', models.DateTimeField(auto_now_add=True, verbose_name='授权时间')),
|
||||
('expires_at', models.DateTimeField(blank=True, null=True, verbose_name='过期时间')),
|
||||
('granted_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='granted_permissions', to=settings.AUTH_USER_MODEL, verbose_name='授权人')),
|
||||
('knowledge_base', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_permissions', to='user_management.knowledgebase', verbose_name='知识库')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='knowledge_base_permissions', to=settings.AUTH_USER_MODEL, verbose_name='用户')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '知识库权限',
|
||||
'verbose_name_plural': '知识库权限',
|
||||
'db_table': 'knowledge_base_permissions',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Notification',
|
||||
fields=[
|
||||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
|
||||
('type', models.CharField(choices=[('permission_request', '权限申请'), ('permission_approved', '权限批准'), ('permission_rejected', '权限拒绝'), ('permission_expired', '权限过期'), ('system_notice', '系统通知')], max_length=20)),
|
||||
('title', models.CharField(max_length=100)),
|
||||
('content', models.TextField()),
|
||||
('is_read', models.BooleanField(default=False)),
|
||||
('related_resource', models.CharField(blank=True, max_length=100)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('receiver', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='received_notifications', to=settings.AUTH_USER_MODEL)),
|
||||
('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sent_notifications', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Permission',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('permissions', models.JSONField(default=dict, verbose_name='权限配置')),
|
||||
('status', models.CharField(choices=[('pending', '待审批'), ('approved', '已批准'), ('rejected', '已拒绝')], default='pending', max_length=20, verbose_name='状态')),
|
||||
('reason', models.TextField(verbose_name='申请原因')),
|
||||
('response_message', models.TextField(blank=True, null=True, verbose_name='审批意见')),
|
||||
('expires_at', models.DateTimeField(blank=True, null=True, verbose_name='过期时间')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('applicant', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='permission_applications', to=settings.AUTH_USER_MODEL, verbose_name='申请人')),
|
||||
('approver', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='permission_approvals', to=settings.AUTH_USER_MODEL, verbose_name='审批人')),
|
||||
('knowledge_base', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='permissions', to='user_management.knowledgebase', verbose_name='知识库')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '权限申请',
|
||||
'verbose_name_plural': '权限申请',
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserProfile',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('department', models.CharField(blank=True, help_text='部门', max_length=100)),
|
||||
('group', models.CharField(blank=True, help_text='小组', max_length=100)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'user_profiles',
|
||||
},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='knowledgebase',
|
||||
index=models.Index(fields=['type'], name='knowledge_b_type_0439e7_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='knowledgebase',
|
||||
index=models.Index(fields=['department'], name='knowledge_b_departm_e739fd_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='knowledgebase',
|
||||
index=models.Index(fields=['group'], name='knowledge_b_group_3dcf34_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='chathistory',
|
||||
index=models.Index(fields=['conversation_id', 'created_at'], name='chat_histor_convers_33721a_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='chathistory',
|
||||
index=models.Index(fields=['user', 'created_at'], name='chat_histor_user_id_aa050a_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='knowledgebasepermission',
|
||||
index=models.Index(fields=['knowledge_base', 'user', 'status'], name='knowledge_b_knowled_88e81e_idx'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='knowledgebasepermission',
|
||||
unique_together={('knowledge_base', 'user')},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='notification',
|
||||
index=models.Index(fields=['receiver', '-created_at'], name='user_manage_receive_fcb0eb_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='notification',
|
||||
index=models.Index(fields=['type', 'is_read'], name='user_manage_type_362052_idx'),
|
||||
),
|
||||
]
|
0
user_management/migrations/__init__.py
Normal file
0
user_management/migrations/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
user_management/migrations/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
user_management/migrations/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
549
user_management/models.py
Normal file
549
user_management/models.py
Normal file
@ -0,0 +1,549 @@
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.core.exceptions import ValidationError
|
||||
import uuid
|
||||
import logging
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class User(AbstractUser):
|
||||
"""自定义用户模型"""
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
|
||||
ROLE_CHOICES = (
|
||||
('admin', '管理员'),
|
||||
('leader', '组长'),
|
||||
('member', '组员'),
|
||||
)
|
||||
|
||||
name = models.CharField(max_length=150, verbose_name='真实姓名', default='未设置')
|
||||
role = models.CharField(max_length=20, choices=ROLE_CHOICES, verbose_name='角色', default='member')
|
||||
department = models.CharField(max_length=100, verbose_name='部门', default='未分配')
|
||||
group = models.CharField(max_length=100, null=True, blank=True, verbose_name='小组')
|
||||
|
||||
class Meta:
|
||||
db_table = 'users'
|
||||
verbose_name = '用户'
|
||||
verbose_name_plural = '用户'
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.username}({self.name})"
|
||||
|
||||
def can_manage_department(self):
|
||||
"""检查是否可以管理部门"""
|
||||
return self.role in ['admin', 'leader']
|
||||
|
||||
def can_manage_knowledge_base(self, knowledge_base):
|
||||
"""检查是否可以管理知识库"""
|
||||
if self.role == 'admin':
|
||||
return knowledge_base.type != 'private' # 管理员不能管理私人知识库
|
||||
if self.role == 'leader' and self.department == knowledge_base.department:
|
||||
return knowledge_base.type == 'member' # 组长只能管理本部门的成员知识库
|
||||
return knowledge_base.user_id == str(self.id) # 用户可以管理自己创建的知识库
|
||||
|
||||
def has_access_permission(self, knowledge_base):
|
||||
"""检查用户是否有权限访问知识库"""
|
||||
|
||||
# 1. 如果是私人知识库
|
||||
if knowledge_base.type == 'private':
|
||||
# 创建者直接允许
|
||||
if str(knowledge_base.user_id) == str(self.id):
|
||||
return True
|
||||
# 其他人需要申请权限
|
||||
return Permission.objects.filter(
|
||||
resource_type='knowledge',
|
||||
resource_id=str(knowledge_base.id),
|
||||
applicant=self,
|
||||
status='approved',
|
||||
expires_at__gt=timezone.now()
|
||||
).exists()
|
||||
|
||||
# 2. 如果是管理级知识库
|
||||
if knowledge_base.type == 'admin':
|
||||
# 管理员直接允许
|
||||
if self.role == 'admin':
|
||||
return True
|
||||
# 其他人需要申请权限
|
||||
return Permission.objects.filter(
|
||||
resource_type='knowledge',
|
||||
resource_id=str(knowledge_base.id),
|
||||
applicant=self,
|
||||
status='approved'
|
||||
).exists()
|
||||
|
||||
# 3. 如果是部门级知识库
|
||||
if knowledge_base.type == 'leader':
|
||||
# 同部门的管理员和组长可以访问
|
||||
if self.department == knowledge_base.department:
|
||||
return self.role in ['admin', 'leader']
|
||||
return False
|
||||
|
||||
# 4. 如果是成员级知识库
|
||||
if knowledge_base.type == 'member':
|
||||
# 同部门的所有人可以访问
|
||||
return self.department == knowledge_base.department
|
||||
|
||||
class Data(models.Model):
|
||||
"""统一的数据模型"""
|
||||
DATA_TYPES = (
|
||||
('admin', '管理员数据'),
|
||||
('leader', '组长数据'),
|
||||
('member', '组员数据'),
|
||||
)
|
||||
|
||||
# 基本信息
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
name = models.CharField(max_length=100, help_text="数据名称")
|
||||
desc = models.TextField(blank=True, help_text="数据描述")
|
||||
type = models.CharField(max_length=10, choices=DATA_TYPES)
|
||||
meta = models.JSONField(default=dict, blank=True, help_text="元数据")
|
||||
|
||||
# 关联信息
|
||||
user_id = models.UUIDField(help_text="创建者ID")
|
||||
department = models.CharField(max_length=50, blank=True)
|
||||
|
||||
# 统计信息
|
||||
char_length = models.IntegerField(null=True, blank=True, help_text="字符长度")
|
||||
document_count = models.IntegerField(null=True, blank=True, help_text="文档数量")
|
||||
application_mapping_count = models.IntegerField(default=0, help_text="应用映射数量")
|
||||
|
||||
# 时间信息
|
||||
create_time = models.DateTimeField(auto_now_add=True)
|
||||
update_time = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'user_data'
|
||||
indexes = [
|
||||
models.Index(fields=['type', 'user_id']),
|
||||
models.Index(fields=['create_time']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.get_type_display()})"
|
||||
|
||||
def publish(self):
|
||||
"""发布数据"""
|
||||
if self.status == 'draft':
|
||||
self.status = 'published'
|
||||
self.published_at = timezone.now()
|
||||
self.save()
|
||||
logger.info(f"Data {self.id} published by {self.owner.username}")
|
||||
|
||||
def archive(self):
|
||||
"""归档数据"""
|
||||
if self.status == 'published':
|
||||
self.status = 'archived'
|
||||
self.archived_at = timezone.now()
|
||||
self.save()
|
||||
logger.info(f"Data {self.id} archived by {self.owner.username}")
|
||||
|
||||
class Notification(models.Model):
|
||||
"""通知模型"""
|
||||
NOTIFICATION_TYPES = (
|
||||
('permission_request', '权限申请'),
|
||||
('permission_approved', '权限批准'),
|
||||
('permission_rejected', '权限拒绝'),
|
||||
('permission_expired', '权限过期'),
|
||||
('system_notice', '系统通知'),
|
||||
)
|
||||
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
type = models.CharField(max_length=20, choices=NOTIFICATION_TYPES)
|
||||
title = models.CharField(max_length=100)
|
||||
content = models.TextField()
|
||||
sender = models.ForeignKey('User', on_delete=models.CASCADE, related_name='sent_notifications')
|
||||
receiver = models.ForeignKey('User', on_delete=models.CASCADE, related_name='received_notifications')
|
||||
is_read = models.BooleanField(default=False)
|
||||
related_resource = models.CharField(max_length=100, blank=True) # 相关资源ID
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-created_at']
|
||||
indexes = [
|
||||
models.Index(fields=['receiver', '-created_at']),
|
||||
models.Index(fields=['type', 'is_read']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.get_type_display()} - {self.title}"
|
||||
|
||||
class Permission(models.Model):
|
||||
"""权限申请模型"""
|
||||
STATUS_CHOICES = (
|
||||
('pending', '待审批'),
|
||||
('approved', '已批准'),
|
||||
('rejected', '已拒绝'),
|
||||
)
|
||||
|
||||
knowledge_base = models.ForeignKey(
|
||||
'KnowledgeBase',
|
||||
on_delete=models.CASCADE,
|
||||
related_name='permissions',
|
||||
verbose_name='知识库'
|
||||
)
|
||||
applicant = models.ForeignKey(
|
||||
'User',
|
||||
on_delete=models.CASCADE,
|
||||
related_name='permission_applications',
|
||||
verbose_name='申请人'
|
||||
)
|
||||
approver = models.ForeignKey(
|
||||
'User',
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='permission_approvals',
|
||||
verbose_name='审批人'
|
||||
)
|
||||
|
||||
permissions = models.JSONField(default=dict, verbose_name='权限配置') # {"can_read": true, "can_edit": false, "can_delete": false}
|
||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending', verbose_name='状态')
|
||||
reason = models.TextField(verbose_name='申请原因')
|
||||
response_message = models.TextField(null=True, blank=True, verbose_name='审批意见')
|
||||
expires_at = models.DateTimeField(null=True, blank=True, verbose_name='过期时间') # 修改为可空
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
|
||||
|
||||
class Meta:
|
||||
verbose_name = '权限申请'
|
||||
verbose_name_plural = '权限申请'
|
||||
ordering = ['-created_at']
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.applicant} 申请 {self.knowledge_base} 的权限"
|
||||
|
||||
def clean(self):
|
||||
"""验证权限申请的合法性"""
|
||||
try:
|
||||
# 检查是否是自己的知识库
|
||||
if str(self.knowledge_base.user_id) == str(self.applicant.id):
|
||||
raise ValidationError('不能申请访问自己的知识库')
|
||||
except KnowledgeBase.DoesNotExist:
|
||||
raise ValidationError('知识库不存在')
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.clean()
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def approve(self, approver, response_message=''):
|
||||
"""批准权限申请"""
|
||||
if self.status == 'pending':
|
||||
self.status = 'approved'
|
||||
self.approver = approver
|
||||
self.response_message = response_message
|
||||
self.save()
|
||||
|
||||
def reject(self, approver, response_message=''):
|
||||
"""拒绝权限申请"""
|
||||
if self.status == 'pending':
|
||||
self.status = 'rejected'
|
||||
self.approver = approver
|
||||
self.response_message = response_message
|
||||
self.save()
|
||||
|
||||
def check_expiration(self):
|
||||
"""检查权限是否过期"""
|
||||
if self.status == 'approved' and self.expires_at and self.expires_at < timezone.now():
|
||||
self.status = 'expired'
|
||||
self.save()
|
||||
logger.info(f"Permission {self.id} expired")
|
||||
|
||||
def send_notification(self, notification_type, title, content):
|
||||
"""发送通知"""
|
||||
Notification.objects.create(
|
||||
type=notification_type,
|
||||
title=title,
|
||||
content=content,
|
||||
sender=self.applicant,
|
||||
receiver=self.approver if notification_type == 'permission_request' else self.applicant,
|
||||
related_resource=str(self.id)
|
||||
)
|
||||
|
||||
def notify_approver(self):
|
||||
"""通知审批人"""
|
||||
self.send_notification(
|
||||
'permission_request',
|
||||
f'新的权限申请 - {self.get_resource_type_display()}',
|
||||
f'用户 {self.applicant.username} 申请访问 {self.get_resource_type_display()} 的权限'
|
||||
)
|
||||
|
||||
def notify_applicant(self, status):
|
||||
"""通知申请人审批结果"""
|
||||
notification_type = 'permission_approved' if status == 'approved' else 'permission_rejected'
|
||||
title = f'权限申请{self.get_status_display()} - {self.get_resource_type_display()}'
|
||||
content = f'您申请的 {self.get_resource_type_display()} 权限已{self.get_status_display()}'
|
||||
self.send_notification(notification_type, title, content)
|
||||
|
||||
class ChatHistory(models.Model):
|
||||
"""聊天历史记录"""
|
||||
ROLE_CHOICES = [
|
||||
('user', '用户'),
|
||||
('assistant', 'AI助手'),
|
||||
('system', '系统')
|
||||
]
|
||||
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
knowledge_base = models.ForeignKey('KnowledgeBase', on_delete=models.CASCADE)
|
||||
conversation_id = models.CharField(max_length=100, db_index=True)
|
||||
parent_id = models.CharField(max_length=100, null=True, blank=True)
|
||||
role = models.CharField(max_length=20, choices=ROLE_CHOICES)
|
||||
content = models.TextField()
|
||||
tokens = models.IntegerField(default=0, help_text="消息token数")
|
||||
metadata = models.JSONField(default=dict, blank=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
is_deleted = models.BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
db_table = 'chat_history'
|
||||
ordering = ['created_at']
|
||||
indexes = [
|
||||
models.Index(fields=['conversation_id', 'created_at']),
|
||||
models.Index(fields=['user', 'created_at']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.user.username} - {self.knowledge_base.name} - {self.created_at}"
|
||||
|
||||
@classmethod
|
||||
def get_conversation(cls, conversation_id):
|
||||
"""获取完整对话历史"""
|
||||
return cls.objects.filter(
|
||||
conversation_id=conversation_id,
|
||||
is_deleted=False
|
||||
).order_by('created_at')
|
||||
|
||||
def soft_delete(self):
|
||||
"""软删除消息"""
|
||||
self.is_deleted = True
|
||||
self.save()
|
||||
|
||||
class UserProfile(models.Model):
|
||||
"""用户档案模型"""
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
|
||||
department = models.CharField(max_length=100, blank=True, help_text="部门")
|
||||
group = models.CharField(max_length=100, blank=True, help_text="小组")
|
||||
|
||||
class Meta:
|
||||
db_table = 'user_profiles'
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.user.username}'s profile"
|
||||
|
||||
class KnowledgeBasePermission(models.Model):
|
||||
"""知识库权限模型 - 实现知识库和用户的多对多关系"""
|
||||
STATUS_CHOICES = (
|
||||
('active', '生效中'),
|
||||
('expired', '已过期'),
|
||||
('revoked', '已撤销'),
|
||||
)
|
||||
|
||||
knowledge_base = models.ForeignKey(
|
||||
'KnowledgeBase',
|
||||
on_delete=models.CASCADE,
|
||||
related_name='user_permissions',
|
||||
verbose_name='知识库'
|
||||
)
|
||||
user = models.ForeignKey(
|
||||
'User',
|
||||
on_delete=models.CASCADE,
|
||||
related_name='knowledge_base_permissions',
|
||||
verbose_name='用户'
|
||||
)
|
||||
|
||||
# 基础权限
|
||||
can_read = models.BooleanField(default=False, verbose_name='查看权限')
|
||||
can_edit = models.BooleanField(default=False, verbose_name='修改权限')
|
||||
can_delete = models.BooleanField(default=False, verbose_name='删除权限')
|
||||
|
||||
# 权限状态
|
||||
status = models.CharField(
|
||||
max_length=10,
|
||||
choices=STATUS_CHOICES,
|
||||
default='active',
|
||||
verbose_name='状态'
|
||||
)
|
||||
|
||||
# 授权信息
|
||||
granted_by = models.ForeignKey(
|
||||
'User',
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
related_name='granted_permissions',
|
||||
verbose_name='授权人'
|
||||
)
|
||||
granted_at = models.DateTimeField(auto_now_add=True, verbose_name='授权时间')
|
||||
expires_at = models.DateTimeField(null=True, blank=True, verbose_name='过期时间')
|
||||
|
||||
class Meta:
|
||||
app_label = 'user_management'
|
||||
db_table = 'knowledge_base_permissions'
|
||||
unique_together = ['knowledge_base', 'user']
|
||||
indexes = [
|
||||
models.Index(fields=['knowledge_base', 'user', 'status']),
|
||||
]
|
||||
verbose_name = '知识库权限'
|
||||
verbose_name_plural = '知识库权限'
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.user.username} - {self.knowledge_base.name}"
|
||||
|
||||
def is_valid(self):
|
||||
"""检查权限是否有效"""
|
||||
if self.status != 'active':
|
||||
return False
|
||||
if self.expires_at and self.expires_at < timezone.now():
|
||||
self.status = 'expired'
|
||||
self.save()
|
||||
return False
|
||||
return True
|
||||
|
||||
class KnowledgeBase(models.Model):
|
||||
"""知识库模型"""
|
||||
KNOWLEDGE_BASE_TYPES = [
|
||||
('admin', '管理级知识库'),
|
||||
('leader', '部门级知识库'),
|
||||
('member', '成员级知识库'),
|
||||
('private', '私有知识库'),
|
||||
('secret', '公司级别私密知识库'),
|
||||
]
|
||||
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
user_id = models.UUIDField(verbose_name='创建者ID')
|
||||
name = models.CharField(max_length=100, unique=True, verbose_name='知识库名称')
|
||||
desc = models.TextField(verbose_name='知识库描述', null=True, blank=True)
|
||||
type = models.CharField(
|
||||
max_length=20,
|
||||
choices=KNOWLEDGE_BASE_TYPES,
|
||||
default='private',
|
||||
verbose_name='知识库类型'
|
||||
)
|
||||
department = models.CharField(max_length=50, null=True, blank=True)
|
||||
group = models.CharField(max_length=50, null=True, blank=True)
|
||||
documents = models.JSONField(default=list)
|
||||
char_length = models.IntegerField(default=0)
|
||||
document_count = models.IntegerField(default=0)
|
||||
external_id = models.UUIDField(null=True, blank=True)
|
||||
create_time = models.DateTimeField(auto_now_add=True)
|
||||
update_time = models.DateTimeField(auto_now=True)
|
||||
|
||||
def is_owner(self, user):
|
||||
"""检查用户是否是所有者(通过权限表检查)"""
|
||||
return str(user.id) == str(self.user_id) or KnowledgeBasePermission.objects.filter(
|
||||
knowledge_base=self,
|
||||
user=user,
|
||||
can_read=True,
|
||||
can_edit=True,
|
||||
can_delete=True,
|
||||
status='active'
|
||||
).exists()
|
||||
|
||||
def get_owners(self):
|
||||
"""获取所有所有者(包括创建者和具有完整权限的用户)"""
|
||||
from .models import User
|
||||
# 获取创建者
|
||||
owners = [self.user_id]
|
||||
# 获取具有完整权限的用户
|
||||
permission_owners = KnowledgeBasePermission.objects.filter(
|
||||
knowledge_base=self,
|
||||
can_read=True,
|
||||
can_edit=True,
|
||||
can_delete=True,
|
||||
status='active'
|
||||
).values_list('user_id', flat=True)
|
||||
owners.extend(permission_owners)
|
||||
return User.objects.filter(id__in=set(owners))
|
||||
|
||||
def calculate_stats(self):
|
||||
"""计算文档统计信息"""
|
||||
total_chars = 0
|
||||
doc_count = 0
|
||||
|
||||
if self.documents:
|
||||
doc_count = len(self.documents)
|
||||
for doc in self.documents:
|
||||
if 'paragraphs' in doc:
|
||||
for para in doc['paragraphs']:
|
||||
if 'content' in para:
|
||||
total_chars += len(para['content'])
|
||||
if 'title' in para:
|
||||
total_chars += len(para['title'])
|
||||
|
||||
return doc_count, total_chars
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""重写保存方法"""
|
||||
# 只在创建时计算统计信息
|
||||
if not self.pk: # 如果是新实例
|
||||
doc_count, char_count = self.calculate_stats()
|
||||
self.document_count = doc_count
|
||||
self.char_length = char_count
|
||||
|
||||
# 直接调用Model的save方法
|
||||
models.Model.save(self, *args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def update_external_id(cls, instance_id, external_id):
|
||||
"""更新外部ID的静态方法"""
|
||||
cls.objects.filter(id=instance_id).update(external_id=external_id)
|
||||
|
||||
class Meta:
|
||||
db_table = 'knowledge_bases'
|
||||
indexes = [
|
||||
models.Index(fields=['type']),
|
||||
models.Index(fields=['department']),
|
||||
models.Index(fields=['group'])
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.get_type_display()})"
|
||||
|
||||
def clean(self):
|
||||
"""验证知识库类型与创建者权限是否匹配"""
|
||||
try:
|
||||
user = User.objects.get(id=self.user_id)
|
||||
if user.role == 'member' and self.type != 'private':
|
||||
raise ValidationError('组员只能创建私人知识库')
|
||||
if user.role == 'leader' and self.type not in ['member', 'private']:
|
||||
raise ValidationError('组长只能创建成员级或私人知识库')
|
||||
except User.DoesNotExist:
|
||||
raise ValidationError('创建者不存在')
|
||||
|
||||
def to_response_dict(self):
|
||||
"""转换为API响应格式"""
|
||||
return {
|
||||
"create_time": self.create_time.isoformat(),
|
||||
"update_time": self.update_time.isoformat(),
|
||||
"id": str(self.id),
|
||||
"name": self.name,
|
||||
"desc": self.desc,
|
||||
"type": self.type,
|
||||
"meta": self.meta,
|
||||
"user_id": str(self.user_id),
|
||||
"embedding_mode_id": str(self.embedding_mode_id),
|
||||
"char_length": self.char_length,
|
||||
"application_mapping_count": self.application_mapping_count,
|
||||
"document_count": self.document_count
|
||||
}
|
||||
|
||||
def to_external_format(self):
|
||||
"""转换为外部接口格式"""
|
||||
return {
|
||||
"name": self.name,
|
||||
"desc": self.desc,
|
||||
"documents": self.documents
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_external_format(cls, data, user_id, embedding_mode_id):
|
||||
"""从外部接口格式创建实例"""
|
||||
return cls(
|
||||
name=data["name"],
|
||||
desc=data["desc"],
|
||||
documents=data["documents"],
|
||||
user_id=user_id,
|
||||
embedding_mode_id=embedding_mode_id,
|
||||
document_count=len(data["documents"]) if data.get("documents") else 0
|
||||
)
|
160
user_management/permissions.py
Normal file
160
user_management/permissions.py
Normal file
@ -0,0 +1,160 @@
|
||||
from rest_framework import permissions
|
||||
from rest_framework.permissions import SAFE_METHODS
|
||||
from django.utils import timezone
|
||||
from .models import Data, KnowledgeBase, Permission
|
||||
|
||||
|
||||
class DataPermission(permissions.BasePermission):
|
||||
"""数据访问权限控制"""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
# 未认证用户无权限
|
||||
if not request.user.is_authenticated:
|
||||
return False
|
||||
|
||||
# 管理员有全部权限
|
||||
if request.user.role == 'admin':
|
||||
return True
|
||||
|
||||
# GET请求检查
|
||||
if request.method in SAFE_METHODS:
|
||||
return True
|
||||
|
||||
# POST请求权限检查
|
||||
if request.method == 'POST':
|
||||
data_type = request.data.get('type')
|
||||
if data_type == 'admin' and request.user.role != 'admin':
|
||||
return False
|
||||
if data_type == 'leader' and request.user.role not in ['admin', 'leader']:
|
||||
return False
|
||||
return True
|
||||
|
||||
return True
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
user = request.user
|
||||
|
||||
# 管理员有全部权限
|
||||
if user.role == 'admin':
|
||||
return True
|
||||
|
||||
# 对象所有者有全部权限
|
||||
if obj.user_id == str(user.id):
|
||||
return True
|
||||
|
||||
# 组长可以访问本部门数据
|
||||
if user.role == 'leader' and user.department == obj.department:
|
||||
return True
|
||||
|
||||
# 其他情况只允许只读访问
|
||||
return request.method in SAFE_METHODS
|
||||
|
||||
|
||||
class KnowledgeBasePermission(permissions.BasePermission):
|
||||
"""知识库权限控制"""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
if not request.user.is_authenticated:
|
||||
return False
|
||||
|
||||
# GET请求允许访问
|
||||
if request.method in permissions.SAFE_METHODS:
|
||||
return True
|
||||
|
||||
return True
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
user = request.user
|
||||
|
||||
# admin类型: 所有人都可以操作
|
||||
if obj.type == 'admin':
|
||||
return True
|
||||
|
||||
# leader类型: 管理员和本部门组长可以操作
|
||||
if obj.type == 'leader':
|
||||
if user.role == 'admin':
|
||||
return True
|
||||
if user.role == 'leader' and user.department == obj.department:
|
||||
return True
|
||||
return False
|
||||
|
||||
# member类型: 管理员、本部门组长可以操作,本部门组员可以查看
|
||||
if obj.type == 'member':
|
||||
if user.role == 'admin':
|
||||
return True
|
||||
if user.role == 'leader' and user.department == obj.department:
|
||||
return True
|
||||
if user.role == 'member' and user.department == obj.department:
|
||||
return request.method in permissions.SAFE_METHODS
|
||||
return False
|
||||
|
||||
# private类型: 创建者可以操作,其他人需要申请权限
|
||||
if obj.type == 'private':
|
||||
# 创建者可以操作
|
||||
if str(obj.user_id) == str(user.id):
|
||||
return True
|
||||
# 其他人需要申请权限
|
||||
return Permission.objects.filter(
|
||||
resource_type='knowledge',
|
||||
resource_id=str(obj.id),
|
||||
applicant=user,
|
||||
status='approved',
|
||||
expires_at__gt=timezone.now()
|
||||
).exists()
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class PermissionRequestPermission(permissions.BasePermission):
|
||||
"""权限申请的权限控制"""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
return request.user.is_authenticated
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
user = request.user
|
||||
|
||||
# 申请人可以查看自己的申请
|
||||
if obj.applicant == user:
|
||||
return True
|
||||
|
||||
# 审批人可以处理权限申请
|
||||
if obj.approver == user:
|
||||
return True
|
||||
|
||||
# 管理员可以查看所有申请
|
||||
if user.role == 'admin':
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class ResourceCRUDPermission(permissions.BasePermission):
|
||||
"""资源CRUD权限控制"""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
if not request.user.is_authenticated:
|
||||
return False
|
||||
|
||||
if request.user.role == 'admin':
|
||||
return True
|
||||
|
||||
if request.method in SAFE_METHODS:
|
||||
return True
|
||||
|
||||
return True
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
user = request.user
|
||||
|
||||
if user.role == 'admin':
|
||||
return True
|
||||
|
||||
if hasattr(obj, 'user_id') and str(obj.user_id) == str(user.id):
|
||||
return True
|
||||
|
||||
if hasattr(obj, 'department') and user.role == 'leader' and user.department == obj.department:
|
||||
return True
|
||||
|
||||
return request.method in SAFE_METHODS
|
||||
|
6
user_management/routing.py
Normal file
6
user_management/routing.py
Normal file
@ -0,0 +1,6 @@
|
||||
from django.urls import re_path
|
||||
from . import consumers
|
||||
|
||||
websocket_urlpatterns = [
|
||||
re_path(r'ws/notifications/$', consumers.NotificationConsumer.as_asgi()),
|
||||
]
|
140
user_management/serializers.py
Normal file
140
user_management/serializers.py
Normal file
@ -0,0 +1,140 @@
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from .models import User, Data, Permission, ChatHistory, KnowledgeBase, Notification
|
||||
import uuid
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ['id', 'username', 'email', 'role', 'department', 'phone', 'avatar']
|
||||
read_only_fields = ['id']
|
||||
|
||||
class DataSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Data
|
||||
fields = [
|
||||
'id', 'name', 'desc', 'type', 'meta',
|
||||
'user_id', 'department', 'char_length',
|
||||
'document_count', 'application_mapping_count',
|
||||
'create_time', 'update_time'
|
||||
]
|
||||
read_only_fields = ['id', 'create_time', 'update_time', 'user_id']
|
||||
|
||||
def validate(self, data):
|
||||
request = self.context.get('request')
|
||||
if not request or not request.user.is_authenticated:
|
||||
raise ValidationError("用户未认证")
|
||||
|
||||
# 验证数据类型权限
|
||||
user = request.user
|
||||
data_type = data.get('type')
|
||||
if data_type == 'admin' and user.role != 'admin':
|
||||
raise ValidationError("只有管理员可以创建管理员数据")
|
||||
elif data_type == 'leader' and user.role not in ['admin', 'leader']:
|
||||
raise ValidationError("只有管理员和组长可以创建组长数据")
|
||||
|
||||
return data
|
||||
|
||||
class PermissionSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Permission
|
||||
fields = [
|
||||
'id',
|
||||
'knowledge_base',
|
||||
'applicant',
|
||||
'permissions',
|
||||
'status',
|
||||
'reason',
|
||||
'response_message',
|
||||
'expires_at',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
]
|
||||
read_only_fields = [
|
||||
'id',
|
||||
'applicant',
|
||||
'status',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
]
|
||||
|
||||
class ChatHistorySerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ChatHistory
|
||||
fields = [
|
||||
'id', 'user', 'knowledge_base',
|
||||
'conversation_id', 'parent_id', 'role',
|
||||
'content', 'create_time'
|
||||
]
|
||||
read_only_fields = ['id', 'create_time']
|
||||
|
||||
class KnowledgeBaseSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = KnowledgeBase
|
||||
fields = '__all__'
|
||||
read_only_fields = ('user_id',) # 移除 owners
|
||||
|
||||
def create(self, validated_data):
|
||||
"""创建时自动设置 user_id"""
|
||||
request = self.context.get('request')
|
||||
if not request or not hasattr(request, 'user'):
|
||||
raise serializers.ValidationError('无法获取当前用户信息')
|
||||
|
||||
user = request.user
|
||||
if not user.is_authenticated:
|
||||
raise serializers.ValidationError('用户未登录')
|
||||
|
||||
# 设置 user_id
|
||||
validated_data['user_id'] = user.id
|
||||
|
||||
logger.info(f"设置知识库创建者: user_id={user.id}, username={user.username}")
|
||||
|
||||
return super().create(validated_data)
|
||||
|
||||
class KnowledgePermissionSerializer(serializers.ModelSerializer):
|
||||
"""知识库权限序列化器"""
|
||||
|
||||
class Meta:
|
||||
model = Permission
|
||||
fields = [
|
||||
'id',
|
||||
'resource_type',
|
||||
'resource_id',
|
||||
'applicant',
|
||||
'approver',
|
||||
'operations',
|
||||
'status',
|
||||
'expires_at',
|
||||
'create_time',
|
||||
'update_time'
|
||||
]
|
||||
read_only_fields = ['id', 'create_time', 'update_time']
|
||||
|
||||
def validate(self, data):
|
||||
"""验证权限申请数据"""
|
||||
if data['resource_type'] != 'knowledge':
|
||||
raise serializers.ValidationError("资源类型必须是知识库")
|
||||
|
||||
# 验证知识库是否存在
|
||||
try:
|
||||
KnowledgeBase.objects.get(id=data['resource_id'])
|
||||
except KnowledgeBase.DoesNotExist:
|
||||
raise serializers.ValidationError("知识库不存在")
|
||||
|
||||
return data
|
||||
|
||||
def create(self, validated_data):
|
||||
"""创建权限申请"""
|
||||
validated_data['resource_type'] = 'knowledge'
|
||||
return super().create(validated_data)
|
||||
|
||||
class NotificationSerializer(serializers.ModelSerializer):
|
||||
"""通知序列化器"""
|
||||
class Meta:
|
||||
model = Notification
|
||||
fields = ['id', 'type', 'title', 'content', 'sender', 'receiver',
|
||||
'is_read', 'related_resource', 'created_at']
|
||||
read_only_fields = ['id', 'created_at']
|
3
user_management/tests.py
Normal file
3
user_management/tests.py
Normal file
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
43
user_management/urls.py
Normal file
43
user_management/urls.py
Normal file
@ -0,0 +1,43 @@
|
||||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from .views import (
|
||||
KnowledgeBaseViewSet,
|
||||
PermissionViewSet,
|
||||
NotificationViewSet,
|
||||
verify_token,
|
||||
user_list,
|
||||
user_detail,
|
||||
user_update,
|
||||
user_delete,
|
||||
change_password,
|
||||
RegisterView,
|
||||
LoginView,
|
||||
LogoutView
|
||||
)
|
||||
|
||||
# 创建路由器
|
||||
router = DefaultRouter()
|
||||
|
||||
# 注册视图集
|
||||
router.register(r'knowledge-bases', KnowledgeBaseViewSet, basename='knowledge-base')
|
||||
router.register(r'permissions', PermissionViewSet, basename='permission')
|
||||
router.register(r'notifications', NotificationViewSet, basename='notification')
|
||||
|
||||
# URL patterns
|
||||
urlpatterns = [
|
||||
# API 路由
|
||||
path('', include(router.urls)),
|
||||
|
||||
# 用户认证相关
|
||||
path('auth/register/', RegisterView.as_view(), name='register'),
|
||||
path('auth/login/', LoginView.as_view(), name='login'),
|
||||
path('auth/logout/', LogoutView.as_view(), name='logout'),
|
||||
path('auth/verify-token/', verify_token, name='verify-token'),
|
||||
path('auth/change-password/', change_password, name='change-password'),
|
||||
|
||||
# 用户管理相关
|
||||
path('users/', user_list, name='user-list'),
|
||||
path('users/<str:pk>/', user_detail, name='user-detail'),
|
||||
path('users/<str:pk>/update/', user_update, name='user-update'),
|
||||
path('users/<str:pk>/delete/', user_delete, name='user-delete'),
|
||||
]
|
1833
user_management/views.py
Normal file
1833
user_management/views.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1 @@
|
||||
pip
|
21
venv/Lib/site-packages/Automat-24.8.1.dist-info/LICENSE
Normal file
21
venv/Lib/site-packages/Automat-24.8.1.dist-info/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
Copyright (c) 2014
|
||||
Rackspace
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
199
venv/Lib/site-packages/Automat-24.8.1.dist-info/METADATA
Normal file
199
venv/Lib/site-packages/Automat-24.8.1.dist-info/METADATA
Normal file
@ -0,0 +1,199 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: Automat
|
||||
Version: 24.8.1
|
||||
Summary: Self-service finite-state machines for the programmer on the go.
|
||||
Author-email: Glyph <code@glyph.im>
|
||||
License: Copyright (c) 2014
|
||||
Rackspace
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Project-URL: Documentation, https://automat.readthedocs.io/
|
||||
Project-URL: Source, https://github.com/glyph/automat/
|
||||
Keywords: fsm,state machine,automata
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: 3.11
|
||||
Classifier: Programming Language :: Python :: 3.12
|
||||
Requires-Python: >=3.8
|
||||
Description-Content-Type: text/markdown
|
||||
License-File: LICENSE
|
||||
Requires-Dist: typing-extensions; python_version < "3.10"
|
||||
Provides-Extra: visualize
|
||||
Requires-Dist: graphviz>0.5.1; extra == "visualize"
|
||||
Requires-Dist: Twisted>=16.1.1; extra == "visualize"
|
||||
|
||||
# Automat #
|
||||
|
||||
[](http://automat.readthedocs.io/en/latest/)
|
||||
[](https://github.com/glyph/automat/actions/workflows/ci.yml?query=branch%3Atrunk)
|
||||
[](http://codecov.io/github/glyph/automat?branch=trunk)
|
||||
|
||||
## Self-service finite-state machines for the programmer on the go. ##
|
||||
|
||||
Automat is a library for concise, idiomatic Python expression of finite-state
|
||||
automata (particularly deterministic finite-state transducers).
|
||||
|
||||
Read more here, or on [Read the Docs](https://automat.readthedocs.io/), or watch the following videos for an overview and presentation
|
||||
|
||||
### Why use state machines? ###
|
||||
|
||||
Sometimes you have to create an object whose behavior varies with its state,
|
||||
but still wishes to present a consistent interface to its callers.
|
||||
|
||||
For example, let's say you're writing the software for a coffee machine. It
|
||||
has a lid that can be opened or closed, a chamber for water, a chamber for
|
||||
coffee beans, and a button for "brew".
|
||||
|
||||
There are a number of possible states for the coffee machine. It might or
|
||||
might not have water. It might or might not have beans. The lid might be open
|
||||
or closed. The "brew" button should only actually attempt to brew coffee in
|
||||
one of these configurations, and the "open lid" button should only work if the
|
||||
coffee is not, in fact, brewing.
|
||||
|
||||
With diligence and attention to detail, you can implement this correctly using
|
||||
a collection of attributes on an object; `hasWater`, `hasBeans`, `isLidOpen`
|
||||
and so on. However, you have to keep all these attributes consistent. As the
|
||||
coffee maker becomes more complex - perhaps you add an additional chamber for
|
||||
flavorings so you can make hazelnut coffee, for example - you have to keep
|
||||
adding more and more checks and more and more reasoning about which
|
||||
combinations of states are allowed.
|
||||
|
||||
Rather than adding tedious `if` checks to every single method to make sure that
|
||||
each of these flags are exactly what you expect, you can use a state machine to
|
||||
ensure that if your code runs at all, it will be run with all the required
|
||||
values initialized, because they have to be called in the order you declare
|
||||
them.
|
||||
|
||||
You can read about state machines and their advantages for Python programmers
|
||||
in more detail [in this excellent article by Jean-Paul
|
||||
Calderone](https://web.archive.org/web/20160507053658/https://clusterhq.com/2013/12/05/what-is-a-state-machine/).
|
||||
|
||||
### What makes Automat different? ###
|
||||
|
||||
There are
|
||||
[dozens of libraries on PyPI implementing state machines](https://pypi.org/search/?q=finite+state+machine).
|
||||
So it behooves me to say why yet another one would be a good idea.
|
||||
|
||||
Automat is designed around this principle: while organizing your code around
|
||||
state machines is a good idea, your callers don't, and shouldn't have to, care
|
||||
that you've done so. In Python, the "input" to a stateful system is a method
|
||||
call; the "output" may be a method call, if you need to invoke a side effect,
|
||||
or a return value, if you are just performing a computation in memory. Most
|
||||
other state-machine libraries require you to explicitly create an input object,
|
||||
provide that object to a generic "input" method, and then receive results,
|
||||
sometimes in terms of that library's interfaces and sometimes in terms of
|
||||
classes you define yourself.
|
||||
|
||||
For example, a snippet of the coffee-machine example above might be implemented
|
||||
as follows in naive Python:
|
||||
|
||||
```python
|
||||
class CoffeeMachine(object):
|
||||
def brewButton(self) -> None:
|
||||
if self.hasWater and self.hasBeans and not self.isLidOpen:
|
||||
self.heatTheHeatingElement()
|
||||
# ...
|
||||
```
|
||||
|
||||
With Automat, you'd begin with a `typing.Protocol` that describes all of your
|
||||
inputs:
|
||||
|
||||
```python
|
||||
from typing import Protocol
|
||||
|
||||
class CoffeeBrewer(Protocol):
|
||||
def brewButton(self) -> None:
|
||||
"The user pressed the 'brew' button."
|
||||
def putInBeans(self) -> None:
|
||||
"The user put in some beans."
|
||||
```
|
||||
|
||||
We'll then need a concrete class to contain the shared core of state shared
|
||||
among the different states:
|
||||
|
||||
```python
|
||||
from dataclasses import dataclass
|
||||
|
||||
@dataclass
|
||||
class BrewerCore:
|
||||
heatingElement: HeatingElement
|
||||
```
|
||||
|
||||
Next, we need to describe our state machine, including all of our states. For
|
||||
simplicity's sake let's say that the only two states are `noBeans` and
|
||||
`haveBeans`:
|
||||
|
||||
```python
|
||||
from automat import TypeMachineBuilder
|
||||
|
||||
builder = TypeMachineBuilder(CoffeeBrewer, BrewerCore)
|
||||
noBeans = builder.state("noBeans")
|
||||
haveBeans = builder.state("haveBeans")
|
||||
```
|
||||
|
||||
Next we can describe a simple transition; when we put in beans, we move to the
|
||||
`haveBeans` state, with no other behavior.
|
||||
|
||||
```python
|
||||
# When we don't have beans, upon putting in beans, we will then have beans
|
||||
noBeans.upon(CoffeeBrewer.putInBeans).to(haveBeans).returns(None)
|
||||
```
|
||||
|
||||
And then another transition that we describe with a decorator, one that *does*
|
||||
have some behavior, that needs to heat up the heating element to brew the
|
||||
coffee:
|
||||
|
||||
```python
|
||||
@haveBeans.upon(CoffeeBrewer.brewButton).to(noBeans)
|
||||
def heatUp(inputs: CoffeeBrewer, core: BrewerCore) -> None:
|
||||
"""
|
||||
When we have beans, upon pressing the brew button, we will then not have
|
||||
beans any more (as they have been entered into the brewing chamber) and
|
||||
our output will be heating the heating element.
|
||||
"""
|
||||
print("Brewing the coffee...")
|
||||
core.heatingElement.turnOn()
|
||||
```
|
||||
|
||||
Then we finalize the state machine by building it, which gives us a callable
|
||||
that takes a `BrewerCore` and returns a synthetic `CoffeeBrewer`
|
||||
|
||||
```python
|
||||
newCoffeeMachine = builder.build()
|
||||
```
|
||||
|
||||
```python
|
||||
>>> coffee = newCoffeeMachine(BrewerCore(HeatingElement()))
|
||||
>>> machine.putInBeans()
|
||||
>>> machine.brewButton()
|
||||
Brewing the coffee...
|
||||
```
|
||||
|
||||
All of the *inputs* are provided by calling them like methods, all of the
|
||||
*output behaviors* are automatically invoked when they are produced according
|
||||
to the outputs specified to `upon` and all of the states are simply opaque
|
||||
tokens.
|
39
venv/Lib/site-packages/Automat-24.8.1.dist-info/RECORD
Normal file
39
venv/Lib/site-packages/Automat-24.8.1.dist-info/RECORD
Normal file
@ -0,0 +1,39 @@
|
||||
../../Scripts/automat-visualize.exe,sha256=ZRwvWQ0vDCMIIwtd7o8nxXVwifeK4uG7teTIfYeDgKk,108419
|
||||
Automat-24.8.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
Automat-24.8.1.dist-info/LICENSE,sha256=siATAWeNCpN9k4VDgnyhNgcS6zTiPejuPzv_-9TA43Y,1053
|
||||
Automat-24.8.1.dist-info/METADATA,sha256=XJIxL4Olb15WCoAdVEcORum39__wiCXQR6LNubERZ6M,8396
|
||||
Automat-24.8.1.dist-info/RECORD,,
|
||||
Automat-24.8.1.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
|
||||
Automat-24.8.1.dist-info/entry_points.txt,sha256=D5Dc6byHpLWAktM443OHbx0ZGl1ZBZtf6rPNlGi7NbQ,62
|
||||
Automat-24.8.1.dist-info/top_level.txt,sha256=vg4zAOyhP_3YCmpKZLNgFw1uMF3lC_b6TKsdz7jBSpI,8
|
||||
automat/__init__.py,sha256=8yHAuqaxK0mdiOEXHbwe6WaNzaY01k2HMWD_RltPB-U,356
|
||||
automat/__pycache__/__init__.cpython-310.pyc,,
|
||||
automat/__pycache__/_core.cpython-310.pyc,,
|
||||
automat/__pycache__/_discover.cpython-310.pyc,,
|
||||
automat/__pycache__/_introspection.cpython-310.pyc,,
|
||||
automat/__pycache__/_methodical.cpython-310.pyc,,
|
||||
automat/__pycache__/_runtimeproto.cpython-310.pyc,,
|
||||
automat/__pycache__/_typed.cpython-310.pyc,,
|
||||
automat/__pycache__/_visualize.cpython-310.pyc,,
|
||||
automat/_core.py,sha256=oe4QNlfvmgsnKe_8fyNiOsHsfz5xPArGuXWle9zePp8,6663
|
||||
automat/_discover.py,sha256=KRbmm7kxpd-WReDQU4qe6hVKGUKmGBHUjYIkRneO4mc,5197
|
||||
automat/_introspection.py,sha256=uF5ymY-GZckyRxvRs7UToPBV_oVV6xHmvlBVey9nv80,1441
|
||||
automat/_methodical.py,sha256=YgZXraDe6dvK6w_Y9xfPa0kXCka4ZeGLfcb4IfK4bnI,17243
|
||||
automat/_runtimeproto.py,sha256=mJ_4VuEGpLc1u7Ptm5cfaLUq7LGD7KfrvmsAa4LsyuU,1654
|
||||
automat/_test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
automat/_test/__pycache__/__init__.cpython-310.pyc,,
|
||||
automat/_test/__pycache__/test_core.cpython-310.pyc,,
|
||||
automat/_test/__pycache__/test_discover.cpython-310.pyc,,
|
||||
automat/_test/__pycache__/test_methodical.cpython-310.pyc,,
|
||||
automat/_test/__pycache__/test_trace.cpython-310.pyc,,
|
||||
automat/_test/__pycache__/test_type_based.cpython-310.pyc,,
|
||||
automat/_test/__pycache__/test_visualize.cpython-310.pyc,,
|
||||
automat/_test/test_core.py,sha256=PJHNvQ85i8vjH-oF6nPNKB84_noTyl2dQSv_iRl70J8,3481
|
||||
automat/_test/test_discover.py,sha256=ROnW7eSLE4T76FVncY2UK05DIYcHZ3TSGGg7kQnbvtw,22067
|
||||
automat/_test/test_methodical.py,sha256=SKMMbl-6bjH-QZ1hDFRItCOyKF4SstuA4QvExnVhn7w,20267
|
||||
automat/_test/test_trace.py,sha256=tty7P_ctJtk38ZXnpmEy-J9Rn-Hh2AKb_ia6EmtXSQI,3299
|
||||
automat/_test/test_type_based.py,sha256=8oZxz3T7zIvyMKg4THg7M85zaHtE4QU9nAegU_OUvko,17872
|
||||
automat/_test/test_visualize.py,sha256=HXBPgMAD0OTz_l1Yq0lI3d1vJ_l3sHTH67Jauaf-2sk,14631
|
||||
automat/_typed.py,sha256=lMzMgUfX713Xw_W4pr8iyPqcdpRSbu4rEpRlrXAOW2k,24204
|
||||
automat/_visualize.py,sha256=DQYig2mBKX-LquPEEy89Y_qyj21tSutAUaFsF1F64ws,6512
|
||||
automat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
venv/Lib/site-packages/Automat-24.8.1.dist-info/WHEEL
Normal file
5
venv/Lib/site-packages/Automat-24.8.1.dist-info/WHEEL
Normal file
@ -0,0 +1,5 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: setuptools (72.2.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
@ -0,0 +1,2 @@
|
||||
[console_scripts]
|
||||
automat-visualize = automat._visualize:tool
|
@ -0,0 +1 @@
|
||||
automat
|
1106
venv/Lib/site-packages/Django-5.1.5.dist-info/AUTHORS
Normal file
1106
venv/Lib/site-packages/Django-5.1.5.dist-info/AUTHORS
Normal file
File diff suppressed because it is too large
Load Diff
1
venv/Lib/site-packages/Django-5.1.5.dist-info/INSTALLER
Normal file
1
venv/Lib/site-packages/Django-5.1.5.dist-info/INSTALLER
Normal file
@ -0,0 +1 @@
|
||||
pip
|
27
venv/Lib/site-packages/Django-5.1.5.dist-info/LICENSE
Normal file
27
venv/Lib/site-packages/Django-5.1.5.dist-info/LICENSE
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) Django Software Foundation and individual contributors.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of Django nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
288
venv/Lib/site-packages/Django-5.1.5.dist-info/LICENSE.python
Normal file
288
venv/Lib/site-packages/Django-5.1.5.dist-info/LICENSE.python
Normal file
@ -0,0 +1,288 @@
|
||||
Django is licensed under the three-clause BSD license; see the file
|
||||
LICENSE for details.
|
||||
|
||||
Django includes code from the Python standard library, which is licensed under
|
||||
the Python license, a permissive open source license. The copyright and license
|
||||
is included below for compliance with Python's terms.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2001-present Python Software Foundation; All Rights Reserved
|
||||
|
||||
A. HISTORY OF THE SOFTWARE
|
||||
==========================
|
||||
|
||||
Python was created in the early 1990s by Guido van Rossum at Stichting
|
||||
Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands
|
||||
as a successor of a language called ABC. Guido remains Python's
|
||||
principal author, although it includes many contributions from others.
|
||||
|
||||
In 1995, Guido continued his work on Python at the Corporation for
|
||||
National Research Initiatives (CNRI, see https://www.cnri.reston.va.us)
|
||||
in Reston, Virginia where he released several versions of the
|
||||
software.
|
||||
|
||||
In May 2000, Guido and the Python core development team moved to
|
||||
BeOpen.com to form the BeOpen PythonLabs team. In October of the same
|
||||
year, the PythonLabs team moved to Digital Creations, which became
|
||||
Zope Corporation. In 2001, the Python Software Foundation (PSF, see
|
||||
https://www.python.org/psf/) was formed, a non-profit organization
|
||||
created specifically to own Python-related Intellectual Property.
|
||||
Zope Corporation was a sponsoring member of the PSF.
|
||||
|
||||
All Python releases are Open Source (see https://opensource.org for
|
||||
the Open Source Definition). Historically, most, but not all, Python
|
||||
releases have also been GPL-compatible; the table below summarizes
|
||||
the various releases.
|
||||
|
||||
Release Derived Year Owner GPL-
|
||||
from compatible? (1)
|
||||
|
||||
0.9.0 thru 1.2 1991-1995 CWI yes
|
||||
1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
|
||||
1.6 1.5.2 2000 CNRI no
|
||||
2.0 1.6 2000 BeOpen.com no
|
||||
1.6.1 1.6 2001 CNRI yes (2)
|
||||
2.1 2.0+1.6.1 2001 PSF no
|
||||
2.0.1 2.0+1.6.1 2001 PSF yes
|
||||
2.1.1 2.1+2.0.1 2001 PSF yes
|
||||
2.1.2 2.1.1 2002 PSF yes
|
||||
2.1.3 2.1.2 2002 PSF yes
|
||||
2.2 and above 2.1.1 2001-now PSF yes
|
||||
|
||||
Footnotes:
|
||||
|
||||
(1) GPL-compatible doesn't mean that we're distributing Python under
|
||||
the GPL. All Python licenses, unlike the GPL, let you distribute
|
||||
a modified version without making your changes open source. The
|
||||
GPL-compatible licenses make it possible to combine Python with
|
||||
other software that is released under the GPL; the others don't.
|
||||
|
||||
(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
|
||||
because its license has a choice of law clause. According to
|
||||
CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
|
||||
is "not incompatible" with the GPL.
|
||||
|
||||
Thanks to the many outside volunteers who have worked under Guido's
|
||||
direction to make these releases possible.
|
||||
|
||||
|
||||
B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
|
||||
===============================================================
|
||||
|
||||
Python software and documentation are licensed under the
|
||||
Python Software Foundation License Version 2.
|
||||
|
||||
Starting with Python 3.8.6, examples, recipes, and other code in
|
||||
the documentation are dual licensed under the PSF License Version 2
|
||||
and the Zero-Clause BSD license.
|
||||
|
||||
Some software incorporated into Python is under different licenses.
|
||||
The licenses are listed with code falling under that license.
|
||||
|
||||
|
||||
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
||||
--------------------------------------------
|
||||
|
||||
1. This LICENSE AGREEMENT is between the Python Software Foundation
|
||||
("PSF"), and the Individual or Organization ("Licensee") accessing and
|
||||
otherwise using this software ("Python") in source or binary form and
|
||||
its associated documentation.
|
||||
|
||||
2. Subject to the terms and conditions of this License Agreement, PSF hereby
|
||||
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
|
||||
analyze, test, perform and/or display publicly, prepare derivative works,
|
||||
distribute, and otherwise use Python alone or in any derivative version,
|
||||
provided, however, that PSF's License Agreement and PSF's notice of copyright,
|
||||
i.e., "Copyright (c) 2001-2024 Python Software Foundation; All Rights Reserved"
|
||||
are retained in Python alone or in any derivative version prepared by Licensee.
|
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on
|
||||
or incorporates Python or any part thereof, and wants to make
|
||||
the derivative work available to others as provided herein, then
|
||||
Licensee hereby agrees to include in any such work a brief summary of
|
||||
the changes made to Python.
|
||||
|
||||
4. PSF is making Python available to Licensee on an "AS IS"
|
||||
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
|
||||
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
6. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
7. Nothing in this License Agreement shall be deemed to create any
|
||||
relationship of agency, partnership, or joint venture between PSF and
|
||||
Licensee. This License Agreement does not grant permission to use PSF
|
||||
trademarks or trade name in a trademark sense to endorse or promote
|
||||
products or services of Licensee, or any third party.
|
||||
|
||||
8. By copying, installing or otherwise using Python, Licensee
|
||||
agrees to be bound by the terms and conditions of this License
|
||||
Agreement.
|
||||
|
||||
|
||||
BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
|
||||
-------------------------------------------
|
||||
|
||||
BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
|
||||
|
||||
1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
|
||||
office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
|
||||
Individual or Organization ("Licensee") accessing and otherwise using
|
||||
this software in source or binary form and its associated
|
||||
documentation ("the Software").
|
||||
|
||||
2. Subject to the terms and conditions of this BeOpen Python License
|
||||
Agreement, BeOpen hereby grants Licensee a non-exclusive,
|
||||
royalty-free, world-wide license to reproduce, analyze, test, perform
|
||||
and/or display publicly, prepare derivative works, distribute, and
|
||||
otherwise use the Software alone or in any derivative version,
|
||||
provided, however, that the BeOpen Python License is retained in the
|
||||
Software, alone or in any derivative version prepared by Licensee.
|
||||
|
||||
3. BeOpen is making the Software available to Licensee on an "AS IS"
|
||||
basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
|
||||
SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
|
||||
AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
|
||||
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
5. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
6. This License Agreement shall be governed by and interpreted in all
|
||||
respects by the law of the State of California, excluding conflict of
|
||||
law provisions. Nothing in this License Agreement shall be deemed to
|
||||
create any relationship of agency, partnership, or joint venture
|
||||
between BeOpen and Licensee. This License Agreement does not grant
|
||||
permission to use BeOpen trademarks or trade names in a trademark
|
||||
sense to endorse or promote products or services of Licensee, or any
|
||||
third party. As an exception, the "BeOpen Python" logos available at
|
||||
http://www.pythonlabs.com/logos.html may be used according to the
|
||||
permissions granted on that web page.
|
||||
|
||||
7. By copying, installing or otherwise using the software, Licensee
|
||||
agrees to be bound by the terms and conditions of this License
|
||||
Agreement.
|
||||
|
||||
|
||||
CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
|
||||
---------------------------------------
|
||||
|
||||
1. This LICENSE AGREEMENT is between the Corporation for National
|
||||
Research Initiatives, having an office at 1895 Preston White Drive,
|
||||
Reston, VA 20191 ("CNRI"), and the Individual or Organization
|
||||
("Licensee") accessing and otherwise using Python 1.6.1 software in
|
||||
source or binary form and its associated documentation.
|
||||
|
||||
2. Subject to the terms and conditions of this License Agreement, CNRI
|
||||
hereby grants Licensee a nonexclusive, royalty-free, world-wide
|
||||
license to reproduce, analyze, test, perform and/or display publicly,
|
||||
prepare derivative works, distribute, and otherwise use Python 1.6.1
|
||||
alone or in any derivative version, provided, however, that CNRI's
|
||||
License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
|
||||
1995-2001 Corporation for National Research Initiatives; All Rights
|
||||
Reserved" are retained in Python 1.6.1 alone or in any derivative
|
||||
version prepared by Licensee. Alternately, in lieu of CNRI's License
|
||||
Agreement, Licensee may substitute the following text (omitting the
|
||||
quotes): "Python 1.6.1 is made available subject to the terms and
|
||||
conditions in CNRI's License Agreement. This Agreement together with
|
||||
Python 1.6.1 may be located on the internet using the following
|
||||
unique, persistent identifier (known as a handle): 1895.22/1013. This
|
||||
Agreement may also be obtained from a proxy server on the internet
|
||||
using the following URL: http://hdl.handle.net/1895.22/1013".
|
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on
|
||||
or incorporates Python 1.6.1 or any part thereof, and wants to make
|
||||
the derivative work available to others as provided herein, then
|
||||
Licensee hereby agrees to include in any such work a brief summary of
|
||||
the changes made to Python 1.6.1.
|
||||
|
||||
4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
|
||||
basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||
1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
|
||||
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
6. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
7. This License Agreement shall be governed by the federal
|
||||
intellectual property law of the United States, including without
|
||||
limitation the federal copyright law, and, to the extent such
|
||||
U.S. federal law does not apply, by the law of the Commonwealth of
|
||||
Virginia, excluding Virginia's conflict of law provisions.
|
||||
Notwithstanding the foregoing, with regard to derivative works based
|
||||
on Python 1.6.1 that incorporate non-separable material that was
|
||||
previously distributed under the GNU General Public License (GPL), the
|
||||
law of the Commonwealth of Virginia shall govern this License
|
||||
Agreement only as to issues arising under or with respect to
|
||||
Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
|
||||
License Agreement shall be deemed to create any relationship of
|
||||
agency, partnership, or joint venture between CNRI and Licensee. This
|
||||
License Agreement does not grant permission to use CNRI trademarks or
|
||||
trade name in a trademark sense to endorse or promote products or
|
||||
services of Licensee, or any third party.
|
||||
|
||||
8. By clicking on the "ACCEPT" button where indicated, or by copying,
|
||||
installing or otherwise using Python 1.6.1, Licensee agrees to be
|
||||
bound by the terms and conditions of this License Agreement.
|
||||
|
||||
ACCEPT
|
||||
|
||||
|
||||
CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
|
||||
--------------------------------------------------
|
||||
|
||||
Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
|
||||
The Netherlands. All rights reserved.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose and without fee is hereby granted,
|
||||
provided that the above copyright notice appear in all copies and that
|
||||
both that copyright notice and this permission notice appear in
|
||||
supporting documentation, and that the name of Stichting Mathematisch
|
||||
Centrum or CWI not be used in advertising or publicity pertaining to
|
||||
distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
||||
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
|
||||
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
101
venv/Lib/site-packages/Django-5.1.5.dist-info/METADATA
Normal file
101
venv/Lib/site-packages/Django-5.1.5.dist-info/METADATA
Normal file
@ -0,0 +1,101 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: Django
|
||||
Version: 5.1.5
|
||||
Summary: A high-level Python web framework that encourages rapid development and clean, pragmatic design.
|
||||
Author-email: Django Software Foundation <foundation@djangoproject.com>
|
||||
License: BSD-3-Clause
|
||||
Project-URL: Homepage, https://www.djangoproject.com/
|
||||
Project-URL: Documentation, https://docs.djangoproject.com/
|
||||
Project-URL: Release notes, https://docs.djangoproject.com/en/stable/releases/
|
||||
Project-URL: Funding, https://www.djangoproject.com/fundraising/
|
||||
Project-URL: Source, https://github.com/django/django
|
||||
Project-URL: Tracker, https://code.djangoproject.com/
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Web Environment
|
||||
Classifier: Framework :: Django
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3 :: Only
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: 3.11
|
||||
Classifier: Programming Language :: Python :: 3.12
|
||||
Classifier: Programming Language :: Python :: 3.13
|
||||
Classifier: Topic :: Internet :: WWW/HTTP
|
||||
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
||||
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
|
||||
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Requires-Python: >=3.10
|
||||
Description-Content-Type: text/x-rst
|
||||
License-File: LICENSE
|
||||
License-File: LICENSE.python
|
||||
License-File: AUTHORS
|
||||
Requires-Dist: asgiref<4,>=3.8.1
|
||||
Requires-Dist: sqlparse>=0.3.1
|
||||
Requires-Dist: tzdata; sys_platform == "win32"
|
||||
Provides-Extra: argon2
|
||||
Requires-Dist: argon2-cffi>=19.1.0; extra == "argon2"
|
||||
Provides-Extra: bcrypt
|
||||
Requires-Dist: bcrypt; extra == "bcrypt"
|
||||
|
||||
======
|
||||
Django
|
||||
======
|
||||
|
||||
Django is a high-level Python web framework that encourages rapid development
|
||||
and clean, pragmatic design. Thanks for checking it out.
|
||||
|
||||
All documentation is in the "``docs``" directory and online at
|
||||
https://docs.djangoproject.com/en/stable/. If you're just getting started,
|
||||
here's how we recommend you read the docs:
|
||||
|
||||
* First, read ``docs/intro/install.txt`` for instructions on installing Django.
|
||||
|
||||
* Next, work through the tutorials in order (``docs/intro/tutorial01.txt``,
|
||||
``docs/intro/tutorial02.txt``, etc.).
|
||||
|
||||
* If you want to set up an actual deployment server, read
|
||||
``docs/howto/deployment/index.txt`` for instructions.
|
||||
|
||||
* You'll probably want to read through the topical guides (in ``docs/topics``)
|
||||
next; from there you can jump to the HOWTOs (in ``docs/howto``) for specific
|
||||
problems, and check out the reference (``docs/ref``) for gory details.
|
||||
|
||||
* See ``docs/README`` for instructions on building an HTML version of the docs.
|
||||
|
||||
Docs are updated rigorously. If you find any problems in the docs, or think
|
||||
they should be clarified in any way, please take 30 seconds to fill out a
|
||||
ticket here: https://code.djangoproject.com/newticket
|
||||
|
||||
To get more help:
|
||||
|
||||
* Join the ``#django`` channel on ``irc.libera.chat``. Lots of helpful people
|
||||
hang out there. `Webchat is available <https://web.libera.chat/#django>`_.
|
||||
|
||||
* Join the django-users mailing list, or read the archives, at
|
||||
https://groups.google.com/group/django-users.
|
||||
|
||||
* Join the `Django Discord community <https://discord.gg/xcRH6mN4fa>`_.
|
||||
|
||||
* Join the community on the `Django Forum <https://forum.djangoproject.com/>`_.
|
||||
|
||||
To contribute to Django:
|
||||
|
||||
* Check out https://docs.djangoproject.com/en/dev/internals/contributing/ for
|
||||
information about getting involved.
|
||||
|
||||
To run Django's test suite:
|
||||
|
||||
* Follow the instructions in the "Unit tests" section of
|
||||
``docs/internals/contributing/writing-code/unit-tests.txt``, published online at
|
||||
https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/unit-tests/#running-the-unit-tests
|
||||
|
||||
Supporting the Development of Django
|
||||
====================================
|
||||
|
||||
Django's development depends on your contributions.
|
||||
|
||||
If you depend on Django, remember to support the Django Software Foundation: https://www.djangoproject.com/fundraising/
|
4540
venv/Lib/site-packages/Django-5.1.5.dist-info/RECORD
Normal file
4540
venv/Lib/site-packages/Django-5.1.5.dist-info/RECORD
Normal file
File diff suppressed because it is too large
Load Diff
5
venv/Lib/site-packages/Django-5.1.5.dist-info/WHEEL
Normal file
5
venv/Lib/site-packages/Django-5.1.5.dist-info/WHEEL
Normal file
@ -0,0 +1,5 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.45.1)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
@ -0,0 +1,2 @@
|
||||
[console_scripts]
|
||||
django-admin = django.core.management:execute_from_command_line
|
@ -0,0 +1 @@
|
||||
django
|
168
venv/Lib/site-packages/MySQLdb/__init__.py
Normal file
168
venv/Lib/site-packages/MySQLdb/__init__.py
Normal file
@ -0,0 +1,168 @@
|
||||
"""
|
||||
MySQLdb - A DB API v2.0 compatible interface to MySQL.
|
||||
|
||||
This package is a wrapper around _mysql, which mostly implements the
|
||||
MySQL C API.
|
||||
|
||||
connect() -- connects to server
|
||||
|
||||
See the C API specification and the MySQL documentation for more info
|
||||
on other items.
|
||||
|
||||
For information on how MySQLdb handles type conversion, see the
|
||||
MySQLdb.converters module.
|
||||
"""
|
||||
|
||||
from .release import version_info
|
||||
from . import _mysql
|
||||
|
||||
if version_info != _mysql.version_info:
|
||||
raise ImportError(
|
||||
f"this is MySQLdb version {version_info}, "
|
||||
f"but _mysql is version {_mysql.version_info!r}\n"
|
||||
f"_mysql: {_mysql.__file__!r}"
|
||||
)
|
||||
|
||||
|
||||
from ._mysql import (
|
||||
NotSupportedError,
|
||||
OperationalError,
|
||||
get_client_info,
|
||||
ProgrammingError,
|
||||
Error,
|
||||
InterfaceError,
|
||||
debug,
|
||||
IntegrityError,
|
||||
string_literal,
|
||||
MySQLError,
|
||||
DataError,
|
||||
DatabaseError,
|
||||
InternalError,
|
||||
Warning,
|
||||
)
|
||||
from MySQLdb.constants import FIELD_TYPE
|
||||
from MySQLdb.times import (
|
||||
Date,
|
||||
Time,
|
||||
Timestamp,
|
||||
DateFromTicks,
|
||||
TimeFromTicks,
|
||||
TimestampFromTicks,
|
||||
)
|
||||
|
||||
threadsafety = 1
|
||||
apilevel = "2.0"
|
||||
paramstyle = "format"
|
||||
|
||||
|
||||
class DBAPISet(frozenset):
|
||||
"""A special type of set for which A == x is true if A is a
|
||||
DBAPISet and x is a member of that set."""
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, DBAPISet):
|
||||
return not self.difference(other)
|
||||
return other in self
|
||||
|
||||
|
||||
STRING = DBAPISet([FIELD_TYPE.ENUM, FIELD_TYPE.STRING, FIELD_TYPE.VAR_STRING])
|
||||
BINARY = DBAPISet(
|
||||
[
|
||||
FIELD_TYPE.BLOB,
|
||||
FIELD_TYPE.LONG_BLOB,
|
||||
FIELD_TYPE.MEDIUM_BLOB,
|
||||
FIELD_TYPE.TINY_BLOB,
|
||||
]
|
||||
)
|
||||
NUMBER = DBAPISet(
|
||||
[
|
||||
FIELD_TYPE.DECIMAL,
|
||||
FIELD_TYPE.DOUBLE,
|
||||
FIELD_TYPE.FLOAT,
|
||||
FIELD_TYPE.INT24,
|
||||
FIELD_TYPE.LONG,
|
||||
FIELD_TYPE.LONGLONG,
|
||||
FIELD_TYPE.TINY,
|
||||
FIELD_TYPE.YEAR,
|
||||
FIELD_TYPE.NEWDECIMAL,
|
||||
]
|
||||
)
|
||||
DATE = DBAPISet([FIELD_TYPE.DATE])
|
||||
TIME = DBAPISet([FIELD_TYPE.TIME])
|
||||
TIMESTAMP = DBAPISet([FIELD_TYPE.TIMESTAMP, FIELD_TYPE.DATETIME])
|
||||
DATETIME = TIMESTAMP
|
||||
ROWID = DBAPISet()
|
||||
|
||||
|
||||
def test_DBAPISet_set_equality():
|
||||
assert STRING == STRING
|
||||
|
||||
|
||||
def test_DBAPISet_set_inequality():
|
||||
assert STRING != NUMBER
|
||||
|
||||
|
||||
def test_DBAPISet_set_equality_membership():
|
||||
assert FIELD_TYPE.VAR_STRING == STRING
|
||||
|
||||
|
||||
def test_DBAPISet_set_inequality_membership():
|
||||
assert FIELD_TYPE.DATE != STRING
|
||||
|
||||
|
||||
def Binary(x):
|
||||
return bytes(x)
|
||||
|
||||
|
||||
def Connect(*args, **kwargs):
|
||||
"""Factory function for connections.Connection."""
|
||||
from MySQLdb.connections import Connection
|
||||
|
||||
return Connection(*args, **kwargs)
|
||||
|
||||
|
||||
connect = Connection = Connect
|
||||
|
||||
__all__ = [
|
||||
"BINARY",
|
||||
"Binary",
|
||||
"Connect",
|
||||
"Connection",
|
||||
"DATE",
|
||||
"Date",
|
||||
"Time",
|
||||
"Timestamp",
|
||||
"DateFromTicks",
|
||||
"TimeFromTicks",
|
||||
"TimestampFromTicks",
|
||||
"DataError",
|
||||
"DatabaseError",
|
||||
"Error",
|
||||
"FIELD_TYPE",
|
||||
"IntegrityError",
|
||||
"InterfaceError",
|
||||
"InternalError",
|
||||
"MySQLError",
|
||||
"NUMBER",
|
||||
"NotSupportedError",
|
||||
"DBAPISet",
|
||||
"OperationalError",
|
||||
"ProgrammingError",
|
||||
"ROWID",
|
||||
"STRING",
|
||||
"TIME",
|
||||
"TIMESTAMP",
|
||||
"Warning",
|
||||
"apilevel",
|
||||
"connect",
|
||||
"connections",
|
||||
"constants",
|
||||
"converters",
|
||||
"cursors",
|
||||
"debug",
|
||||
"get_client_info",
|
||||
"paramstyle",
|
||||
"string_literal",
|
||||
"threadsafety",
|
||||
"version_info",
|
||||
]
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
venv/Lib/site-packages/MySQLdb/__pycache__/times.cpython-310.pyc
Normal file
BIN
venv/Lib/site-packages/MySQLdb/__pycache__/times.cpython-310.pyc
Normal file
Binary file not shown.
91
venv/Lib/site-packages/MySQLdb/_exceptions.py
Normal file
91
venv/Lib/site-packages/MySQLdb/_exceptions.py
Normal file
@ -0,0 +1,91 @@
|
||||
"""Exception classes for _mysql and MySQLdb.
|
||||
|
||||
These classes are dictated by the DB API v2.0:
|
||||
|
||||
https://www.python.org/dev/peps/pep-0249/
|
||||
"""
|
||||
|
||||
|
||||
class MySQLError(Exception):
|
||||
"""Exception related to operation with MySQL."""
|
||||
|
||||
__module__ = "MySQLdb"
|
||||
|
||||
|
||||
class Warning(Warning, MySQLError):
|
||||
"""Exception raised for important warnings like data truncations
|
||||
while inserting, etc."""
|
||||
|
||||
__module__ = "MySQLdb"
|
||||
|
||||
|
||||
class Error(MySQLError):
|
||||
"""Exception that is the base class of all other error exceptions
|
||||
(not Warning)."""
|
||||
|
||||
__module__ = "MySQLdb"
|
||||
|
||||
|
||||
class InterfaceError(Error):
|
||||
"""Exception raised for errors that are related to the database
|
||||
interface rather than the database itself."""
|
||||
|
||||
__module__ = "MySQLdb"
|
||||
|
||||
|
||||
class DatabaseError(Error):
|
||||
"""Exception raised for errors that are related to the
|
||||
database."""
|
||||
|
||||
__module__ = "MySQLdb"
|
||||
|
||||
|
||||
class DataError(DatabaseError):
|
||||
"""Exception raised for errors that are due to problems with the
|
||||
processed data like division by zero, numeric value out of range,
|
||||
etc."""
|
||||
|
||||
__module__ = "MySQLdb"
|
||||
|
||||
|
||||
class OperationalError(DatabaseError):
|
||||
"""Exception raised for errors that are related to the database's
|
||||
operation and not necessarily under the control of the programmer,
|
||||
e.g. an unexpected disconnect occurs, the data source name is not
|
||||
found, a transaction could not be processed, a memory allocation
|
||||
error occurred during processing, etc."""
|
||||
|
||||
__module__ = "MySQLdb"
|
||||
|
||||
|
||||
class IntegrityError(DatabaseError):
|
||||
"""Exception raised when the relational integrity of the database
|
||||
is affected, e.g. a foreign key check fails, duplicate key,
|
||||
etc."""
|
||||
|
||||
__module__ = "MySQLdb"
|
||||
|
||||
|
||||
class InternalError(DatabaseError):
|
||||
"""Exception raised when the database encounters an internal
|
||||
error, e.g. the cursor is not valid anymore, the transaction is
|
||||
out of sync, etc."""
|
||||
|
||||
__module__ = "MySQLdb"
|
||||
|
||||
|
||||
class ProgrammingError(DatabaseError):
|
||||
"""Exception raised for programming errors, e.g. table not found
|
||||
or already exists, syntax error in the SQL statement, wrong number
|
||||
of parameters specified, etc."""
|
||||
|
||||
__module__ = "MySQLdb"
|
||||
|
||||
|
||||
class NotSupportedError(DatabaseError):
|
||||
"""Exception raised in case a method or database API was used
|
||||
which is not supported by the database, e.g. requesting a
|
||||
.rollback() on a connection that does not support transaction or
|
||||
has transactions turned off."""
|
||||
|
||||
__module__ = "MySQLdb"
|
2959
venv/Lib/site-packages/MySQLdb/_mysql.c
Normal file
2959
venv/Lib/site-packages/MySQLdb/_mysql.c
Normal file
File diff suppressed because it is too large
Load Diff
BIN
venv/Lib/site-packages/MySQLdb/_mysql.cp310-win_amd64.pyd
Normal file
BIN
venv/Lib/site-packages/MySQLdb/_mysql.cp310-win_amd64.pyd
Normal file
Binary file not shown.
362
venv/Lib/site-packages/MySQLdb/connections.py
Normal file
362
venv/Lib/site-packages/MySQLdb/connections.py
Normal file
@ -0,0 +1,362 @@
|
||||
"""
|
||||
This module implements connections for MySQLdb. Presently there is
|
||||
only one class: Connection. Others are unlikely. However, you might
|
||||
want to make your own subclasses. In most cases, you will probably
|
||||
override Connection.default_cursor with a non-standard Cursor class.
|
||||
"""
|
||||
import re
|
||||
|
||||
from . import cursors, _mysql
|
||||
from ._exceptions import (
|
||||
Warning,
|
||||
Error,
|
||||
InterfaceError,
|
||||
DataError,
|
||||
DatabaseError,
|
||||
OperationalError,
|
||||
IntegrityError,
|
||||
InternalError,
|
||||
NotSupportedError,
|
||||
ProgrammingError,
|
||||
)
|
||||
|
||||
# Mapping from MySQL charset name to Python codec name
|
||||
_charset_to_encoding = {
|
||||
"utf8mb4": "utf8",
|
||||
"utf8mb3": "utf8",
|
||||
"latin1": "cp1252",
|
||||
"koi8r": "koi8_r",
|
||||
"koi8u": "koi8_u",
|
||||
}
|
||||
|
||||
re_numeric_part = re.compile(r"^(\d+)")
|
||||
|
||||
|
||||
def numeric_part(s):
|
||||
"""Returns the leading numeric part of a string.
|
||||
|
||||
>>> numeric_part("20-alpha")
|
||||
20
|
||||
>>> numeric_part("foo")
|
||||
>>> numeric_part("16b")
|
||||
16
|
||||
"""
|
||||
|
||||
m = re_numeric_part.match(s)
|
||||
if m:
|
||||
return int(m.group(1))
|
||||
return None
|
||||
|
||||
|
||||
class Connection(_mysql.connection):
|
||||
"""MySQL Database Connection Object"""
|
||||
|
||||
default_cursor = cursors.Cursor
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
Create a connection to the database. It is strongly recommended
|
||||
that you only use keyword parameters. Consult the MySQL C API
|
||||
documentation for more information.
|
||||
|
||||
:param str host: host to connect
|
||||
:param str user: user to connect as
|
||||
:param str password: password to use
|
||||
:param str passwd: alias of password (deprecated)
|
||||
:param str database: database to use
|
||||
:param str db: alias of database (deprecated)
|
||||
:param int port: TCP/IP port to connect to
|
||||
:param str unix_socket: location of unix_socket to use
|
||||
:param dict conv: conversion dictionary, see MySQLdb.converters
|
||||
:param int connect_timeout:
|
||||
number of seconds to wait before the connection attempt fails.
|
||||
|
||||
:param bool compress: if set, compression is enabled
|
||||
:param str named_pipe: if set, a named pipe is used to connect (Windows only)
|
||||
:param str init_command:
|
||||
command which is run once the connection is created
|
||||
|
||||
:param str read_default_file:
|
||||
file from which default client values are read
|
||||
|
||||
:param str read_default_group:
|
||||
configuration group to use from the default file
|
||||
|
||||
:param type cursorclass:
|
||||
class object, used to create cursors (keyword only)
|
||||
|
||||
:param bool use_unicode:
|
||||
If True, text-like columns are returned as unicode objects
|
||||
using the connection's character set. Otherwise, text-like
|
||||
columns are returned as bytes. Unicode objects will always
|
||||
be encoded to the connection's character set regardless of
|
||||
this setting.
|
||||
Default to True.
|
||||
|
||||
:param str charset:
|
||||
If supplied, the connection character set will be changed
|
||||
to this character set.
|
||||
|
||||
:param str collation:
|
||||
If ``charset`` and ``collation`` are both supplied, the
|
||||
character set and collation for the current connection
|
||||
will be set.
|
||||
|
||||
If omitted, empty string, or None, the default collation
|
||||
for the ``charset`` is implied.
|
||||
|
||||
:param str auth_plugin:
|
||||
If supplied, the connection default authentication plugin will be
|
||||
changed to this value. Example values:
|
||||
`mysql_native_password` or `caching_sha2_password`
|
||||
|
||||
:param str sql_mode:
|
||||
If supplied, the session SQL mode will be changed to this
|
||||
setting.
|
||||
For more details and legal values, see the MySQL documentation.
|
||||
|
||||
:param int client_flag:
|
||||
flags to use or 0 (see MySQL docs or constants/CLIENTS.py)
|
||||
|
||||
:param bool multi_statements:
|
||||
If True, enable multi statements for clients >= 4.1.
|
||||
Defaults to True.
|
||||
|
||||
:param str ssl_mode:
|
||||
specify the security settings for connection to the server;
|
||||
see the MySQL documentation for more details
|
||||
(mysql_option(), MYSQL_OPT_SSL_MODE).
|
||||
Only one of 'DISABLED', 'PREFERRED', 'REQUIRED',
|
||||
'VERIFY_CA', 'VERIFY_IDENTITY' can be specified.
|
||||
|
||||
:param dict ssl:
|
||||
dictionary or mapping contains SSL connection parameters;
|
||||
see the MySQL documentation for more details
|
||||
(mysql_ssl_set()). If this is set, and the client does not
|
||||
support SSL, NotSupportedError will be raised.
|
||||
Since mysqlclient 2.2.4, ssl=True is alias of ssl_mode=REQUIRED
|
||||
for better compatibility with PyMySQL and MariaDB.
|
||||
|
||||
:param str server_public_key_path:
|
||||
specify the path to a file RSA public key file for caching_sha2_password.
|
||||
See https://dev.mysql.com/doc/refman/9.0/en/caching-sha2-pluggable-authentication.html
|
||||
|
||||
:param bool local_infile:
|
||||
enables LOAD LOCAL INFILE; zero disables
|
||||
|
||||
:param bool autocommit:
|
||||
If False (default), autocommit is disabled.
|
||||
If True, autocommit is enabled.
|
||||
If None, autocommit isn't set and server default is used.
|
||||
|
||||
:param bool binary_prefix:
|
||||
If set, the '_binary' prefix will be used for raw byte query
|
||||
arguments (e.g. Binary). This is disabled by default.
|
||||
|
||||
There are a number of undocumented, non-standard methods. See the
|
||||
documentation for the MySQL C API for some hints on what they do.
|
||||
"""
|
||||
from MySQLdb.constants import CLIENT, FIELD_TYPE
|
||||
from MySQLdb.converters import conversions, _bytes_or_str
|
||||
|
||||
kwargs2 = kwargs.copy()
|
||||
|
||||
if "db" in kwargs2:
|
||||
kwargs2["database"] = kwargs2.pop("db")
|
||||
if "passwd" in kwargs2:
|
||||
kwargs2["password"] = kwargs2.pop("passwd")
|
||||
|
||||
if "conv" in kwargs:
|
||||
conv = kwargs["conv"]
|
||||
else:
|
||||
conv = conversions
|
||||
|
||||
conv2 = {}
|
||||
for k, v in conv.items():
|
||||
if isinstance(k, int) and isinstance(v, list):
|
||||
conv2[k] = v[:]
|
||||
else:
|
||||
conv2[k] = v
|
||||
kwargs2["conv"] = conv2
|
||||
|
||||
cursorclass = kwargs2.pop("cursorclass", self.default_cursor)
|
||||
charset = kwargs2.get("charset", "")
|
||||
collation = kwargs2.pop("collation", "")
|
||||
use_unicode = kwargs2.pop("use_unicode", True)
|
||||
sql_mode = kwargs2.pop("sql_mode", "")
|
||||
self._binary_prefix = kwargs2.pop("binary_prefix", False)
|
||||
|
||||
client_flag = kwargs.get("client_flag", 0)
|
||||
client_flag |= CLIENT.MULTI_RESULTS
|
||||
multi_statements = kwargs2.pop("multi_statements", True)
|
||||
if multi_statements:
|
||||
client_flag |= CLIENT.MULTI_STATEMENTS
|
||||
kwargs2["client_flag"] = client_flag
|
||||
|
||||
# PEP-249 requires autocommit to be initially off
|
||||
autocommit = kwargs2.pop("autocommit", False)
|
||||
|
||||
self._set_attributes(*args, **kwargs2)
|
||||
super().__init__(*args, **kwargs2)
|
||||
|
||||
self.cursorclass = cursorclass
|
||||
self.encoders = {
|
||||
k: v
|
||||
for k, v in conv.items()
|
||||
if type(k) is not int # noqa: E721
|
||||
}
|
||||
self._server_version = tuple(
|
||||
[numeric_part(n) for n in self.get_server_info().split(".")[:2]]
|
||||
)
|
||||
self.encoding = "ascii" # overridden in set_character_set()
|
||||
|
||||
if not charset:
|
||||
charset = self.character_set_name()
|
||||
self.set_character_set(charset, collation)
|
||||
|
||||
if sql_mode:
|
||||
self.set_sql_mode(sql_mode)
|
||||
|
||||
if use_unicode:
|
||||
for t in (
|
||||
FIELD_TYPE.STRING,
|
||||
FIELD_TYPE.VAR_STRING,
|
||||
FIELD_TYPE.VARCHAR,
|
||||
FIELD_TYPE.TINY_BLOB,
|
||||
FIELD_TYPE.MEDIUM_BLOB,
|
||||
FIELD_TYPE.LONG_BLOB,
|
||||
FIELD_TYPE.BLOB,
|
||||
):
|
||||
self.converter[t] = _bytes_or_str
|
||||
# Unlike other string/blob types, JSON is always text.
|
||||
# MySQL may return JSON with charset==binary.
|
||||
self.converter[FIELD_TYPE.JSON] = str
|
||||
|
||||
self._transactional = self.server_capabilities & CLIENT.TRANSACTIONS
|
||||
if self._transactional:
|
||||
if autocommit is not None:
|
||||
self.autocommit(autocommit)
|
||||
self.messages = []
|
||||
|
||||
def _set_attributes(self, host=None, user=None, password=None, database="", port=3306,
|
||||
unix_socket=None, **kwargs):
|
||||
"""set some attributes for otel"""
|
||||
if unix_socket and not host:
|
||||
host = "localhost"
|
||||
# support opentelemetry-instrumentation-dbapi
|
||||
self.host = host
|
||||
# _mysql.Connection provides self.port
|
||||
self.user = user
|
||||
self.database = database
|
||||
# otel-inst-mysqlclient uses db instead of database.
|
||||
self.db = database
|
||||
# NOTE: We have not supported semantic conventions yet.
|
||||
# https://opentelemetry.io/docs/specs/semconv/database/sql/
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.close()
|
||||
|
||||
def autocommit(self, on):
|
||||
on = bool(on)
|
||||
if self.get_autocommit() != on:
|
||||
_mysql.connection.autocommit(self, on)
|
||||
|
||||
def cursor(self, cursorclass=None):
|
||||
"""
|
||||
Create a cursor on which queries may be performed. The
|
||||
optional cursorclass parameter is used to create the
|
||||
Cursor. By default, self.cursorclass=cursors.Cursor is
|
||||
used.
|
||||
"""
|
||||
return (cursorclass or self.cursorclass)(self)
|
||||
|
||||
def query(self, query):
|
||||
# Since _mysql releases GIL while querying, we need immutable buffer.
|
||||
if isinstance(query, bytearray):
|
||||
query = bytes(query)
|
||||
_mysql.connection.query(self, query)
|
||||
|
||||
def _bytes_literal(self, bs):
|
||||
assert isinstance(bs, (bytes, bytearray))
|
||||
x = self.string_literal(bs) # x is escaped and quoted bytes
|
||||
if self._binary_prefix:
|
||||
return b"_binary" + x
|
||||
return x
|
||||
|
||||
def _tuple_literal(self, t):
|
||||
return b"(%s)" % (b",".join(map(self.literal, t)))
|
||||
|
||||
def literal(self, o):
|
||||
"""If o is a single object, returns an SQL literal as a string.
|
||||
If o is a non-string sequence, the items of the sequence are
|
||||
converted and returned as a sequence.
|
||||
|
||||
Non-standard. For internal use; do not use this in your
|
||||
applications.
|
||||
"""
|
||||
if isinstance(o, str):
|
||||
s = self.string_literal(o.encode(self.encoding))
|
||||
elif isinstance(o, bytearray):
|
||||
s = self._bytes_literal(o)
|
||||
elif isinstance(o, bytes):
|
||||
s = self._bytes_literal(o)
|
||||
elif isinstance(o, (tuple, list)):
|
||||
s = self._tuple_literal(o)
|
||||
else:
|
||||
s = self.escape(o, self.encoders)
|
||||
if isinstance(s, str):
|
||||
s = s.encode(self.encoding)
|
||||
assert isinstance(s, bytes)
|
||||
return s
|
||||
|
||||
def begin(self):
|
||||
"""Explicitly begin a connection.
|
||||
|
||||
This method is not used when autocommit=False (default).
|
||||
"""
|
||||
self.query(b"BEGIN")
|
||||
|
||||
def set_character_set(self, charset, collation=None):
|
||||
"""Set the connection character set to charset."""
|
||||
super().set_character_set(charset)
|
||||
self.encoding = _charset_to_encoding.get(charset, charset)
|
||||
if collation:
|
||||
self.query(f"SET NAMES {charset} COLLATE {collation}")
|
||||
self.store_result()
|
||||
|
||||
def set_sql_mode(self, sql_mode):
|
||||
"""Set the connection sql_mode. See MySQL documentation for
|
||||
legal values."""
|
||||
if self._server_version < (4, 1):
|
||||
raise NotSupportedError("server is too old to set sql_mode")
|
||||
self.query("SET SESSION sql_mode='%s'" % sql_mode)
|
||||
self.store_result()
|
||||
|
||||
def show_warnings(self):
|
||||
"""Return detailed information about warnings as a
|
||||
sequence of tuples of (Level, Code, Message). This
|
||||
is only supported in MySQL-4.1 and up. If your server
|
||||
is an earlier version, an empty sequence is returned."""
|
||||
if self._server_version < (4, 1):
|
||||
return ()
|
||||
self.query("SHOW WARNINGS")
|
||||
r = self.store_result()
|
||||
warnings = r.fetch_row(0)
|
||||
return warnings
|
||||
|
||||
Warning = Warning
|
||||
Error = Error
|
||||
InterfaceError = InterfaceError
|
||||
DatabaseError = DatabaseError
|
||||
DataError = DataError
|
||||
OperationalError = OperationalError
|
||||
IntegrityError = IntegrityError
|
||||
InternalError = InternalError
|
||||
ProgrammingError = ProgrammingError
|
||||
NotSupportedError = NotSupportedError
|
||||
|
||||
|
||||
# vim: colorcolumn=100
|
27
venv/Lib/site-packages/MySQLdb/constants/CLIENT.py
Normal file
27
venv/Lib/site-packages/MySQLdb/constants/CLIENT.py
Normal file
@ -0,0 +1,27 @@
|
||||
"""MySQL CLIENT constants
|
||||
|
||||
These constants are used when creating the connection. Use bitwise-OR
|
||||
(|) to combine options together, and pass them as the client_flags
|
||||
parameter to MySQLdb.Connection. For more information on these flags,
|
||||
see the MySQL C API documentation for mysql_real_connect().
|
||||
|
||||
"""
|
||||
|
||||
LONG_PASSWORD = 1
|
||||
FOUND_ROWS = 2
|
||||
LONG_FLAG = 4
|
||||
CONNECT_WITH_DB = 8
|
||||
NO_SCHEMA = 16
|
||||
COMPRESS = 32
|
||||
ODBC = 64
|
||||
LOCAL_FILES = 128
|
||||
IGNORE_SPACE = 256
|
||||
CHANGE_USER = 512
|
||||
INTERACTIVE = 1024
|
||||
SSL = 2048
|
||||
IGNORE_SIGPIPE = 4096
|
||||
TRANSACTIONS = 8192 # mysql_com.h was WRONG prior to 3.23.35
|
||||
RESERVED = 16384
|
||||
SECURE_CONNECTION = 32768
|
||||
MULTI_STATEMENTS = 65536
|
||||
MULTI_RESULTS = 131072
|
105
venv/Lib/site-packages/MySQLdb/constants/CR.py
Normal file
105
venv/Lib/site-packages/MySQLdb/constants/CR.py
Normal file
@ -0,0 +1,105 @@
|
||||
"""MySQL Connection Errors
|
||||
|
||||
Nearly all of these raise OperationalError. COMMANDS_OUT_OF_SYNC
|
||||
raises ProgrammingError.
|
||||
|
||||
"""
|
||||
|
||||
if __name__ == "__main__":
|
||||
"""
|
||||
Usage: python CR.py [/path/to/mysql/errmsg.h ...] >> CR.py
|
||||
"""
|
||||
import fileinput
|
||||
import re
|
||||
|
||||
data = {}
|
||||
error_last = None
|
||||
for line in fileinput.input():
|
||||
line = re.sub(r"/\*.*?\*/", "", line)
|
||||
m = re.match(r"^\s*#define\s+CR_([A-Z0-9_]+)\s+(\d+)(\s.*|$)", line)
|
||||
if m:
|
||||
name = m.group(1)
|
||||
value = int(m.group(2))
|
||||
if name == "ERROR_LAST":
|
||||
if error_last is None or error_last < value:
|
||||
error_last = value
|
||||
continue
|
||||
if value not in data:
|
||||
data[value] = set()
|
||||
data[value].add(name)
|
||||
for value, names in sorted(data.items()):
|
||||
for name in sorted(names):
|
||||
print(f"{name} = {value}")
|
||||
if error_last is not None:
|
||||
print("ERROR_LAST = %s" % error_last)
|
||||
|
||||
|
||||
ERROR_FIRST = 2000
|
||||
MIN_ERROR = 2000
|
||||
UNKNOWN_ERROR = 2000
|
||||
SOCKET_CREATE_ERROR = 2001
|
||||
CONNECTION_ERROR = 2002
|
||||
CONN_HOST_ERROR = 2003
|
||||
IPSOCK_ERROR = 2004
|
||||
UNKNOWN_HOST = 2005
|
||||
SERVER_GONE_ERROR = 2006
|
||||
VERSION_ERROR = 2007
|
||||
OUT_OF_MEMORY = 2008
|
||||
WRONG_HOST_INFO = 2009
|
||||
LOCALHOST_CONNECTION = 2010
|
||||
TCP_CONNECTION = 2011
|
||||
SERVER_HANDSHAKE_ERR = 2012
|
||||
SERVER_LOST = 2013
|
||||
COMMANDS_OUT_OF_SYNC = 2014
|
||||
NAMEDPIPE_CONNECTION = 2015
|
||||
NAMEDPIPEWAIT_ERROR = 2016
|
||||
NAMEDPIPEOPEN_ERROR = 2017
|
||||
NAMEDPIPESETSTATE_ERROR = 2018
|
||||
CANT_READ_CHARSET = 2019
|
||||
NET_PACKET_TOO_LARGE = 2020
|
||||
EMBEDDED_CONNECTION = 2021
|
||||
PROBE_SLAVE_STATUS = 2022
|
||||
PROBE_SLAVE_HOSTS = 2023
|
||||
PROBE_SLAVE_CONNECT = 2024
|
||||
PROBE_MASTER_CONNECT = 2025
|
||||
SSL_CONNECTION_ERROR = 2026
|
||||
MALFORMED_PACKET = 2027
|
||||
WRONG_LICENSE = 2028
|
||||
NULL_POINTER = 2029
|
||||
NO_PREPARE_STMT = 2030
|
||||
PARAMS_NOT_BOUND = 2031
|
||||
DATA_TRUNCATED = 2032
|
||||
NO_PARAMETERS_EXISTS = 2033
|
||||
INVALID_PARAMETER_NO = 2034
|
||||
INVALID_BUFFER_USE = 2035
|
||||
UNSUPPORTED_PARAM_TYPE = 2036
|
||||
SHARED_MEMORY_CONNECTION = 2037
|
||||
SHARED_MEMORY_CONNECT_REQUEST_ERROR = 2038
|
||||
SHARED_MEMORY_CONNECT_ANSWER_ERROR = 2039
|
||||
SHARED_MEMORY_CONNECT_FILE_MAP_ERROR = 2040
|
||||
SHARED_MEMORY_CONNECT_MAP_ERROR = 2041
|
||||
SHARED_MEMORY_FILE_MAP_ERROR = 2042
|
||||
SHARED_MEMORY_MAP_ERROR = 2043
|
||||
SHARED_MEMORY_EVENT_ERROR = 2044
|
||||
SHARED_MEMORY_CONNECT_ABANDONED_ERROR = 2045
|
||||
SHARED_MEMORY_CONNECT_SET_ERROR = 2046
|
||||
CONN_UNKNOW_PROTOCOL = 2047
|
||||
INVALID_CONN_HANDLE = 2048
|
||||
UNUSED_1 = 2049
|
||||
FETCH_CANCELED = 2050
|
||||
NO_DATA = 2051
|
||||
NO_STMT_METADATA = 2052
|
||||
NO_RESULT_SET = 2053
|
||||
NOT_IMPLEMENTED = 2054
|
||||
SERVER_LOST_EXTENDED = 2055
|
||||
STMT_CLOSED = 2056
|
||||
NEW_STMT_METADATA = 2057
|
||||
ALREADY_CONNECTED = 2058
|
||||
AUTH_PLUGIN_CANNOT_LOAD = 2059
|
||||
DUPLICATE_CONNECTION_ATTR = 2060
|
||||
AUTH_PLUGIN_ERR = 2061
|
||||
INSECURE_API_ERR = 2062
|
||||
FILE_NAME_TOO_LONG = 2063
|
||||
SSL_FIPS_MODE_ERR = 2064
|
||||
MAX_ERROR = 2999
|
||||
ERROR_LAST = 2064
|
827
venv/Lib/site-packages/MySQLdb/constants/ER.py
Normal file
827
venv/Lib/site-packages/MySQLdb/constants/ER.py
Normal file
@ -0,0 +1,827 @@
|
||||
"""MySQL ER Constants
|
||||
|
||||
These constants are error codes for the bulk of the error conditions
|
||||
that may occur.
|
||||
"""
|
||||
|
||||
if __name__ == "__main__":
|
||||
"""
|
||||
Usage: python ER.py [/path/to/mysql/mysqld_error.h ...] >> ER.py
|
||||
"""
|
||||
import fileinput
|
||||
import re
|
||||
|
||||
data = {}
|
||||
error_last = None
|
||||
for line in fileinput.input():
|
||||
line = re.sub(r"/\*.*?\*/", "", line)
|
||||
m = re.match(r"^\s*#define\s+((ER|WARN)_[A-Z0-9_]+)\s+(\d+)\s*", line)
|
||||
if m:
|
||||
name = m.group(1)
|
||||
if name.startswith("ER_"):
|
||||
name = name[3:]
|
||||
value = int(m.group(3))
|
||||
if name == "ERROR_LAST":
|
||||
if error_last is None or error_last < value:
|
||||
error_last = value
|
||||
continue
|
||||
if value not in data:
|
||||
data[value] = set()
|
||||
data[value].add(name)
|
||||
for value, names in sorted(data.items()):
|
||||
for name in sorted(names):
|
||||
print(f"{name} = {value}")
|
||||
if error_last is not None:
|
||||
print("ERROR_LAST = %s" % error_last)
|
||||
|
||||
|
||||
ERROR_FIRST = 1000
|
||||
NO = 1002
|
||||
YES = 1003
|
||||
CANT_CREATE_FILE = 1004
|
||||
CANT_CREATE_TABLE = 1005
|
||||
CANT_CREATE_DB = 1006
|
||||
DB_CREATE_EXISTS = 1007
|
||||
DB_DROP_EXISTS = 1008
|
||||
DB_DROP_RMDIR = 1010
|
||||
CANT_FIND_SYSTEM_REC = 1012
|
||||
CANT_GET_STAT = 1013
|
||||
CANT_LOCK = 1015
|
||||
CANT_OPEN_FILE = 1016
|
||||
FILE_NOT_FOUND = 1017
|
||||
CANT_READ_DIR = 1018
|
||||
CHECKREAD = 1020
|
||||
DUP_KEY = 1022
|
||||
ERROR_ON_READ = 1024
|
||||
ERROR_ON_RENAME = 1025
|
||||
ERROR_ON_WRITE = 1026
|
||||
FILE_USED = 1027
|
||||
FILSORT_ABORT = 1028
|
||||
GET_ERRNO = 1030
|
||||
ILLEGAL_HA = 1031
|
||||
KEY_NOT_FOUND = 1032
|
||||
NOT_FORM_FILE = 1033
|
||||
NOT_KEYFILE = 1034
|
||||
OLD_KEYFILE = 1035
|
||||
OPEN_AS_READONLY = 1036
|
||||
OUTOFMEMORY = 1037
|
||||
OUT_OF_SORTMEMORY = 1038
|
||||
CON_COUNT_ERROR = 1040
|
||||
OUT_OF_RESOURCES = 1041
|
||||
BAD_HOST_ERROR = 1042
|
||||
HANDSHAKE_ERROR = 1043
|
||||
DBACCESS_DENIED_ERROR = 1044
|
||||
ACCESS_DENIED_ERROR = 1045
|
||||
NO_DB_ERROR = 1046
|
||||
UNKNOWN_COM_ERROR = 1047
|
||||
BAD_NULL_ERROR = 1048
|
||||
BAD_DB_ERROR = 1049
|
||||
TABLE_EXISTS_ERROR = 1050
|
||||
BAD_TABLE_ERROR = 1051
|
||||
NON_UNIQ_ERROR = 1052
|
||||
SERVER_SHUTDOWN = 1053
|
||||
BAD_FIELD_ERROR = 1054
|
||||
WRONG_FIELD_WITH_GROUP = 1055
|
||||
WRONG_GROUP_FIELD = 1056
|
||||
WRONG_SUM_SELECT = 1057
|
||||
WRONG_VALUE_COUNT = 1058
|
||||
TOO_LONG_IDENT = 1059
|
||||
DUP_FIELDNAME = 1060
|
||||
DUP_KEYNAME = 1061
|
||||
DUP_ENTRY = 1062
|
||||
WRONG_FIELD_SPEC = 1063
|
||||
PARSE_ERROR = 1064
|
||||
EMPTY_QUERY = 1065
|
||||
NONUNIQ_TABLE = 1066
|
||||
INVALID_DEFAULT = 1067
|
||||
MULTIPLE_PRI_KEY = 1068
|
||||
TOO_MANY_KEYS = 1069
|
||||
TOO_MANY_KEY_PARTS = 1070
|
||||
TOO_LONG_KEY = 1071
|
||||
KEY_COLUMN_DOES_NOT_EXITS = 1072
|
||||
BLOB_USED_AS_KEY = 1073
|
||||
TOO_BIG_FIELDLENGTH = 1074
|
||||
WRONG_AUTO_KEY = 1075
|
||||
READY = 1076
|
||||
SHUTDOWN_COMPLETE = 1079
|
||||
FORCING_CLOSE = 1080
|
||||
IPSOCK_ERROR = 1081
|
||||
NO_SUCH_INDEX = 1082
|
||||
WRONG_FIELD_TERMINATORS = 1083
|
||||
BLOBS_AND_NO_TERMINATED = 1084
|
||||
TEXTFILE_NOT_READABLE = 1085
|
||||
FILE_EXISTS_ERROR = 1086
|
||||
LOAD_INFO = 1087
|
||||
ALTER_INFO = 1088
|
||||
WRONG_SUB_KEY = 1089
|
||||
CANT_REMOVE_ALL_FIELDS = 1090
|
||||
CANT_DROP_FIELD_OR_KEY = 1091
|
||||
INSERT_INFO = 1092
|
||||
UPDATE_TABLE_USED = 1093
|
||||
NO_SUCH_THREAD = 1094
|
||||
KILL_DENIED_ERROR = 1095
|
||||
NO_TABLES_USED = 1096
|
||||
TOO_BIG_SET = 1097
|
||||
NO_UNIQUE_LOGFILE = 1098
|
||||
TABLE_NOT_LOCKED_FOR_WRITE = 1099
|
||||
TABLE_NOT_LOCKED = 1100
|
||||
BLOB_CANT_HAVE_DEFAULT = 1101
|
||||
WRONG_DB_NAME = 1102
|
||||
WRONG_TABLE_NAME = 1103
|
||||
TOO_BIG_SELECT = 1104
|
||||
UNKNOWN_ERROR = 1105
|
||||
UNKNOWN_PROCEDURE = 1106
|
||||
WRONG_PARAMCOUNT_TO_PROCEDURE = 1107
|
||||
WRONG_PARAMETERS_TO_PROCEDURE = 1108
|
||||
UNKNOWN_TABLE = 1109
|
||||
FIELD_SPECIFIED_TWICE = 1110
|
||||
INVALID_GROUP_FUNC_USE = 1111
|
||||
UNSUPPORTED_EXTENSION = 1112
|
||||
TABLE_MUST_HAVE_COLUMNS = 1113
|
||||
RECORD_FILE_FULL = 1114
|
||||
UNKNOWN_CHARACTER_SET = 1115
|
||||
TOO_MANY_TABLES = 1116
|
||||
TOO_MANY_FIELDS = 1117
|
||||
TOO_BIG_ROWSIZE = 1118
|
||||
STACK_OVERRUN = 1119
|
||||
WRONG_OUTER_JOIN_UNUSED = 1120
|
||||
NULL_COLUMN_IN_INDEX = 1121
|
||||
CANT_FIND_UDF = 1122
|
||||
CANT_INITIALIZE_UDF = 1123
|
||||
UDF_NO_PATHS = 1124
|
||||
UDF_EXISTS = 1125
|
||||
CANT_OPEN_LIBRARY = 1126
|
||||
CANT_FIND_DL_ENTRY = 1127
|
||||
FUNCTION_NOT_DEFINED = 1128
|
||||
HOST_IS_BLOCKED = 1129
|
||||
HOST_NOT_PRIVILEGED = 1130
|
||||
PASSWORD_ANONYMOUS_USER = 1131
|
||||
PASSWORD_NOT_ALLOWED = 1132
|
||||
PASSWORD_NO_MATCH = 1133
|
||||
UPDATE_INFO = 1134
|
||||
CANT_CREATE_THREAD = 1135
|
||||
WRONG_VALUE_COUNT_ON_ROW = 1136
|
||||
CANT_REOPEN_TABLE = 1137
|
||||
INVALID_USE_OF_NULL = 1138
|
||||
REGEXP_ERROR = 1139
|
||||
MIX_OF_GROUP_FUNC_AND_FIELDS = 1140
|
||||
NONEXISTING_GRANT = 1141
|
||||
TABLEACCESS_DENIED_ERROR = 1142
|
||||
COLUMNACCESS_DENIED_ERROR = 1143
|
||||
ILLEGAL_GRANT_FOR_TABLE = 1144
|
||||
GRANT_WRONG_HOST_OR_USER = 1145
|
||||
NO_SUCH_TABLE = 1146
|
||||
NONEXISTING_TABLE_GRANT = 1147
|
||||
NOT_ALLOWED_COMMAND = 1148
|
||||
SYNTAX_ERROR = 1149
|
||||
ABORTING_CONNECTION = 1152
|
||||
NET_PACKET_TOO_LARGE = 1153
|
||||
NET_READ_ERROR_FROM_PIPE = 1154
|
||||
NET_FCNTL_ERROR = 1155
|
||||
NET_PACKETS_OUT_OF_ORDER = 1156
|
||||
NET_UNCOMPRESS_ERROR = 1157
|
||||
NET_READ_ERROR = 1158
|
||||
NET_READ_INTERRUPTED = 1159
|
||||
NET_ERROR_ON_WRITE = 1160
|
||||
NET_WRITE_INTERRUPTED = 1161
|
||||
TOO_LONG_STRING = 1162
|
||||
TABLE_CANT_HANDLE_BLOB = 1163
|
||||
TABLE_CANT_HANDLE_AUTO_INCREMENT = 1164
|
||||
WRONG_COLUMN_NAME = 1166
|
||||
WRONG_KEY_COLUMN = 1167
|
||||
WRONG_MRG_TABLE = 1168
|
||||
DUP_UNIQUE = 1169
|
||||
BLOB_KEY_WITHOUT_LENGTH = 1170
|
||||
PRIMARY_CANT_HAVE_NULL = 1171
|
||||
TOO_MANY_ROWS = 1172
|
||||
REQUIRES_PRIMARY_KEY = 1173
|
||||
UPDATE_WITHOUT_KEY_IN_SAFE_MODE = 1175
|
||||
KEY_DOES_NOT_EXITS = 1176
|
||||
CHECK_NO_SUCH_TABLE = 1177
|
||||
CHECK_NOT_IMPLEMENTED = 1178
|
||||
CANT_DO_THIS_DURING_AN_TRANSACTION = 1179
|
||||
ERROR_DURING_COMMIT = 1180
|
||||
ERROR_DURING_ROLLBACK = 1181
|
||||
ERROR_DURING_FLUSH_LOGS = 1182
|
||||
NEW_ABORTING_CONNECTION = 1184
|
||||
MASTER = 1188
|
||||
MASTER_NET_READ = 1189
|
||||
MASTER_NET_WRITE = 1190
|
||||
FT_MATCHING_KEY_NOT_FOUND = 1191
|
||||
LOCK_OR_ACTIVE_TRANSACTION = 1192
|
||||
UNKNOWN_SYSTEM_VARIABLE = 1193
|
||||
CRASHED_ON_USAGE = 1194
|
||||
CRASHED_ON_REPAIR = 1195
|
||||
WARNING_NOT_COMPLETE_ROLLBACK = 1196
|
||||
TRANS_CACHE_FULL = 1197
|
||||
SLAVE_NOT_RUNNING = 1199
|
||||
BAD_SLAVE = 1200
|
||||
MASTER_INFO = 1201
|
||||
SLAVE_THREAD = 1202
|
||||
TOO_MANY_USER_CONNECTIONS = 1203
|
||||
SET_CONSTANTS_ONLY = 1204
|
||||
LOCK_WAIT_TIMEOUT = 1205
|
||||
LOCK_TABLE_FULL = 1206
|
||||
READ_ONLY_TRANSACTION = 1207
|
||||
WRONG_ARGUMENTS = 1210
|
||||
NO_PERMISSION_TO_CREATE_USER = 1211
|
||||
LOCK_DEADLOCK = 1213
|
||||
TABLE_CANT_HANDLE_FT = 1214
|
||||
CANNOT_ADD_FOREIGN = 1215
|
||||
NO_REFERENCED_ROW = 1216
|
||||
ROW_IS_REFERENCED = 1217
|
||||
CONNECT_TO_MASTER = 1218
|
||||
ERROR_WHEN_EXECUTING_COMMAND = 1220
|
||||
WRONG_USAGE = 1221
|
||||
WRONG_NUMBER_OF_COLUMNS_IN_SELECT = 1222
|
||||
CANT_UPDATE_WITH_READLOCK = 1223
|
||||
MIXING_NOT_ALLOWED = 1224
|
||||
DUP_ARGUMENT = 1225
|
||||
USER_LIMIT_REACHED = 1226
|
||||
SPECIFIC_ACCESS_DENIED_ERROR = 1227
|
||||
LOCAL_VARIABLE = 1228
|
||||
GLOBAL_VARIABLE = 1229
|
||||
NO_DEFAULT = 1230
|
||||
WRONG_VALUE_FOR_VAR = 1231
|
||||
WRONG_TYPE_FOR_VAR = 1232
|
||||
VAR_CANT_BE_READ = 1233
|
||||
CANT_USE_OPTION_HERE = 1234
|
||||
NOT_SUPPORTED_YET = 1235
|
||||
MASTER_FATAL_ERROR_READING_BINLOG = 1236
|
||||
SLAVE_IGNORED_TABLE = 1237
|
||||
INCORRECT_GLOBAL_LOCAL_VAR = 1238
|
||||
WRONG_FK_DEF = 1239
|
||||
KEY_REF_DO_NOT_MATCH_TABLE_REF = 1240
|
||||
OPERAND_COLUMNS = 1241
|
||||
SUBQUERY_NO_1_ROW = 1242
|
||||
UNKNOWN_STMT_HANDLER = 1243
|
||||
CORRUPT_HELP_DB = 1244
|
||||
AUTO_CONVERT = 1246
|
||||
ILLEGAL_REFERENCE = 1247
|
||||
DERIVED_MUST_HAVE_ALIAS = 1248
|
||||
SELECT_REDUCED = 1249
|
||||
TABLENAME_NOT_ALLOWED_HERE = 1250
|
||||
NOT_SUPPORTED_AUTH_MODE = 1251
|
||||
SPATIAL_CANT_HAVE_NULL = 1252
|
||||
COLLATION_CHARSET_MISMATCH = 1253
|
||||
TOO_BIG_FOR_UNCOMPRESS = 1256
|
||||
ZLIB_Z_MEM_ERROR = 1257
|
||||
ZLIB_Z_BUF_ERROR = 1258
|
||||
ZLIB_Z_DATA_ERROR = 1259
|
||||
CUT_VALUE_GROUP_CONCAT = 1260
|
||||
WARN_TOO_FEW_RECORDS = 1261
|
||||
WARN_TOO_MANY_RECORDS = 1262
|
||||
WARN_NULL_TO_NOTNULL = 1263
|
||||
WARN_DATA_OUT_OF_RANGE = 1264
|
||||
WARN_DATA_TRUNCATED = 1265
|
||||
WARN_USING_OTHER_HANDLER = 1266
|
||||
CANT_AGGREGATE_2COLLATIONS = 1267
|
||||
REVOKE_GRANTS = 1269
|
||||
CANT_AGGREGATE_3COLLATIONS = 1270
|
||||
CANT_AGGREGATE_NCOLLATIONS = 1271
|
||||
VARIABLE_IS_NOT_STRUCT = 1272
|
||||
UNKNOWN_COLLATION = 1273
|
||||
SLAVE_IGNORED_SSL_PARAMS = 1274
|
||||
SERVER_IS_IN_SECURE_AUTH_MODE = 1275
|
||||
WARN_FIELD_RESOLVED = 1276
|
||||
BAD_SLAVE_UNTIL_COND = 1277
|
||||
MISSING_SKIP_SLAVE = 1278
|
||||
UNTIL_COND_IGNORED = 1279
|
||||
WRONG_NAME_FOR_INDEX = 1280
|
||||
WRONG_NAME_FOR_CATALOG = 1281
|
||||
BAD_FT_COLUMN = 1283
|
||||
UNKNOWN_KEY_CACHE = 1284
|
||||
WARN_HOSTNAME_WONT_WORK = 1285
|
||||
UNKNOWN_STORAGE_ENGINE = 1286
|
||||
WARN_DEPRECATED_SYNTAX = 1287
|
||||
NON_UPDATABLE_TABLE = 1288
|
||||
FEATURE_DISABLED = 1289
|
||||
OPTION_PREVENTS_STATEMENT = 1290
|
||||
DUPLICATED_VALUE_IN_TYPE = 1291
|
||||
TRUNCATED_WRONG_VALUE = 1292
|
||||
INVALID_ON_UPDATE = 1294
|
||||
UNSUPPORTED_PS = 1295
|
||||
GET_ERRMSG = 1296
|
||||
GET_TEMPORARY_ERRMSG = 1297
|
||||
UNKNOWN_TIME_ZONE = 1298
|
||||
WARN_INVALID_TIMESTAMP = 1299
|
||||
INVALID_CHARACTER_STRING = 1300
|
||||
WARN_ALLOWED_PACKET_OVERFLOWED = 1301
|
||||
CONFLICTING_DECLARATIONS = 1302
|
||||
SP_NO_RECURSIVE_CREATE = 1303
|
||||
SP_ALREADY_EXISTS = 1304
|
||||
SP_DOES_NOT_EXIST = 1305
|
||||
SP_DROP_FAILED = 1306
|
||||
SP_STORE_FAILED = 1307
|
||||
SP_LILABEL_MISMATCH = 1308
|
||||
SP_LABEL_REDEFINE = 1309
|
||||
SP_LABEL_MISMATCH = 1310
|
||||
SP_UNINIT_VAR = 1311
|
||||
SP_BADSELECT = 1312
|
||||
SP_BADRETURN = 1313
|
||||
SP_BADSTATEMENT = 1314
|
||||
UPDATE_LOG_DEPRECATED_IGNORED = 1315
|
||||
UPDATE_LOG_DEPRECATED_TRANSLATED = 1316
|
||||
QUERY_INTERRUPTED = 1317
|
||||
SP_WRONG_NO_OF_ARGS = 1318
|
||||
SP_COND_MISMATCH = 1319
|
||||
SP_NORETURN = 1320
|
||||
SP_NORETURNEND = 1321
|
||||
SP_BAD_CURSOR_QUERY = 1322
|
||||
SP_BAD_CURSOR_SELECT = 1323
|
||||
SP_CURSOR_MISMATCH = 1324
|
||||
SP_CURSOR_ALREADY_OPEN = 1325
|
||||
SP_CURSOR_NOT_OPEN = 1326
|
||||
SP_UNDECLARED_VAR = 1327
|
||||
SP_WRONG_NO_OF_FETCH_ARGS = 1328
|
||||
SP_FETCH_NO_DATA = 1329
|
||||
SP_DUP_PARAM = 1330
|
||||
SP_DUP_VAR = 1331
|
||||
SP_DUP_COND = 1332
|
||||
SP_DUP_CURS = 1333
|
||||
SP_CANT_ALTER = 1334
|
||||
SP_SUBSELECT_NYI = 1335
|
||||
STMT_NOT_ALLOWED_IN_SF_OR_TRG = 1336
|
||||
SP_VARCOND_AFTER_CURSHNDLR = 1337
|
||||
SP_CURSOR_AFTER_HANDLER = 1338
|
||||
SP_CASE_NOT_FOUND = 1339
|
||||
FPARSER_TOO_BIG_FILE = 1340
|
||||
FPARSER_BAD_HEADER = 1341
|
||||
FPARSER_EOF_IN_COMMENT = 1342
|
||||
FPARSER_ERROR_IN_PARAMETER = 1343
|
||||
FPARSER_EOF_IN_UNKNOWN_PARAMETER = 1344
|
||||
VIEW_NO_EXPLAIN = 1345
|
||||
WRONG_OBJECT = 1347
|
||||
NONUPDATEABLE_COLUMN = 1348
|
||||
VIEW_SELECT_CLAUSE = 1350
|
||||
VIEW_SELECT_VARIABLE = 1351
|
||||
VIEW_SELECT_TMPTABLE = 1352
|
||||
VIEW_WRONG_LIST = 1353
|
||||
WARN_VIEW_MERGE = 1354
|
||||
WARN_VIEW_WITHOUT_KEY = 1355
|
||||
VIEW_INVALID = 1356
|
||||
SP_NO_DROP_SP = 1357
|
||||
TRG_ALREADY_EXISTS = 1359
|
||||
TRG_DOES_NOT_EXIST = 1360
|
||||
TRG_ON_VIEW_OR_TEMP_TABLE = 1361
|
||||
TRG_CANT_CHANGE_ROW = 1362
|
||||
TRG_NO_SUCH_ROW_IN_TRG = 1363
|
||||
NO_DEFAULT_FOR_FIELD = 1364
|
||||
DIVISION_BY_ZERO = 1365
|
||||
TRUNCATED_WRONG_VALUE_FOR_FIELD = 1366
|
||||
ILLEGAL_VALUE_FOR_TYPE = 1367
|
||||
VIEW_NONUPD_CHECK = 1368
|
||||
VIEW_CHECK_FAILED = 1369
|
||||
PROCACCESS_DENIED_ERROR = 1370
|
||||
RELAY_LOG_FAIL = 1371
|
||||
UNKNOWN_TARGET_BINLOG = 1373
|
||||
IO_ERR_LOG_INDEX_READ = 1374
|
||||
BINLOG_PURGE_PROHIBITED = 1375
|
||||
FSEEK_FAIL = 1376
|
||||
BINLOG_PURGE_FATAL_ERR = 1377
|
||||
LOG_IN_USE = 1378
|
||||
LOG_PURGE_UNKNOWN_ERR = 1379
|
||||
RELAY_LOG_INIT = 1380
|
||||
NO_BINARY_LOGGING = 1381
|
||||
RESERVED_SYNTAX = 1382
|
||||
PS_MANY_PARAM = 1390
|
||||
KEY_PART_0 = 1391
|
||||
VIEW_CHECKSUM = 1392
|
||||
VIEW_MULTIUPDATE = 1393
|
||||
VIEW_NO_INSERT_FIELD_LIST = 1394
|
||||
VIEW_DELETE_MERGE_VIEW = 1395
|
||||
CANNOT_USER = 1396
|
||||
XAER_NOTA = 1397
|
||||
XAER_INVAL = 1398
|
||||
XAER_RMFAIL = 1399
|
||||
XAER_OUTSIDE = 1400
|
||||
XAER_RMERR = 1401
|
||||
XA_RBROLLBACK = 1402
|
||||
NONEXISTING_PROC_GRANT = 1403
|
||||
PROC_AUTO_GRANT_FAIL = 1404
|
||||
PROC_AUTO_REVOKE_FAIL = 1405
|
||||
DATA_TOO_LONG = 1406
|
||||
SP_BAD_SQLSTATE = 1407
|
||||
STARTUP = 1408
|
||||
LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR = 1409
|
||||
CANT_CREATE_USER_WITH_GRANT = 1410
|
||||
WRONG_VALUE_FOR_TYPE = 1411
|
||||
TABLE_DEF_CHANGED = 1412
|
||||
SP_DUP_HANDLER = 1413
|
||||
SP_NOT_VAR_ARG = 1414
|
||||
SP_NO_RETSET = 1415
|
||||
CANT_CREATE_GEOMETRY_OBJECT = 1416
|
||||
BINLOG_UNSAFE_ROUTINE = 1418
|
||||
BINLOG_CREATE_ROUTINE_NEED_SUPER = 1419
|
||||
STMT_HAS_NO_OPEN_CURSOR = 1421
|
||||
COMMIT_NOT_ALLOWED_IN_SF_OR_TRG = 1422
|
||||
NO_DEFAULT_FOR_VIEW_FIELD = 1423
|
||||
SP_NO_RECURSION = 1424
|
||||
TOO_BIG_SCALE = 1425
|
||||
TOO_BIG_PRECISION = 1426
|
||||
M_BIGGER_THAN_D = 1427
|
||||
WRONG_LOCK_OF_SYSTEM_TABLE = 1428
|
||||
CONNECT_TO_FOREIGN_DATA_SOURCE = 1429
|
||||
QUERY_ON_FOREIGN_DATA_SOURCE = 1430
|
||||
FOREIGN_DATA_SOURCE_DOESNT_EXIST = 1431
|
||||
FOREIGN_DATA_STRING_INVALID_CANT_CREATE = 1432
|
||||
FOREIGN_DATA_STRING_INVALID = 1433
|
||||
TRG_IN_WRONG_SCHEMA = 1435
|
||||
STACK_OVERRUN_NEED_MORE = 1436
|
||||
TOO_LONG_BODY = 1437
|
||||
WARN_CANT_DROP_DEFAULT_KEYCACHE = 1438
|
||||
TOO_BIG_DISPLAYWIDTH = 1439
|
||||
XAER_DUPID = 1440
|
||||
DATETIME_FUNCTION_OVERFLOW = 1441
|
||||
CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG = 1442
|
||||
VIEW_PREVENT_UPDATE = 1443
|
||||
PS_NO_RECURSION = 1444
|
||||
SP_CANT_SET_AUTOCOMMIT = 1445
|
||||
VIEW_FRM_NO_USER = 1447
|
||||
VIEW_OTHER_USER = 1448
|
||||
NO_SUCH_USER = 1449
|
||||
FORBID_SCHEMA_CHANGE = 1450
|
||||
ROW_IS_REFERENCED_2 = 1451
|
||||
NO_REFERENCED_ROW_2 = 1452
|
||||
SP_BAD_VAR_SHADOW = 1453
|
||||
TRG_NO_DEFINER = 1454
|
||||
OLD_FILE_FORMAT = 1455
|
||||
SP_RECURSION_LIMIT = 1456
|
||||
SP_WRONG_NAME = 1458
|
||||
TABLE_NEEDS_UPGRADE = 1459
|
||||
SP_NO_AGGREGATE = 1460
|
||||
MAX_PREPARED_STMT_COUNT_REACHED = 1461
|
||||
VIEW_RECURSIVE = 1462
|
||||
NON_GROUPING_FIELD_USED = 1463
|
||||
TABLE_CANT_HANDLE_SPKEYS = 1464
|
||||
NO_TRIGGERS_ON_SYSTEM_SCHEMA = 1465
|
||||
REMOVED_SPACES = 1466
|
||||
AUTOINC_READ_FAILED = 1467
|
||||
USERNAME = 1468
|
||||
HOSTNAME = 1469
|
||||
WRONG_STRING_LENGTH = 1470
|
||||
NON_INSERTABLE_TABLE = 1471
|
||||
ADMIN_WRONG_MRG_TABLE = 1472
|
||||
TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT = 1473
|
||||
NAME_BECOMES_EMPTY = 1474
|
||||
AMBIGUOUS_FIELD_TERM = 1475
|
||||
FOREIGN_SERVER_EXISTS = 1476
|
||||
FOREIGN_SERVER_DOESNT_EXIST = 1477
|
||||
ILLEGAL_HA_CREATE_OPTION = 1478
|
||||
PARTITION_REQUIRES_VALUES_ERROR = 1479
|
||||
PARTITION_WRONG_VALUES_ERROR = 1480
|
||||
PARTITION_MAXVALUE_ERROR = 1481
|
||||
PARTITION_WRONG_NO_PART_ERROR = 1484
|
||||
PARTITION_WRONG_NO_SUBPART_ERROR = 1485
|
||||
WRONG_EXPR_IN_PARTITION_FUNC_ERROR = 1486
|
||||
FIELD_NOT_FOUND_PART_ERROR = 1488
|
||||
INCONSISTENT_PARTITION_INFO_ERROR = 1490
|
||||
PARTITION_FUNC_NOT_ALLOWED_ERROR = 1491
|
||||
PARTITIONS_MUST_BE_DEFINED_ERROR = 1492
|
||||
RANGE_NOT_INCREASING_ERROR = 1493
|
||||
INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR = 1494
|
||||
MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR = 1495
|
||||
PARTITION_ENTRY_ERROR = 1496
|
||||
MIX_HANDLER_ERROR = 1497
|
||||
PARTITION_NOT_DEFINED_ERROR = 1498
|
||||
TOO_MANY_PARTITIONS_ERROR = 1499
|
||||
SUBPARTITION_ERROR = 1500
|
||||
CANT_CREATE_HANDLER_FILE = 1501
|
||||
BLOB_FIELD_IN_PART_FUNC_ERROR = 1502
|
||||
UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF = 1503
|
||||
NO_PARTS_ERROR = 1504
|
||||
PARTITION_MGMT_ON_NONPARTITIONED = 1505
|
||||
FOREIGN_KEY_ON_PARTITIONED = 1506
|
||||
DROP_PARTITION_NON_EXISTENT = 1507
|
||||
DROP_LAST_PARTITION = 1508
|
||||
COALESCE_ONLY_ON_HASH_PARTITION = 1509
|
||||
REORG_HASH_ONLY_ON_SAME_NO = 1510
|
||||
REORG_NO_PARAM_ERROR = 1511
|
||||
ONLY_ON_RANGE_LIST_PARTITION = 1512
|
||||
ADD_PARTITION_SUBPART_ERROR = 1513
|
||||
ADD_PARTITION_NO_NEW_PARTITION = 1514
|
||||
COALESCE_PARTITION_NO_PARTITION = 1515
|
||||
REORG_PARTITION_NOT_EXIST = 1516
|
||||
SAME_NAME_PARTITION = 1517
|
||||
NO_BINLOG_ERROR = 1518
|
||||
CONSECUTIVE_REORG_PARTITIONS = 1519
|
||||
REORG_OUTSIDE_RANGE = 1520
|
||||
PARTITION_FUNCTION_FAILURE = 1521
|
||||
LIMITED_PART_RANGE = 1523
|
||||
PLUGIN_IS_NOT_LOADED = 1524
|
||||
WRONG_VALUE = 1525
|
||||
NO_PARTITION_FOR_GIVEN_VALUE = 1526
|
||||
FILEGROUP_OPTION_ONLY_ONCE = 1527
|
||||
CREATE_FILEGROUP_FAILED = 1528
|
||||
DROP_FILEGROUP_FAILED = 1529
|
||||
TABLESPACE_AUTO_EXTEND_ERROR = 1530
|
||||
WRONG_SIZE_NUMBER = 1531
|
||||
SIZE_OVERFLOW_ERROR = 1532
|
||||
ALTER_FILEGROUP_FAILED = 1533
|
||||
BINLOG_ROW_LOGGING_FAILED = 1534
|
||||
EVENT_ALREADY_EXISTS = 1537
|
||||
EVENT_DOES_NOT_EXIST = 1539
|
||||
EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG = 1542
|
||||
EVENT_ENDS_BEFORE_STARTS = 1543
|
||||
EVENT_EXEC_TIME_IN_THE_PAST = 1544
|
||||
EVENT_SAME_NAME = 1551
|
||||
DROP_INDEX_FK = 1553
|
||||
WARN_DEPRECATED_SYNTAX_WITH_VER = 1554
|
||||
CANT_LOCK_LOG_TABLE = 1556
|
||||
FOREIGN_DUPLICATE_KEY_OLD_UNUSED = 1557
|
||||
COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE = 1558
|
||||
TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR = 1559
|
||||
STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT = 1560
|
||||
PARTITION_NO_TEMPORARY = 1562
|
||||
PARTITION_CONST_DOMAIN_ERROR = 1563
|
||||
PARTITION_FUNCTION_IS_NOT_ALLOWED = 1564
|
||||
NULL_IN_VALUES_LESS_THAN = 1566
|
||||
WRONG_PARTITION_NAME = 1567
|
||||
CANT_CHANGE_TX_CHARACTERISTICS = 1568
|
||||
DUP_ENTRY_AUTOINCREMENT_CASE = 1569
|
||||
EVENT_SET_VAR_ERROR = 1571
|
||||
PARTITION_MERGE_ERROR = 1572
|
||||
BASE64_DECODE_ERROR = 1575
|
||||
EVENT_RECURSION_FORBIDDEN = 1576
|
||||
ONLY_INTEGERS_ALLOWED = 1578
|
||||
UNSUPORTED_LOG_ENGINE = 1579
|
||||
BAD_LOG_STATEMENT = 1580
|
||||
CANT_RENAME_LOG_TABLE = 1581
|
||||
WRONG_PARAMCOUNT_TO_NATIVE_FCT = 1582
|
||||
WRONG_PARAMETERS_TO_NATIVE_FCT = 1583
|
||||
WRONG_PARAMETERS_TO_STORED_FCT = 1584
|
||||
NATIVE_FCT_NAME_COLLISION = 1585
|
||||
DUP_ENTRY_WITH_KEY_NAME = 1586
|
||||
BINLOG_PURGE_EMFILE = 1587
|
||||
EVENT_CANNOT_CREATE_IN_THE_PAST = 1588
|
||||
EVENT_CANNOT_ALTER_IN_THE_PAST = 1589
|
||||
NO_PARTITION_FOR_GIVEN_VALUE_SILENT = 1591
|
||||
BINLOG_UNSAFE_STATEMENT = 1592
|
||||
BINLOG_FATAL_ERROR = 1593
|
||||
BINLOG_LOGGING_IMPOSSIBLE = 1598
|
||||
VIEW_NO_CREATION_CTX = 1599
|
||||
VIEW_INVALID_CREATION_CTX = 1600
|
||||
TRG_CORRUPTED_FILE = 1602
|
||||
TRG_NO_CREATION_CTX = 1603
|
||||
TRG_INVALID_CREATION_CTX = 1604
|
||||
EVENT_INVALID_CREATION_CTX = 1605
|
||||
TRG_CANT_OPEN_TABLE = 1606
|
||||
NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT = 1609
|
||||
SLAVE_CORRUPT_EVENT = 1610
|
||||
LOG_PURGE_NO_FILE = 1612
|
||||
XA_RBTIMEOUT = 1613
|
||||
XA_RBDEADLOCK = 1614
|
||||
NEED_REPREPARE = 1615
|
||||
WARN_NO_MASTER_INFO = 1617
|
||||
WARN_OPTION_IGNORED = 1618
|
||||
PLUGIN_DELETE_BUILTIN = 1619
|
||||
WARN_PLUGIN_BUSY = 1620
|
||||
VARIABLE_IS_READONLY = 1621
|
||||
WARN_ENGINE_TRANSACTION_ROLLBACK = 1622
|
||||
SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE = 1624
|
||||
NDB_REPLICATION_SCHEMA_ERROR = 1625
|
||||
CONFLICT_FN_PARSE_ERROR = 1626
|
||||
EXCEPTIONS_WRITE_ERROR = 1627
|
||||
TOO_LONG_TABLE_COMMENT = 1628
|
||||
TOO_LONG_FIELD_COMMENT = 1629
|
||||
FUNC_INEXISTENT_NAME_COLLISION = 1630
|
||||
DATABASE_NAME = 1631
|
||||
TABLE_NAME = 1632
|
||||
PARTITION_NAME = 1633
|
||||
SUBPARTITION_NAME = 1634
|
||||
TEMPORARY_NAME = 1635
|
||||
RENAMED_NAME = 1636
|
||||
TOO_MANY_CONCURRENT_TRXS = 1637
|
||||
WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED = 1638
|
||||
DEBUG_SYNC_TIMEOUT = 1639
|
||||
DEBUG_SYNC_HIT_LIMIT = 1640
|
||||
DUP_SIGNAL_SET = 1641
|
||||
SIGNAL_WARN = 1642
|
||||
SIGNAL_NOT_FOUND = 1643
|
||||
SIGNAL_EXCEPTION = 1644
|
||||
RESIGNAL_WITHOUT_ACTIVE_HANDLER = 1645
|
||||
SIGNAL_BAD_CONDITION_TYPE = 1646
|
||||
WARN_COND_ITEM_TRUNCATED = 1647
|
||||
COND_ITEM_TOO_LONG = 1648
|
||||
UNKNOWN_LOCALE = 1649
|
||||
SLAVE_IGNORE_SERVER_IDS = 1650
|
||||
SAME_NAME_PARTITION_FIELD = 1652
|
||||
PARTITION_COLUMN_LIST_ERROR = 1653
|
||||
WRONG_TYPE_COLUMN_VALUE_ERROR = 1654
|
||||
TOO_MANY_PARTITION_FUNC_FIELDS_ERROR = 1655
|
||||
MAXVALUE_IN_VALUES_IN = 1656
|
||||
TOO_MANY_VALUES_ERROR = 1657
|
||||
ROW_SINGLE_PARTITION_FIELD_ERROR = 1658
|
||||
FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD = 1659
|
||||
PARTITION_FIELDS_TOO_LONG = 1660
|
||||
BINLOG_ROW_ENGINE_AND_STMT_ENGINE = 1661
|
||||
BINLOG_ROW_MODE_AND_STMT_ENGINE = 1662
|
||||
BINLOG_UNSAFE_AND_STMT_ENGINE = 1663
|
||||
BINLOG_ROW_INJECTION_AND_STMT_ENGINE = 1664
|
||||
BINLOG_STMT_MODE_AND_ROW_ENGINE = 1665
|
||||
BINLOG_ROW_INJECTION_AND_STMT_MODE = 1666
|
||||
BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE = 1667
|
||||
BINLOG_UNSAFE_LIMIT = 1668
|
||||
BINLOG_UNSAFE_SYSTEM_TABLE = 1670
|
||||
BINLOG_UNSAFE_AUTOINC_COLUMNS = 1671
|
||||
BINLOG_UNSAFE_UDF = 1672
|
||||
BINLOG_UNSAFE_SYSTEM_VARIABLE = 1673
|
||||
BINLOG_UNSAFE_SYSTEM_FUNCTION = 1674
|
||||
BINLOG_UNSAFE_NONTRANS_AFTER_TRANS = 1675
|
||||
MESSAGE_AND_STATEMENT = 1676
|
||||
SLAVE_CANT_CREATE_CONVERSION = 1678
|
||||
INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT = 1679
|
||||
PATH_LENGTH = 1680
|
||||
WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT = 1681
|
||||
WRONG_NATIVE_TABLE_STRUCTURE = 1682
|
||||
WRONG_PERFSCHEMA_USAGE = 1683
|
||||
WARN_I_S_SKIPPED_TABLE = 1684
|
||||
INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT = 1685
|
||||
STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_DIRECT = 1686
|
||||
SPATIAL_MUST_HAVE_GEOM_COL = 1687
|
||||
TOO_LONG_INDEX_COMMENT = 1688
|
||||
LOCK_ABORTED = 1689
|
||||
DATA_OUT_OF_RANGE = 1690
|
||||
WRONG_SPVAR_TYPE_IN_LIMIT = 1691
|
||||
BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE = 1692
|
||||
BINLOG_UNSAFE_MIXED_STATEMENT = 1693
|
||||
INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN = 1694
|
||||
STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN = 1695
|
||||
FAILED_READ_FROM_PAR_FILE = 1696
|
||||
VALUES_IS_NOT_INT_TYPE_ERROR = 1697
|
||||
ACCESS_DENIED_NO_PASSWORD_ERROR = 1698
|
||||
SET_PASSWORD_AUTH_PLUGIN = 1699
|
||||
TRUNCATE_ILLEGAL_FK = 1701
|
||||
PLUGIN_IS_PERMANENT = 1702
|
||||
SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN = 1703
|
||||
SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX = 1704
|
||||
STMT_CACHE_FULL = 1705
|
||||
MULTI_UPDATE_KEY_CONFLICT = 1706
|
||||
TABLE_NEEDS_REBUILD = 1707
|
||||
WARN_OPTION_BELOW_LIMIT = 1708
|
||||
INDEX_COLUMN_TOO_LONG = 1709
|
||||
ERROR_IN_TRIGGER_BODY = 1710
|
||||
ERROR_IN_UNKNOWN_TRIGGER_BODY = 1711
|
||||
INDEX_CORRUPT = 1712
|
||||
UNDO_RECORD_TOO_BIG = 1713
|
||||
BINLOG_UNSAFE_INSERT_IGNORE_SELECT = 1714
|
||||
BINLOG_UNSAFE_INSERT_SELECT_UPDATE = 1715
|
||||
BINLOG_UNSAFE_REPLACE_SELECT = 1716
|
||||
BINLOG_UNSAFE_CREATE_IGNORE_SELECT = 1717
|
||||
BINLOG_UNSAFE_CREATE_REPLACE_SELECT = 1718
|
||||
BINLOG_UNSAFE_UPDATE_IGNORE = 1719
|
||||
PLUGIN_NO_UNINSTALL = 1720
|
||||
PLUGIN_NO_INSTALL = 1721
|
||||
BINLOG_UNSAFE_WRITE_AUTOINC_SELECT = 1722
|
||||
BINLOG_UNSAFE_CREATE_SELECT_AUTOINC = 1723
|
||||
BINLOG_UNSAFE_INSERT_TWO_KEYS = 1724
|
||||
TABLE_IN_FK_CHECK = 1725
|
||||
UNSUPPORTED_ENGINE = 1726
|
||||
BINLOG_UNSAFE_AUTOINC_NOT_FIRST = 1727
|
||||
CANNOT_LOAD_FROM_TABLE_V2 = 1728
|
||||
MASTER_DELAY_VALUE_OUT_OF_RANGE = 1729
|
||||
ONLY_FD_AND_RBR_EVENTS_ALLOWED_IN_BINLOG_STATEMENT = 1730
|
||||
PARTITION_EXCHANGE_DIFFERENT_OPTION = 1731
|
||||
PARTITION_EXCHANGE_PART_TABLE = 1732
|
||||
PARTITION_EXCHANGE_TEMP_TABLE = 1733
|
||||
PARTITION_INSTEAD_OF_SUBPARTITION = 1734
|
||||
UNKNOWN_PARTITION = 1735
|
||||
TABLES_DIFFERENT_METADATA = 1736
|
||||
ROW_DOES_NOT_MATCH_PARTITION = 1737
|
||||
BINLOG_CACHE_SIZE_GREATER_THAN_MAX = 1738
|
||||
WARN_INDEX_NOT_APPLICABLE = 1739
|
||||
PARTITION_EXCHANGE_FOREIGN_KEY = 1740
|
||||
RPL_INFO_DATA_TOO_LONG = 1742
|
||||
BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX = 1745
|
||||
CANT_UPDATE_TABLE_IN_CREATE_TABLE_SELECT = 1746
|
||||
PARTITION_CLAUSE_ON_NONPARTITIONED = 1747
|
||||
ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET = 1748
|
||||
CHANGE_RPL_INFO_REPOSITORY_FAILURE = 1750
|
||||
WARNING_NOT_COMPLETE_ROLLBACK_WITH_CREATED_TEMP_TABLE = 1751
|
||||
WARNING_NOT_COMPLETE_ROLLBACK_WITH_DROPPED_TEMP_TABLE = 1752
|
||||
MTS_FEATURE_IS_NOT_SUPPORTED = 1753
|
||||
MTS_UPDATED_DBS_GREATER_MAX = 1754
|
||||
MTS_CANT_PARALLEL = 1755
|
||||
MTS_INCONSISTENT_DATA = 1756
|
||||
FULLTEXT_NOT_SUPPORTED_WITH_PARTITIONING = 1757
|
||||
DA_INVALID_CONDITION_NUMBER = 1758
|
||||
INSECURE_PLAIN_TEXT = 1759
|
||||
INSECURE_CHANGE_MASTER = 1760
|
||||
FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO = 1761
|
||||
FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO = 1762
|
||||
SQLTHREAD_WITH_SECURE_SLAVE = 1763
|
||||
TABLE_HAS_NO_FT = 1764
|
||||
VARIABLE_NOT_SETTABLE_IN_SF_OR_TRIGGER = 1765
|
||||
VARIABLE_NOT_SETTABLE_IN_TRANSACTION = 1766
|
||||
SET_STATEMENT_CANNOT_INVOKE_FUNCTION = 1769
|
||||
GTID_NEXT_CANT_BE_AUTOMATIC_IF_GTID_NEXT_LIST_IS_NON_NULL = 1770
|
||||
MALFORMED_GTID_SET_SPECIFICATION = 1772
|
||||
MALFORMED_GTID_SET_ENCODING = 1773
|
||||
MALFORMED_GTID_SPECIFICATION = 1774
|
||||
GNO_EXHAUSTED = 1775
|
||||
BAD_SLAVE_AUTO_POSITION = 1776
|
||||
AUTO_POSITION_REQUIRES_GTID_MODE_NOT_OFF = 1777
|
||||
CANT_DO_IMPLICIT_COMMIT_IN_TRX_WHEN_GTID_NEXT_IS_SET = 1778
|
||||
GTID_MODE_ON_REQUIRES_ENFORCE_GTID_CONSISTENCY_ON = 1779
|
||||
CANT_SET_GTID_NEXT_TO_GTID_WHEN_GTID_MODE_IS_OFF = 1781
|
||||
CANT_SET_GTID_NEXT_TO_ANONYMOUS_WHEN_GTID_MODE_IS_ON = 1782
|
||||
CANT_SET_GTID_NEXT_LIST_TO_NON_NULL_WHEN_GTID_MODE_IS_OFF = 1783
|
||||
GTID_UNSAFE_NON_TRANSACTIONAL_TABLE = 1785
|
||||
GTID_UNSAFE_CREATE_SELECT = 1786
|
||||
GTID_UNSAFE_CREATE_DROP_TEMPORARY_TABLE_IN_TRANSACTION = 1787
|
||||
GTID_MODE_CAN_ONLY_CHANGE_ONE_STEP_AT_A_TIME = 1788
|
||||
MASTER_HAS_PURGED_REQUIRED_GTIDS = 1789
|
||||
CANT_SET_GTID_NEXT_WHEN_OWNING_GTID = 1790
|
||||
UNKNOWN_EXPLAIN_FORMAT = 1791
|
||||
CANT_EXECUTE_IN_READ_ONLY_TRANSACTION = 1792
|
||||
TOO_LONG_TABLE_PARTITION_COMMENT = 1793
|
||||
SLAVE_CONFIGURATION = 1794
|
||||
INNODB_FT_LIMIT = 1795
|
||||
INNODB_NO_FT_TEMP_TABLE = 1796
|
||||
INNODB_FT_WRONG_DOCID_COLUMN = 1797
|
||||
INNODB_FT_WRONG_DOCID_INDEX = 1798
|
||||
INNODB_ONLINE_LOG_TOO_BIG = 1799
|
||||
UNKNOWN_ALTER_ALGORITHM = 1800
|
||||
UNKNOWN_ALTER_LOCK = 1801
|
||||
MTS_CHANGE_MASTER_CANT_RUN_WITH_GAPS = 1802
|
||||
MTS_RECOVERY_FAILURE = 1803
|
||||
MTS_RESET_WORKERS = 1804
|
||||
COL_COUNT_DOESNT_MATCH_CORRUPTED_V2 = 1805
|
||||
SLAVE_SILENT_RETRY_TRANSACTION = 1806
|
||||
DISCARD_FK_CHECKS_RUNNING = 1807
|
||||
TABLE_SCHEMA_MISMATCH = 1808
|
||||
TABLE_IN_SYSTEM_TABLESPACE = 1809
|
||||
IO_READ_ERROR = 1810
|
||||
IO_WRITE_ERROR = 1811
|
||||
TABLESPACE_MISSING = 1812
|
||||
TABLESPACE_EXISTS = 1813
|
||||
TABLESPACE_DISCARDED = 1814
|
||||
INTERNAL_ERROR = 1815
|
||||
INNODB_IMPORT_ERROR = 1816
|
||||
INNODB_INDEX_CORRUPT = 1817
|
||||
INVALID_YEAR_COLUMN_LENGTH = 1818
|
||||
NOT_VALID_PASSWORD = 1819
|
||||
MUST_CHANGE_PASSWORD = 1820
|
||||
FK_NO_INDEX_CHILD = 1821
|
||||
FK_NO_INDEX_PARENT = 1822
|
||||
FK_FAIL_ADD_SYSTEM = 1823
|
||||
FK_CANNOT_OPEN_PARENT = 1824
|
||||
FK_INCORRECT_OPTION = 1825
|
||||
FK_DUP_NAME = 1826
|
||||
PASSWORD_FORMAT = 1827
|
||||
FK_COLUMN_CANNOT_DROP = 1828
|
||||
FK_COLUMN_CANNOT_DROP_CHILD = 1829
|
||||
FK_COLUMN_NOT_NULL = 1830
|
||||
DUP_INDEX = 1831
|
||||
FK_COLUMN_CANNOT_CHANGE = 1832
|
||||
FK_COLUMN_CANNOT_CHANGE_CHILD = 1833
|
||||
MALFORMED_PACKET = 1835
|
||||
READ_ONLY_MODE = 1836
|
||||
GTID_NEXT_TYPE_UNDEFINED_GTID = 1837
|
||||
VARIABLE_NOT_SETTABLE_IN_SP = 1838
|
||||
CANT_SET_GTID_PURGED_WHEN_GTID_EXECUTED_IS_NOT_EMPTY = 1840
|
||||
CANT_SET_GTID_PURGED_WHEN_OWNED_GTIDS_IS_NOT_EMPTY = 1841
|
||||
GTID_PURGED_WAS_CHANGED = 1842
|
||||
GTID_EXECUTED_WAS_CHANGED = 1843
|
||||
BINLOG_STMT_MODE_AND_NO_REPL_TABLES = 1844
|
||||
ALTER_OPERATION_NOT_SUPPORTED = 1845
|
||||
ALTER_OPERATION_NOT_SUPPORTED_REASON = 1846
|
||||
ALTER_OPERATION_NOT_SUPPORTED_REASON_COPY = 1847
|
||||
ALTER_OPERATION_NOT_SUPPORTED_REASON_PARTITION = 1848
|
||||
ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_RENAME = 1849
|
||||
ALTER_OPERATION_NOT_SUPPORTED_REASON_COLUMN_TYPE = 1850
|
||||
ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_CHECK = 1851
|
||||
ALTER_OPERATION_NOT_SUPPORTED_REASON_NOPK = 1853
|
||||
ALTER_OPERATION_NOT_SUPPORTED_REASON_AUTOINC = 1854
|
||||
ALTER_OPERATION_NOT_SUPPORTED_REASON_HIDDEN_FTS = 1855
|
||||
ALTER_OPERATION_NOT_SUPPORTED_REASON_CHANGE_FTS = 1856
|
||||
ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS = 1857
|
||||
SQL_SLAVE_SKIP_COUNTER_NOT_SETTABLE_IN_GTID_MODE = 1858
|
||||
DUP_UNKNOWN_IN_INDEX = 1859
|
||||
IDENT_CAUSES_TOO_LONG_PATH = 1860
|
||||
ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL = 1861
|
||||
MUST_CHANGE_PASSWORD_LOGIN = 1862
|
||||
ROW_IN_WRONG_PARTITION = 1863
|
||||
MTS_EVENT_BIGGER_PENDING_JOBS_SIZE_MAX = 1864
|
||||
BINLOG_LOGICAL_CORRUPTION = 1866
|
||||
WARN_PURGE_LOG_IN_USE = 1867
|
||||
WARN_PURGE_LOG_IS_ACTIVE = 1868
|
||||
AUTO_INCREMENT_CONFLICT = 1869
|
||||
WARN_ON_BLOCKHOLE_IN_RBR = 1870
|
||||
SLAVE_MI_INIT_REPOSITORY = 1871
|
||||
SLAVE_RLI_INIT_REPOSITORY = 1872
|
||||
ACCESS_DENIED_CHANGE_USER_ERROR = 1873
|
||||
INNODB_READ_ONLY = 1874
|
||||
STOP_SLAVE_SQL_THREAD_TIMEOUT = 1875
|
||||
STOP_SLAVE_IO_THREAD_TIMEOUT = 1876
|
||||
TABLE_CORRUPT = 1877
|
||||
TEMP_FILE_WRITE_FAILURE = 1878
|
||||
INNODB_FT_AUX_NOT_HEX_ID = 1879
|
||||
OLD_TEMPORALS_UPGRADED = 1880
|
||||
INNODB_FORCED_RECOVERY = 1881
|
||||
AES_INVALID_IV = 1882
|
||||
PLUGIN_CANNOT_BE_UNINSTALLED = 1883
|
||||
GTID_UNSAFE_BINLOG_SPLITTABLE_STATEMENT_AND_ASSIGNED_GTID = 1884
|
||||
SLAVE_HAS_MORE_GTIDS_THAN_MASTER = 1885
|
||||
MISSING_KEY = 1886
|
||||
ERROR_LAST = 1973
|
40
venv/Lib/site-packages/MySQLdb/constants/FIELD_TYPE.py
Normal file
40
venv/Lib/site-packages/MySQLdb/constants/FIELD_TYPE.py
Normal file
@ -0,0 +1,40 @@
|
||||
"""MySQL FIELD_TYPE Constants
|
||||
|
||||
These constants represent the various column (field) types that are
|
||||
supported by MySQL.
|
||||
"""
|
||||
|
||||
DECIMAL = 0
|
||||
TINY = 1
|
||||
SHORT = 2
|
||||
LONG = 3
|
||||
FLOAT = 4
|
||||
DOUBLE = 5
|
||||
NULL = 6
|
||||
TIMESTAMP = 7
|
||||
LONGLONG = 8
|
||||
INT24 = 9
|
||||
DATE = 10
|
||||
TIME = 11
|
||||
DATETIME = 12
|
||||
YEAR = 13
|
||||
# NEWDATE = 14 # Internal to MySQL.
|
||||
VARCHAR = 15
|
||||
BIT = 16
|
||||
# TIMESTAMP2 = 17
|
||||
# DATETIME2 = 18
|
||||
# TIME2 = 19
|
||||
JSON = 245
|
||||
NEWDECIMAL = 246
|
||||
ENUM = 247
|
||||
SET = 248
|
||||
TINY_BLOB = 249
|
||||
MEDIUM_BLOB = 250
|
||||
LONG_BLOB = 251
|
||||
BLOB = 252
|
||||
VAR_STRING = 253
|
||||
STRING = 254
|
||||
GEOMETRY = 255
|
||||
|
||||
CHAR = TINY
|
||||
INTERVAL = ENUM
|
23
venv/Lib/site-packages/MySQLdb/constants/FLAG.py
Normal file
23
venv/Lib/site-packages/MySQLdb/constants/FLAG.py
Normal file
@ -0,0 +1,23 @@
|
||||
"""MySQL FLAG Constants
|
||||
|
||||
These flags are used along with the FIELD_TYPE to indicate various
|
||||
properties of columns in a result set.
|
||||
|
||||
"""
|
||||
|
||||
NOT_NULL = 1
|
||||
PRI_KEY = 2
|
||||
UNIQUE_KEY = 4
|
||||
MULTIPLE_KEY = 8
|
||||
BLOB = 16
|
||||
UNSIGNED = 32
|
||||
ZEROFILL = 64
|
||||
BINARY = 128
|
||||
ENUM = 256
|
||||
AUTO_INCREMENT = 512
|
||||
TIMESTAMP = 1024
|
||||
SET = 2048
|
||||
NUM = 32768
|
||||
PART_KEY = 16384
|
||||
GROUP = 32768
|
||||
UNIQUE = 65536
|
1
venv/Lib/site-packages/MySQLdb/constants/__init__.py
Normal file
1
venv/Lib/site-packages/MySQLdb/constants/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
__all__ = ["CR", "FIELD_TYPE", "CLIENT", "ER", "FLAG"]
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user