first commit

This commit is contained in:
hukdoesn
2025-06-12 16:48:37 +08:00
commit 1bb6f0b9a8
44 changed files with 8808 additions and 0 deletions

View File

14
backend/backend/asgi.py Normal file
View File

@@ -0,0 +1,14 @@
"""
ASGI config for backend 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/4.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
application = get_asgi_application()

199
backend/backend/settings.py Normal file
View File

@@ -0,0 +1,199 @@
from pathlib import Path
import pymysql
import logging
BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = 'django-insecure-5z@^6hpk^zxffj_7)&l3pvww8@ky3qsai4)m!vcog!8#=@a3&%'
DEBUG = True
ALLOWED_HOSTS = ['*'] # 允许所有主机访问
# CORS设置
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_ALL_ORIGINS = True # 允许所有来源
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'corsheaders', # 添加 cors-headers
'apps',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'backend.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'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 = 'backend.wsgi.application'
pymysql.install_as_MySQLdb()
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'OPTIONS': {
'read_default_file': str(BASE_DIR / 'conf' / 'config.txt'),
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
}
}
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 = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False # 修改为 True使用时区功能
# 日志配置
LOG_DIR = BASE_DIR / 'logs'
LOG_DIR.mkdir(exist_ok=True) # 确保日志目录存在
class BuildLogFilter(logging.Filter):
def filter(self, record):
# 如果是构建日志,使用简单格式
if getattr(record, 'from_builder', False):
return True
# 其他日志使用默认格式
return True
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'build_log_filter': {
'()': 'backend.settings.BuildLogFilter',
},
'non_build_log_filter': {
'()': lambda: type('Filter', (logging.Filter,), {
'filter': lambda self, record: not getattr(record, 'from_builder', False)
})(),
},
},
'formatters': {
'verbose': {
'format': '[{asctime}] {levelname} [{name}:{lineno}] {message}',
'style': '{',
'datefmt': '%Y-%m-%d %H:%M:%S'
},
'simple': {
'format': '{message}',
'style': '{'
},
'console_with_time': {
'format': '[{asctime}] {levelname} {message}',
'style': '{',
'datefmt': '%Y-%m-%d %H:%M:%S'
},
},
'handlers': {
'console_build': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'simple',
'filters': ['build_log_filter'],
},
'console_normal': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'console_with_time',
'filters': ['non_build_log_filter'],
},
'file': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': str(LOG_DIR / 'django.log'),
'maxBytes': 1024 * 1024 * 5, # 5MB
'backupCount': 5,
'formatter': 'verbose',
},
'error_file': {
'level': 'ERROR',
'class': 'logging.handlers.RotatingFileHandler',
'filename': str(LOG_DIR / 'error.log'),
'maxBytes': 1024 * 1024 * 5, # 5MB
'backupCount': 5,
'formatter': 'verbose',
}
},
'loggers': {
'django': {
'handlers': ['console_normal', 'file'],
'level': 'INFO',
'propagate': True,
},
'django.request': {
'handlers': ['error_file'],
'level': 'ERROR',
'propagate': False,
},
'django.server': {
'handlers': ['console_normal', 'file'],
'level': 'INFO',
'propagate': False,
},
'apps': {
'handlers': ['console_build', 'console_normal', 'file', 'error_file'],
'level': 'DEBUG',
'propagate': False, # 设置为False以避免重复记录
},
},
'root': {
'handlers': ['console_normal', 'file', 'error_file'],
'level': 'INFO',
},
}
STATIC_URL = 'static/'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# 构建相关配置
#BUILD_ROOT = Path('/data/liteops/build') # 修改为指定目录
BUILD_ROOT = Path('/Users/huk/Downloads/data')
BUILD_ROOT.mkdir(exist_ok=True, parents=True) # 确保目录存在,包括父目录

67
backend/backend/urls.py Normal file
View File

@@ -0,0 +1,67 @@
from django.contrib import admin
from django.urls import path
from apps.views.login import login, logout
from apps.views.project import ProjectView, ProjectServiceView
from apps.views.environment import EnvironmentView, EnvironmentTypeView
from apps.views.credentials import CredentialView
from apps.views.gitlab import GitlabBranchView, GitlabCommitView
from apps.views.build import BuildTaskView, BuildExecuteView
from apps.views.build_history import BuildHistoryView, BuildLogView, BuildStageLogView
from apps.views.build_sse import BuildLogSSEView
from apps.views.notification import NotificationRobotView, NotificationTestView
from apps.views.user import UserView, UserProfileView
from apps.views.role import RoleView, UserPermissionView
from apps.views.logs import login_logs_list, login_log_detail
from apps.views.dashboard import DashboardStatsView, BuildTrendView, BuildDetailView, RecentBuildsView, ProjectDistributionView
from apps.views.security import SecurityConfigView
urlpatterns = [
path('admin/', admin.site.urls),
path('api/login/', login, name='login'),
path('api/logout/', logout, name='logout'),
path('api/projects/', ProjectView.as_view(), name='projects'),
path('api/project-services/', ProjectServiceView.as_view(), name='project-services'),
path('api/environments/', EnvironmentView.as_view(), name='environments'),
path('api/environments/types/', EnvironmentTypeView.as_view(), name='environment-types'),
path('api/credentials/', CredentialView.as_view(), name='credentials'),
path('api/gitlab/branches/', GitlabBranchView.as_view(), name='gitlab-branches'),
path('api/gitlab/commits/', GitlabCommitView.as_view(), name='gitlab-commits'),
path('api/build/tasks/', BuildTaskView.as_view(), name='build-tasks'),
path('api/build/tasks/<str:task_id>/', BuildTaskView.as_view(), name='build-task-detail'),
path('api/build/tasks/build', BuildExecuteView.as_view(), name='build-execute'),
# 构建历史相关路由
path('api/build/history/', BuildHistoryView.as_view(), name='build-history'),
path('api/build/history/log/<str:history_id>/', BuildLogView.as_view(), name='build-log'),
path('api/build/history/log/<str:history_id>/download/', BuildLogView.as_view(), name='build-log-download'),
path('api/build/history/stage-log/<str:history_id>/<str:stage_name>/', BuildStageLogView.as_view(), name='build-stage-log'),
# SSE构建日志流
path('api/build/logs/stream/<str:task_id>/<str:build_number>/', BuildLogSSEView.as_view(), name='build-log-sse'),
# 通知机器人相关路由
path('api/notification/robots/', NotificationRobotView.as_view(), name='notification-robots'),
path('api/notification/robots/test/', NotificationTestView.as_view(), name='notification-robot-test'),
path('api/notification/robots/<str:robot_id>/', NotificationRobotView.as_view(), name='notification-robot-detail'),
# 用户管理相关路由
path('api/users/', UserView.as_view(), name='users'),
path('api/roles/', RoleView.as_view(), name='roles'),
path('api/user/permissions/', UserPermissionView.as_view(), name='user-permissions'),
path('api/user/profile/', UserProfileView.as_view(), name='user-profile'),
# 登录日志相关路由
path('api/logs/login/', login_logs_list, name='login-logs'),
path('api/logs/login/<str:log_id>/', login_log_detail, name='login-log-detail'),
# 首页仪表盘相关路由
path('api/dashboard/stats/', DashboardStatsView.as_view(), name='dashboard-stats'),
path('api/dashboard/build-trend/', BuildTrendView.as_view(), name='build-trend'),
path('api/dashboard/build-detail/', BuildDetailView.as_view(), name='build-detail'),
path('api/dashboard/recent-builds/', RecentBuildsView.as_view(), name='recent-builds'),
path('api/dashboard/project-distribution/', ProjectDistributionView.as_view(), name='project-distribution'),
# 安全配置相关路由
path('api/system/security/', SecurityConfigView.as_view(), name='security-config'),
]

7
backend/backend/wsgi.py Normal file
View File

@@ -0,0 +1,7 @@
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
application = get_wsgi_application()