1
0
forked from erp-dev/erp
Files
erpnew/flower/urls.py

166 lines
5.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
URL configuration for flower project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.2/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.contrib.auth import get_user_model
from django.contrib.auth.models import update_last_login
from django.core.exceptions import ObjectDoesNotExist
from django.urls import path, include
from rest_framework import status
from rest_framework.response import Response
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
from sse.views import create_sse_event, push_test_event, get_sse_status, shutdown_sse
from rest_framework_simplejwt.settings import api_settings
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
from basic_info.models import EmployeeStatusEnum
from flower.app_version import AppVersionView
from flower.error_code import AuthErrorCode
from flower.error_code_views import ErrorCodeListView
# 自定义后台站点标题simpleui 也会读取)
admin.site.site_header = "宇问科技"
admin.site.site_title = "宇问科技"
admin.site.index_title = "管理后台"
def login_error_response(error_code: AuthErrorCode, code: str, message: str, http_status: int):
return Response(
{
'error_code': int(error_code),
'code': code,
'message': message,
'detail': message,
},
status=http_status,
)
class CustomTokenObtainPairView(TokenObtainPairView):
"""自定义登录视图"""
def post(self, request, *args, **kwargs):
data = request.data or {}
username = (data.get('username') or '').strip()
password = data.get('password')
if not username and not password:
return login_error_response(
AuthErrorCode.MISSING_CREDENTIALS,
'missing_credentials',
'请输入用户名和密码',
status.HTTP_400_BAD_REQUEST,
)
if not username:
return login_error_response(
AuthErrorCode.MISSING_USERNAME,
'missing_username',
'请输入用户名',
status.HTTP_400_BAD_REQUEST,
)
if not password:
return login_error_response(
AuthErrorCode.MISSING_PASSWORD,
'missing_password',
'请输入密码',
status.HTTP_400_BAD_REQUEST,
)
UserModel = get_user_model()
try:
user = UserModel._default_manager.get_by_natural_key(username)
except UserModel.DoesNotExist:
return login_error_response(
AuthErrorCode.USER_NOT_FOUND,
'user_not_found',
'用户不存在',
status.HTTP_401_UNAUTHORIZED,
)
if not user.check_password(password):
return login_error_response(
AuthErrorCode.INVALID_PASSWORD,
'invalid_password',
'密码错误',
status.HTTP_401_UNAUTHORIZED,
)
if not user.is_active:
return login_error_response(
AuthErrorCode.USER_INACTIVE,
'user_inactive',
'该用户已被禁用',
status.HTTP_403_FORBIDDEN,
)
try:
employee = user.employee
except ObjectDoesNotExist:
return login_error_response(
AuthErrorCode.EMPLOYEE_NOT_BOUND,
'employee_not_bound',
'该用户未绑定员工身份',
status.HTTP_403_FORBIDDEN,
)
if employee.status != EmployeeStatusEnum.ACTIVE:
return login_error_response(
AuthErrorCode.EMPLOYEE_INACTIVE,
'employee_inactive',
'该员工已离职或停用',
status.HTTP_403_FORBIDDEN,
)
refresh = TokenObtainPairSerializer.get_token(user)
if api_settings.UPDATE_LAST_LOGIN:
update_last_login(None, user)
return Response(
{
'refresh': str(refresh),
'access': str(refresh.access_token),
},
status=status.HTTP_200_OK,
)
urlpatterns = [
# JWT 登录
path('api/auth/login/', CustomTokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/auth/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('api/error-codes/', ErrorCodeListView.as_view(), name='error_code_list'),
path('api/app-version/', AppVersionView.as_view(), name='app_version'),
# API 文档
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
path('api/docs/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
path('admin/', admin.site.urls),
path('api/v1/', include('api_v1.urls')),
path('api/v2/', include('api_v2.urls')),
path('api/core/', include('api_core.urls')),
path('api/backend/', include('api_man.urls')),
# sse 相关端点
path('sse/', create_sse_event, name='sse_event'),
path('sse/push/', push_test_event, name='push_sse_event'),
path('sse/status/', get_sse_status, name='sse_status'),
path('sse/shutdown/', shutdown_sse, name='shutdown_sse'),
]