Files
LiteOps/backend/apps/views/project.py
2025-06-12 16:48:37 +08:00

392 lines
14 KiB
Python

import json
import uuid
import hashlib
import logging
from django.http import JsonResponse
from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.db import transaction
from django.db.models import Q
from ..models import Project, User
from ..utils.auth import jwt_auth_required
from ..utils.permissions import get_user_permissions
logger = logging.getLogger('apps')
def generate_id():
"""生成唯一ID"""
return hashlib.sha256(str(uuid.uuid4()).encode()).hexdigest()[:32]
@method_decorator(csrf_exempt, name='dispatch')
class ProjectView(View):
@method_decorator(jwt_auth_required)
def get(self, request):
"""获取项目列表"""
try:
# 获取当前用户的权限信息
user_permissions = get_user_permissions(request.user_id)
data_permissions = user_permissions.get('data', {})
# 检查用户是否有项目查看权限
function_permissions = user_permissions.get('function', {})
project_permissions = function_permissions.get('project', [])
if 'view' not in project_permissions:
logger.warning(f'用户[{request.user_id}]没有项目查看权限')
return JsonResponse({
'code': 403,
'message': '没有权限查看项目'
}, status=403)
project_id = request.GET.get('project_id')
name = request.GET.get('name')
category = request.GET.get('category')
# 构建查询条件
query = Q()
if project_id:
query &= Q(project_id=project_id)
if name:
query &= Q(name__icontains=name) # 使用 icontains 进行不区分大小写的模糊查询
if category:
query &= Q(category=category)
# 应用项目权限过滤
project_scope = data_permissions.get('project_scope', 'all')
if project_scope == 'custom':
permitted_project_ids = data_permissions.get('project_ids', [])
if not permitted_project_ids:
# 如果设置了自定义项目权限但列表为空,意味着没有权限查看任何项目
logger.info(f'用户[{request.user_id}]没有权限查看任何项目')
return JsonResponse({
'code': 200,
'message': '获取项目列表成功',
'data': []
})
# 限制只能查看有权限的项目
query &= Q(project_id__in=permitted_project_ids)
# 使用查询条件过滤项目
projects = Project.objects.select_related('creator').filter(query)
project_list = []
for project in projects:
project_list.append({
'project_id': project.project_id,
'name': project.name,
'description': project.description,
'category': project.category,
'repository': project.repository,
'creator': {
'user_id': project.creator.user_id,
'username': project.creator.username,
'name': project.creator.name
},
'create_time': project.create_time.strftime('%Y-%m-%d %H:%M:%S'),
'update_time': project.update_time.strftime('%Y-%m-%d %H:%M:%S')
})
return JsonResponse({
'code': 200,
'message': '获取项目列表成功',
'data': project_list
})
except Exception as e:
logger.error(f'获取项目列表失败: {str(e)}', exc_info=True)
return JsonResponse({
'code': 500,
'message': f'服务器错误: {str(e)}'
})
@method_decorator(jwt_auth_required)
def post(self, request):
"""创建项目"""
try:
with transaction.atomic():
data = json.loads(request.body)
name = data.get('name')
description = data.get('description')
category = data.get('category')
repository = data.get('repository')
if not name:
return JsonResponse({
'code': 400,
'message': '项目名称不能为空'
})
# 检查项目名称是否已存在
if Project.objects.filter(name=name).exists():
return JsonResponse({
'code': 400,
'message': '项目名称已存在'
})
# 创建项目
creator = User.objects.get(user_id=request.user_id)
project = Project.objects.create(
project_id=generate_id(),
name=name,
description=description,
category=category,
repository=repository,
creator=creator
)
return JsonResponse({
'code': 200,
'message': '创建项目成功',
'data': {
'project_id': project.project_id,
'name': project.name
}
})
except Exception as e:
logger.error(f'创建项目失败: {str(e)}', exc_info=True)
return JsonResponse({
'code': 500,
'message': f'服务器错误: {str(e)}'
})
@method_decorator(jwt_auth_required)
def put(self, request):
"""编辑项目"""
try:
with transaction.atomic():
data = json.loads(request.body)
project_id = data.get('project_id')
name = data.get('name')
description = data.get('description')
category = data.get('category')
repository = data.get('repository')
if not project_id:
return JsonResponse({
'code': 400,
'message': '项目ID不能为空'
})
try:
project = Project.objects.get(project_id=project_id)
except Project.DoesNotExist:
return JsonResponse({
'code': 404,
'message': '项目不存在'
})
# 检查项目名称是否已存在
if name and name != project.name:
if Project.objects.filter(name=name).exists():
return JsonResponse({
'code': 400,
'message': '项目名称已存在'
})
project.name = name
if description is not None:
project.description = description
if category:
project.category = category
if repository:
project.repository = repository
project.save()
return JsonResponse({
'code': 200,
'message': '更新项目成功'
})
except Exception as e:
logger.error(f'更新项目失败: {str(e)}', exc_info=True)
return JsonResponse({
'code': 500,
'message': f'服务器错误: {str(e)}'
})
@method_decorator(jwt_auth_required)
def delete(self, request):
"""删除项目"""
try:
with transaction.atomic():
data = json.loads(request.body)
project_id = data.get('project_id')
if not project_id:
return JsonResponse({
'code': 400,
'message': '项目ID不能为空'
})
try:
project = Project.objects.get(project_id=project_id)
project.delete()
return JsonResponse({
'code': 200,
'message': '删除项目成功'
})
except Project.DoesNotExist:
return JsonResponse({
'code': 404,
'message': '项目不存在'
})
except Exception as e:
logger.error(f'删除项目失败: {str(e)}', exc_info=True)
return JsonResponse({
'code': 500,
'message': f'服务器错误: {str(e)}'
})
@method_decorator(csrf_exempt, name='dispatch')
class ProjectServiceView(View):
@method_decorator(jwt_auth_required)
def post(self, request):
"""创建项目服务"""
try:
with transaction.atomic():
data = json.loads(request.body)
project_id = data.get('project_id')
name = data.get('name')
description = data.get('description')
category = data.get('category')
repository = data.get('repository')
if not all([project_id, name, category, repository]):
return JsonResponse({
'code': 400,
'message': '项目ID、服务名称、类别和仓库地址不能为空'
})
try:
project = Project.objects.get(project_id=project_id)
except Project.DoesNotExist:
return JsonResponse({
'code': 404,
'message': '项目不存在'
})
# 检查服务名称在项目下是否已存在
if ProjectService.objects.filter(project=project, name=name).exists():
return JsonResponse({
'code': 400,
'message': '该项目下已存在同名服务'
})
creator = User.objects.get(user_id=request.user_id)
service = ProjectService.objects.create(
service_id=generate_id(),
project=project,
name=name,
description=description,
category=category,
repository=repository,
creator=creator
)
return JsonResponse({
'code': 200,
'message': '创建服务成功',
'data': {
'service_id': service.service_id,
'name': service.name
}
})
except Exception as e:
logger.error(f'创建服务失败: {str(e)}', exc_info=True)
return JsonResponse({
'code': 500,
'message': f'服务器错误: {str(e)}'
})
@method_decorator(jwt_auth_required)
def put(self, request):
"""更新项目服务"""
try:
with transaction.atomic():
data = json.loads(request.body)
service_id = data.get('service_id')
name = data.get('name')
description = data.get('description')
category = data.get('category')
repository = data.get('repository')
if not service_id:
return JsonResponse({
'code': 400,
'message': '服务ID不能为空'
})
try:
service = ProjectService.objects.get(service_id=service_id)
except ProjectService.DoesNotExist:
return JsonResponse({
'code': 404,
'message': '服务不存在'
})
# 检查服务名称是否已存在
if name and name != service.name:
if ProjectService.objects.filter(project=service.project, name=name).exists():
return JsonResponse({
'code': 400,
'message': '该项目下已存在同名服务'
})
service.name = name
if description is not None:
service.description = description
if category:
service.category = category
if repository:
service.repository = repository
service.save()
return JsonResponse({
'code': 200,
'message': '更新服务成功'
})
except Exception as e:
logger.error(f'更新服务失败: {str(e)}', exc_info=True)
return JsonResponse({
'code': 500,
'message': f'服务器错误: {str(e)}'
})
@method_decorator(jwt_auth_required)
def delete(self, request):
"""删除项目服务"""
try:
with transaction.atomic():
data = json.loads(request.body)
service_id = data.get('service_id')
if not service_id:
return JsonResponse({
'code': 400,
'message': '服务ID不能为空'
})
try:
service = ProjectService.objects.get(service_id=service_id)
service.delete()
return JsonResponse({
'code': 200,
'message': '删除服务成功'
})
except ProjectService.DoesNotExist:
return JsonResponse({
'code': 404,
'message': '服务不存在'
})
except Exception as e:
logger.error(f'删除服务失败: {str(e)}', exc_info=True)
return JsonResponse({
'code': 500,
'message': f'服务器错误: {str(e)}'
})