增加项目的各个功能

This commit is contained in:
qiaoxinjiu
2026-05-07 19:21:19 +08:00
parent aba1618f89
commit ee6cd4ae66
121 changed files with 9346 additions and 43 deletions

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.

Binary file not shown.

Binary file not shown.

224
app/api/dao/bugDao.py Normal file
View File

@@ -0,0 +1,224 @@
# encoding: UTF-8
from sqlalchemy import func, cast, Date
from ..model.bugModel import Bug, BugComment, BugHistory
from ..model.userModel import User
from ..model.caseModel import Module
from logger import logger
class BugDao(object):
@staticmethod
def create(session, model_cls, add_info):
obj = model_cls(**add_info)
session.add(obj)
err = session.done(close=False)
if err:
logger.warning(f'{model_cls.__name__}新增失败!{err}')
return 0, f'新增失败!{err}'
return obj.id, ''
@staticmethod
def update_by_id(session, model_cls, obj_id, update_info, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
update_res = session.query(model_cls).filter(*filters).update(update_info)
err = session.done(close=False)
if err:
logger.error(f'{model_cls.__name__}更新失败id: {obj_id}, err: {err}')
return 0, f'更新失败!{err}'
if not update_res:
return 0, '未查询到对应记录!'
return int(obj_id), ''
@staticmethod
def get_by_id(session, model_cls, obj_id, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
return session.query(model_cls).filter(*filters).first()
@staticmethod
def list_by_filters(session, model_cls, filter_list, page=1, limit=20, order_column=None, asc=False):
query = session.query(model_cls).filter(*filter_list)
if hasattr(model_cls, 'is_delete'):
query = query.filter(model_cls.is_delete == 0)
total = query.count()
if order_column is not None:
query = query.order_by(order_column.asc() if asc else order_column.desc())
rets = query.offset((int(page) - 1) * int(limit)).limit(int(limit)).all()
return rets, total
@staticmethod
def delete_by_id(session, model_cls, obj_id):
return BugDao.update_by_id(session, model_cls, obj_id, {'is_delete': 1})
@staticmethod
def generate_bug_key(session):
max_key = session.query(func.max(Bug.bug_key)).filter(Bug.bug_key.like('BUG-%')).scalar()
if max_key:
num = int(max_key.split('-')[1]) + 1
else:
num = 1
return f'BUG-{num:03d}'
@staticmethod
def get_comments(session, bug_id):
return session.query(BugComment).filter(
BugComment.bug_id == int(bug_id),
BugComment.is_delete == 0
).order_by(BugComment.created_time.desc()).all()
@staticmethod
def get_history(session, bug_id):
return session.query(BugHistory).filter(
BugHistory.bug_id == int(bug_id)
).order_by(BugHistory.created_time.desc()).all()
@staticmethod
def add_history(session, bug_id, field_name, old_value, new_value, operator_id):
session.add(BugHistory(
bug_id=bug_id,
field_name=field_name,
old_value=str(old_value) if old_value else None,
new_value=str(new_value) if new_value else None,
operator_id=operator_id
))
err = session.done(close=False)
if err:
logger.warning(f'BugHistory新增失败{err}')
return False
return True
@staticmethod
def get_stats(session, product_id=None, project_id=None):
query = session.query(Bug).filter(Bug.is_delete == 0)
if product_id:
query = query.filter(Bug.product_id == int(product_id))
if project_id:
query = query.filter(Bug.project_id == int(project_id))
total = query.count()
new_count = query.filter(Bug.status == 0).count()
pending_count = query.filter(Bug.status == 1).count()
in_progress_count = query.filter(Bug.status == 2).count()
resolved_count = query.filter(Bug.status == 3).count()
closed_count = query.filter(Bug.status == 4).count()
rejected_count = query.filter(Bug.status == 5).count()
by_status = {}
for status in range(6):
by_status[str(status)] = query.filter(Bug.status == status).count()
by_solution = {}
solution_results = session.query(
Bug.solution, func.count(Bug.id)
).filter(Bug.is_delete == 0)
if product_id:
solution_results = solution_results.filter(Bug.product_id == int(product_id))
if project_id:
solution_results = solution_results.filter(Bug.project_id == int(project_id))
solution_results = solution_results.filter(Bug.solution.isnot(None)).group_by(Bug.solution).all()
for solution, count in solution_results:
by_solution[solution] = count
by_reporter = {}
reporter_results = session.query(
User.real_name, func.count(Bug.id)
).join(User, Bug.reporter_id == User.id).filter(Bug.is_delete == 0)
if product_id:
reporter_results = reporter_results.filter(Bug.product_id == int(product_id))
if project_id:
reporter_results = reporter_results.filter(Bug.project_id == int(project_id))
reporter_results = reporter_results.group_by(User.real_name).all()
for name, count in reporter_results:
by_reporter[name] = count
by_assignee = {}
assignee_results = session.query(
User.real_name, func.count(Bug.id)
).outerjoin(User, Bug.assignee_id == User.id).filter(Bug.is_delete == 0)
if product_id:
assignee_results = assignee_results.filter(Bug.product_id == int(product_id))
if project_id:
assignee_results = assignee_results.filter(Bug.project_id == int(project_id))
assignee_results = assignee_results.group_by(User.real_name).all()
for name, count in assignee_results:
by_assignee[name or '未指派'] = count
by_resolver = {}
resolver_results = session.query(
User.real_name, func.count(Bug.id)
).outerjoin(User, Bug.resolved_by == User.id).filter(Bug.is_delete == 0)
if product_id:
resolver_results = resolver_results.filter(Bug.product_id == int(product_id))
if project_id:
resolver_results = resolver_results.filter(Bug.project_id == int(project_id))
resolver_results = resolver_results.group_by(User.real_name).all()
for name, count in resolver_results:
by_resolver[name or '未解决'] = count
by_module = {}
module_results = session.query(
Module.name, func.count(Bug.id)
).outerjoin(Module, Bug.module_id == Module.id).filter(Bug.is_delete == 0)
if product_id:
module_results = module_results.filter(Bug.product_id == int(product_id))
if project_id:
module_results = module_results.filter(Bug.project_id == int(project_id))
module_results = module_results.group_by(Module.name).all()
for name, count in module_results:
by_module[name or '未分类'] = count
by_version = {}
version_results = session.query(
Bug.resolve_version, func.count(Bug.id)
).filter(Bug.is_delete == 0)
if product_id:
version_results = version_results.filter(Bug.product_id == int(product_id))
if project_id:
version_results = version_results.filter(Bug.project_id == int(project_id))
version_results = version_results.filter(Bug.resolve_version.isnot(None)).group_by(Bug.resolve_version).all()
for version, count in version_results:
by_version[version] = count
by_activation = {}
daily_new = {}
daily_new_results = session.query(
cast(Bug.created_time, Date).label('stat_date'),
func.count(Bug.id)
).filter(Bug.is_delete == 0)
if product_id:
daily_new_results = daily_new_results.filter(Bug.product_id == int(product_id))
if project_id:
daily_new_results = daily_new_results.filter(Bug.project_id == int(project_id))
daily_new_results = daily_new_results.group_by('stat_date').order_by('stat_date').all()
for date, count in daily_new_results:
daily_new[str(date)] = count
daily_resolved = {}
daily_closed = {}
return {
'total': total,
'new': new_count,
'pending': pending_count,
'in_progress': in_progress_count,
'resolved': resolved_count,
'closed': closed_count,
'rejected': rejected_count,
'by_status': by_status,
'by_solution': by_solution,
'by_reporter': by_reporter,
'by_assignee': by_assignee,
'by_resolver': by_resolver,
'by_module': by_module,
'by_version': by_version,
'by_activation': by_activation,
'daily_new': daily_new,
'daily_resolved': daily_resolved,
'daily_closed': daily_closed
}

90
app/api/dao/caseDao.py Normal file
View File

@@ -0,0 +1,90 @@
# encoding: UTF-8
from sqlalchemy import func
from ..model.caseModel import CaseReview, CaseSnapshot, Module, TestCase
from logger import logger
class CaseDao(object):
"""用例域通用 DAO复用模块、用例、快照、评审的基础操作。"""
@staticmethod
def create(session, model_cls, add_info):
"""创建记录并提交事务。"""
obj = model_cls(**add_info)
session.add(obj)
err = session.done(close=False)
if err:
logger.warning(f'{model_cls.__name__}新增失败!{err}')
return 0, f'新增失败!{err}'
return obj.id, ''
@staticmethod
def update_by_id(session, model_cls, obj_id, update_info, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
update_res = session.query(model_cls).filter(*filters).update(update_info)
err = session.done(close=False)
if err:
logger.error(f'{model_cls.__name__}更新失败id: {obj_id}, err: {err}')
return 0, f'更新失败!{err}'
if not update_res:
return 0, '未查询到对应记录!'
return int(obj_id), ''
@staticmethod
def get_by_id(session, model_cls, obj_id, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
return session.query(model_cls).filter(*filters).first()
@staticmethod
def list_by_filters(session, model_cls, filter_list, page=1, limit=20, order_column=None):
query = session.query(model_cls).filter(*filter_list)
if hasattr(model_cls, 'is_delete'):
query = query.filter(model_cls.is_delete == 0)
total = query.count()
if order_column is not None:
query = query.order_by(order_column.desc())
rets = query.offset((int(page) - 1) * int(limit)).limit(int(limit)).all()
return rets, total
@staticmethod
def delete_by_id(session, model_cls, obj_id):
return CaseDao.update_by_id(session, model_cls, obj_id, {'is_delete': 1})
@staticmethod
def next_case_key(session, project_id):
count_num = session.query(func.count(TestCase.id)).filter(TestCase.project_id == int(project_id)).scalar() or 0
return 'TC-{:03d}'.format(count_num + 1)
@staticmethod
def next_snapshot_version(session, case_id):
"""生成用例快照版本号。"""
max_version = session.query(func.max(CaseSnapshot.version)).filter(CaseSnapshot.case_id == int(case_id)).scalar() or 0
return int(max_version) + 1
@staticmethod
def module_model():
return Module
@staticmethod
def case_model():
return TestCase
@staticmethod
def snapshot_model():
return CaseSnapshot
@staticmethod
def review_model():
return CaseReview
@staticmethod
def get_module_name_map(session, module_ids):
if not module_ids:
return {}
module_items = session.query(Module).filter(Module.id.in_(module_ids), Module.is_delete == 0).all()
return {module.id: module.name for module in module_items}

View File

@@ -0,0 +1,59 @@
# encoding: UTF-8
from ..model.dataBuilderModel import DataBuilder, DataTask
from logger import logger
class DataBuilderDao(object):
@staticmethod
def create(session, model_cls, add_info):
obj = model_cls(**add_info)
session.add(obj)
err = session.done(close=False)
if err:
logger.warning(f'{model_cls.__name__}新增失败!{err}')
return 0, f'新增失败!{err}'
return obj.id, ''
@staticmethod
def update_by_id(session, model_cls, obj_id, update_info, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
update_res = session.query(model_cls).filter(*filters).update(update_info)
err = session.done(close=False)
if err:
logger.error(f'{model_cls.__name__}更新失败id: {obj_id}, err: {err}')
return 0, f'更新失败!{err}'
if not update_res:
return 0, '未查询到对应记录!'
return int(obj_id), ''
@staticmethod
def get_by_id(session, model_cls, obj_id, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
return session.query(model_cls).filter(*filters).first()
@staticmethod
def list_by_filters(session, model_cls, filter_list, page=1, limit=20, order_column=None):
query = session.query(model_cls).filter(*filter_list)
if hasattr(model_cls, 'is_delete'):
query = query.filter(model_cls.is_delete == 0)
total = query.count()
if order_column is not None:
query = query.order_by(order_column.desc())
rets = query.offset((int(page) - 1) * int(limit)).limit(int(limit)).all()
return rets, total
@staticmethod
def delete_by_id(session, model_cls, obj_id):
return DataBuilderDao.update_by_id(session, model_cls, obj_id, {'is_delete': 1})
@staticmethod
def builder_model():
return DataBuilder
@staticmethod
def task_model():
return DataTask

88
app/api/dao/planDao.py Normal file
View File

@@ -0,0 +1,88 @@
# encoding: UTF-8
from sqlalchemy import func
from ..model.planModel import PlanCase, TestPlan, TestRound
from logger import logger
class PlanDao(object):
@staticmethod
def create(session, model_cls, add_info):
obj = model_cls(**add_info)
session.add(obj)
err = session.done(close=False)
if err:
logger.warning(f'{model_cls.__name__}新增失败!{err}')
return 0, f'新增失败!{err}'
return obj.id, ''
@staticmethod
def batch_create(session, model_cls, batch_info_list):
if not batch_info_list:
return 0, ''
objs = [model_cls(**info) for info in batch_info_list]
session.add_all(objs)
err = session.done(close=False)
if err:
logger.warning(f'{model_cls.__name__}批量新增失败!{err}')
return 0, f'批量新增失败!{err}'
return len(objs), ''
@staticmethod
def update_by_id(session, model_cls, obj_id, update_info, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
update_res = session.query(model_cls).filter(*filters).update(update_info)
err = session.done(close=False)
if err:
logger.error(f'{model_cls.__name__}更新失败id: {obj_id}, err: {err}')
return 0, f'更新失败!{err}'
if not update_res:
return 0, '未查询到对应记录!'
return int(obj_id), ''
@staticmethod
def get_by_id(session, model_cls, obj_id, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
return session.query(model_cls).filter(*filters).first()
@staticmethod
def list_by_filters(session, model_cls, filter_list, page=1, limit=20, order_column=None, asc=False):
query = session.query(model_cls).filter(*filter_list)
if hasattr(model_cls, 'is_delete'):
query = query.filter(model_cls.is_delete == 0)
total = query.count()
if order_column is not None:
query = query.order_by(order_column.asc() if asc else order_column.desc())
rets = query.offset((int(page) - 1) * int(limit)).limit(int(limit)).all()
return rets, total
@staticmethod
def delete_by_id(session, model_cls, obj_id):
return PlanDao.update_by_id(session, model_cls, obj_id, {'is_delete': 1})
@staticmethod
def plan_stats(session, plan_id):
"""聚合计划执行进度,用于计划详情、进度看板和报告生成。"""
total = session.query(func.count(PlanCase.id)).filter(PlanCase.plan_id == int(plan_id)).scalar() or 0
passed = session.query(func.count(PlanCase.id)).filter(PlanCase.plan_id == int(plan_id), PlanCase.status == 1).scalar() or 0
failed = session.query(func.count(PlanCase.id)).filter(PlanCase.plan_id == int(plan_id), PlanCase.status == 2).scalar() or 0
blocked = session.query(func.count(PlanCase.id)).filter(PlanCase.plan_id == int(plan_id), PlanCase.status == 3).scalar() or 0
completed = passed + failed + blocked
pass_rate = round(passed / total * 100, 2) if total else 0
return {'total_cases': total, 'completed': completed, 'passed': passed, 'failed': failed, 'blocked': blocked, 'pass_rate': pass_rate}
@staticmethod
def plan_model():
return TestPlan
@staticmethod
def plan_case_model():
return PlanCase
@staticmethod
def round_model():
return TestRound

55
app/api/dao/productDao.py Normal file
View File

@@ -0,0 +1,55 @@
# encoding: UTF-8
from ..model.productModel import Product
from logger import logger
class ProductDao(object):
@staticmethod
def create(session, model_cls, add_info):
obj = model_cls(**add_info)
session.add(obj)
err = session.done(close=False)
if err:
logger.warning(f'{model_cls.__name__}新增失败!{err}')
return 0, f'新增失败!{err}'
return obj.id, ''
@staticmethod
def update_by_id(session, model_cls, obj_id, update_info, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
update_res = session.query(model_cls).filter(*filters).update(update_info)
err = session.done(close=False)
if err:
logger.error(f'{model_cls.__name__}更新失败id: {obj_id}, err: {err}')
return 0, f'更新失败!{err}'
if not update_res:
return 0, '未查询到对应记录!'
return int(obj_id), ''
@staticmethod
def get_by_id(session, model_cls, obj_id, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
return session.query(model_cls).filter(*filters).first()
@staticmethod
def list_by_filters(session, model_cls, filter_list, page=1, limit=20, order_column=None):
query = session.query(model_cls).filter(*filter_list)
if hasattr(model_cls, 'is_delete'):
query = query.filter(model_cls.is_delete == 0)
total = query.count()
if order_column is not None:
query = query.order_by(order_column.desc())
rets = query.offset((int(page) - 1) * int(limit)).limit(int(limit)).all()
return rets, total
@staticmethod
def delete_by_id(session, model_cls, obj_id):
return ProductDao.update_by_id(session, model_cls, obj_id, {'is_delete': 1})
@staticmethod
def product_model():
return Product

79
app/api/dao/projectDao.py Normal file
View File

@@ -0,0 +1,79 @@
# encoding: UTF-8
from ..model.productModel import Product
from ..model.projectModel import Environment, Project, ProjectMember
from logger import logger
class ProjectDao(object):
@staticmethod
def create(session, model_cls, add_info):
obj = model_cls(**add_info)
session.add(obj)
err = session.done(close=False)
if err:
logger.warning(f'{model_cls.__name__}新增失败!{err}')
return 0, f'新增失败!{err}'
return obj.id, ''
@staticmethod
def update_by_id(session, model_cls, obj_id, update_info, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
update_res = session.query(model_cls).filter(*filters).update(update_info)
err = session.done(close=False)
if err:
logger.error(f'{model_cls.__name__}更新失败id: {obj_id}, err: {err}')
return 0, f'更新失败!{err}'
if not update_res:
return 0, '未查询到对应记录!'
return int(obj_id), ''
@staticmethod
def get_by_id(session, model_cls, obj_id, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
return session.query(model_cls).filter(*filters).first()
@staticmethod
def list_by_filters(session, model_cls, filter_list, page=1, limit=20, order_column=None):
"""按过滤条件分页查询;存在 is_delete 字段时统一过滤未删除数据。"""
query = session.query(model_cls).filter(*filter_list)
if hasattr(model_cls, 'is_delete'):
query = query.filter(model_cls.is_delete == 0)
total = query.count()
if order_column is not None:
query = query.order_by(order_column.desc())
rets = query.offset((int(page) - 1) * int(limit)).limit(int(limit)).all()
return rets, total
@staticmethod
def delete_by_id(session, model_cls, obj_id):
return ProjectDao.update_by_id(session, model_cls, obj_id, {'is_delete': 1})
@staticmethod
def get_product_map(session, product_ids):
if not product_ids:
return {}
product_items = session.query(Product).filter(Product.id.in_(product_ids), Product.is_delete == 0).all()
return {product.id: product.name for product in product_items}
@staticmethod
def get_project_name_map(session, project_ids):
if not project_ids:
return {}
project_items = session.query(Project).filter(Project.id.in_(project_ids), Project.is_delete == 0).all()
return {project.id: {'name': project.name} for project in project_items}
@staticmethod
def project_model():
return Project
@staticmethod
def member_model():
return ProjectMember
@staticmethod
def environment_model():
return Environment

View File

@@ -0,0 +1,62 @@
# encoding: UTF-8
from ..model.projectHookModel import ProjectHook
from logger import logger
class ProjectHookDao(object):
@staticmethod
def create(session, model_cls, add_info):
obj = model_cls(**add_info)
session.add(obj)
err = session.done(close=False)
if err:
logger.warning(f'{model_cls.__name__}新增失败!{err}')
return 0, f'新增失败!{err}'
return obj.id, ''
@staticmethod
def update_by_id(session, model_cls, obj_id, update_info, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
update_res = session.query(model_cls).filter(*filters).update(update_info)
err = session.done(close=False)
if err:
logger.error(f'{model_cls.__name__}更新失败id: {obj_id}, err: {err}')
return 0, f'更新失败!{err}'
if not update_res:
return 0, '未查询到对应记录!'
return int(obj_id), ''
@staticmethod
def get_by_id(session, model_cls, obj_id, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
return session.query(model_cls).filter(*filters).first()
@staticmethod
def list_by_filters(session, model_cls, filter_list, page=1, limit=20, order_column=None):
query = session.query(model_cls).filter(*filter_list)
if hasattr(model_cls, 'is_delete'):
query = query.filter(model_cls.is_delete == 0)
total = query.count()
if order_column is not None:
query = query.order_by(order_column.desc())
rets = query.offset((int(page) - 1) * int(limit)).limit(int(limit)).all()
return rets, total
@staticmethod
def delete_by_id(session, model_cls, obj_id):
return ProjectHookDao.update_by_id(session, model_cls, obj_id, {'is_delete': 1})
@staticmethod
def hook_model():
return ProjectHook
@staticmethod
def list_all_by_filters(session, model_cls, filter_list):
query = session.query(model_cls).filter(*filter_list)
if hasattr(model_cls, 'is_delete'):
query = query.filter(model_cls.is_delete == 0)
return query.all()

185
app/api/dao/rbacDao.py Normal file
View File

@@ -0,0 +1,185 @@
# encoding: UTF-8
from ..model.rbacModel import Role, Permission, RolePermission, Menu, RoleMenu
from logger import logger
class RbacDao(object):
@staticmethod
def create(session, model_cls, add_info):
obj = model_cls(**add_info)
session.add(obj)
err = session.done(close=False)
if err:
logger.warning(f'{model_cls.__name__}新增失败!{err}')
return 0, f'新增失败!{err}'
return obj.id, ''
@staticmethod
def update_by_id(session, model_cls, obj_id, update_info, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
update_res = session.query(model_cls).filter(*filters).update(update_info)
err = session.done(close=False)
if err:
logger.error(f'{model_cls.__name__}更新失败id: {obj_id}, err: {err}')
return 0, f'更新失败!{err}'
if not update_res:
return 0, '未查询到对应记录!'
return int(obj_id), ''
@staticmethod
def get_by_id(session, model_cls, obj_id, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
return session.query(model_cls).filter(*filters).first()
@staticmethod
def list_by_filters(session, model_cls, filter_list, page=1, limit=20, order_column=None):
query = session.query(model_cls).filter(*filter_list)
if hasattr(model_cls, 'is_delete'):
query = query.filter(model_cls.is_delete == 0)
total = query.count()
if order_column is not None:
query = query.order_by(order_column.desc())
rets = query.offset((int(page) - 1) * int(limit)).limit(int(limit)).all()
return rets, total
@staticmethod
def delete_by_id(session, model_cls, obj_id):
return RbacDao.update_by_id(session, model_cls, obj_id, {'is_delete': 1})
@staticmethod
def get_role_permission_ids(session, role_id):
items = session.query(RolePermission).filter(RolePermission.role_id == int(role_id), RolePermission.is_delete == 0).all()
return [item.permission_id for item in items]
@staticmethod
def replace_role_permissions(session, role_id, permission_ids):
role_id = int(role_id)
normalized_permission_ids = []
for permission_id in permission_ids:
permission_id = int(permission_id)
if permission_id not in normalized_permission_ids:
normalized_permission_ids.append(permission_id)
session.query(RolePermission).filter(RolePermission.role_id == role_id, RolePermission.is_delete == 0).update({'is_delete': 1})
session.flush()
if normalized_permission_ids:
existing_items = session.query(RolePermission).filter(
RolePermission.role_id == role_id,
RolePermission.permission_id.in_(normalized_permission_ids)
).all()
existing_map = {item.permission_id: item for item in existing_items}
for permission_id in normalized_permission_ids:
existing_item = existing_map.get(permission_id)
if existing_item:
existing_item.is_delete = 0
else:
session.add(RolePermission(role_id=role_id, permission_id=permission_id, is_delete=0))
err = session.done(close=False)
if err:
return 0, f'分配权限失败!{err}'
return role_id, ''
@staticmethod
def assign_permissions_to_roles(session, role_ids, permission_id):
permission_id = int(permission_id)
normalized_role_ids = []
for role_id in role_ids:
role_id = int(role_id)
if role_id not in normalized_role_ids:
normalized_role_ids.append(role_id)
existing_items = session.query(RolePermission).filter(
RolePermission.role_id.in_(normalized_role_ids),
RolePermission.permission_id == permission_id
).all()
existing_role_ids = {item.role_id for item in existing_items}
for role_id in normalized_role_ids:
if role_id not in existing_role_ids:
session.add(RolePermission(role_id=role_id, permission_id=permission_id, is_delete=0))
else:
existing_item = next(item for item in existing_items if item.role_id == role_id)
if existing_item.is_delete == 1:
existing_item.is_delete = 0
err = session.done(close=False)
if err:
return 0, f'分配权限失败!{err}'
return len(normalized_role_ids), ''
@staticmethod
def get_role_menu_ids(session, role_id):
items = session.query(RoleMenu).filter(RoleMenu.role_id == int(role_id), RoleMenu.is_delete == 0).all()
return [item.menu_id for item in items]
@staticmethod
def replace_role_menus(session, role_id, menu_ids):
role_id = int(role_id)
normalized_menu_ids = []
for menu_id in menu_ids:
menu_id = int(menu_id)
if menu_id not in normalized_menu_ids:
normalized_menu_ids.append(menu_id)
session.query(RoleMenu).filter(RoleMenu.role_id == role_id, RoleMenu.is_delete == 0).update({'is_delete': 1})
if normalized_menu_ids:
existing_items = session.query(RoleMenu).filter(
RoleMenu.role_id == role_id,
RoleMenu.menu_id.in_(normalized_menu_ids)
).all()
existing_map = {item.menu_id: item for item in existing_items}
for menu_id in normalized_menu_ids:
existing_item = existing_map.get(menu_id)
if existing_item:
existing_item.is_delete = 0
else:
session.add(RoleMenu(role_id=role_id, menu_id=menu_id, is_delete=0))
err = session.done(close=False)
if err:
return 0, f'分配菜单失败!{err}'
return role_id, ''
@staticmethod
def get_role_names_map(session, role_ids):
if not role_ids:
return {}
items = session.query(Role).filter(Role.id.in_(role_ids), Role.is_delete == 0).all()
return {item.id: item.name for item in items}
@staticmethod
def get_role_permission_codes(session, role_ids):
if not role_ids:
return []
permission_items = session.query(Permission.code).join(
RolePermission, RolePermission.permission_id == Permission.id
).filter(
RolePermission.role_id.in_(role_ids), RolePermission.is_delete == 0,
Permission.is_delete == 0, Permission.status == 1
).all()
menu_items = session.query(Menu.permission_code).join(
RoleMenu, RoleMenu.menu_id == Menu.id
).filter(
RoleMenu.role_id.in_(role_ids), RoleMenu.is_delete == 0,
Menu.is_delete == 0, Menu.status == 1
).all()
return sorted(list({item[0] for item in permission_items if item[0]} | {item[0] for item in menu_items if item[0]}))
@staticmethod
def get_menu_tree_items(session, filter_list):
return session.query(Menu).filter(*filter_list, Menu.is_delete == 0).order_by(Menu.sort.asc(), Menu.id.asc()).all()
@staticmethod
def role_model():
return Role
@staticmethod
def permission_model():
return Permission
@staticmethod
def menu_model():
return Menu
@staticmethod
def get_role_name_map(session):
items = session.query(Role).filter(Role.is_delete == 0, Role.status == 1).all()
return {item.id: item.name for item in items}

36
app/api/dao/reportDao.py Normal file
View File

@@ -0,0 +1,36 @@
# encoding: UTF-8
from ..model.reportModel import DefectSync, Report
from logger import logger
class ReportDao(object):
@staticmethod
def create(session, model_cls, add_info):
obj = model_cls(**add_info)
session.add(obj)
err = session.done(close=False)
if err:
logger.warning(f'{model_cls.__name__}新增失败!{err}')
return 0, f'新增失败!{err}'
return obj.id, ''
@staticmethod
def get_by_id(session, model_cls, obj_id):
return session.query(model_cls).filter(model_cls.id == int(obj_id)).first()
@staticmethod
def list_by_filters(session, model_cls, filter_list, page=1, limit=20, order_column=None, asc=False):
query = session.query(model_cls).filter(*filter_list)
total = query.count()
if order_column is not None:
query = query.order_by(order_column.asc() if asc else order_column.desc())
rets = query.offset((int(page) - 1) * int(limit)).limit(int(limit)).all()
return rets, total
@staticmethod
def report_model():
return Report
@staticmethod
def defect_model():
return DefectSync

View File

@@ -43,15 +43,12 @@ class UpdateSqlProjectDao(object):
@staticmethod
def get_sql_by_filters(session, filter_list, page=1, limit=20):
rets = session.query(UpdateSqlProject)\
.filter(*filter_list) \
.filter(UpdateSqlProject.is_delete == 0) \
.order_by(UpdateSqlProject.created_time.desc()) \
query = session.query(UpdateSqlProject).filter(*filter_list).filter(UpdateSqlProject.is_delete == 0)
total = query.count()
rets = query.order_by(UpdateSqlProject.created_time.desc()) \
.offset((int(page) - 1) * int(limit)) \
.limit(limit) \
.all()
total = session.query(UpdateSqlProject).filter(*filter_list).filter(
UpdateSqlProject.is_delete == 0).count()
return rets, total
@staticmethod

109
app/api/dao/userDao.py Normal file
View File

@@ -0,0 +1,109 @@
# encoding: UTF-8
from datetime import datetime
from ..model.userModel import User, UserRole
from logger import logger
class UserDao(object):
@staticmethod
def create(session, model_cls, add_info):
obj = model_cls(**add_info)
session.add(obj)
err = session.done(close=False)
if err:
logger.warning(f'{model_cls.__name__}新增失败!{err}')
return 0, f'新增失败!{err}'
return obj.id, ''
@staticmethod
def update_by_id(session, model_cls, obj_id, update_info, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
update_res = session.query(model_cls).filter(*filters).update(update_info)
err = session.done(close=False)
if err:
logger.error(f'{model_cls.__name__}更新失败id: {obj_id}, err: {err}')
return 0, f'更新失败!{err}'
if not update_res:
return 0, '未查询到对应记录!'
return int(obj_id), ''
@staticmethod
def get_by_id(session, model_cls, obj_id, soft_delete=True):
filters = [model_cls.id == int(obj_id)]
if soft_delete and hasattr(model_cls, 'is_delete'):
filters.append(model_cls.is_delete == 0)
return session.query(model_cls).filter(*filters).first()
@staticmethod
def list_by_filters(session, model_cls, filter_list, page=1, limit=20, order_column=None):
query = session.query(model_cls).filter(*filter_list)
if hasattr(model_cls, 'is_delete'):
query = query.filter(model_cls.is_delete == 0)
total = query.count()
if order_column is not None:
query = query.order_by(order_column.desc())
rets = query.offset((int(page) - 1) * int(limit)).limit(int(limit)).all()
return rets, total
@staticmethod
def delete_by_id(session, model_cls, obj_id):
return UserDao.update_by_id(session, model_cls, obj_id, {'is_delete': 1})
@staticmethod
def get_user_role_ids(session, user_id):
items = session.query(UserRole).filter(UserRole.user_id == int(user_id), UserRole.is_delete == 0).all()
return [item.role_id for item in items]
@staticmethod
def replace_user_roles(session, user_id, role_ids):
user_id = int(user_id)
role_ids = [int(role_id) for role_id in role_ids]
session.query(UserRole).filter(UserRole.user_id == user_id, UserRole.is_delete == 0).update({'is_delete': 1})
existing_items = session.query(UserRole).filter(UserRole.user_id == user_id).all()
existing_map = {item.role_id: item for item in existing_items}
for role_id in role_ids:
existing_item = existing_map.get(role_id)
if existing_item:
existing_item.is_delete = 0
else:
session.add(UserRole(user_id=user_id, role_id=role_id, is_delete=0))
err = session.done(close=False)
if err:
return 0, f'分配角色失败!{err}'
return user_id, ''
@staticmethod
def get_user_roles(session, user_ids):
if not user_ids:
return {}
items = session.query(UserRole).filter(UserRole.user_id.in_(user_ids), UserRole.is_delete == 0).all()
ret = {}
for item in items:
ret.setdefault(item.user_id, []).append(item.role_id)
return ret
@staticmethod
def get_by_username(session, username):
return session.query(User).filter(User.username == username, User.is_delete == 0).first()
@staticmethod
def update_last_login_time(session, user_id):
session.query(User).filter(User.id == int(user_id), User.is_delete == 0).update({'last_login_time': datetime.now()})
err = session.done(close=False)
if err:
return 0, f'更新登录时间失败!{err}'
return int(user_id), ''
@staticmethod
def user_model():
return User
@staticmethod
def get_user_info_map(session, user_ids):
if not user_ids:
return {}
items = session.query(User).filter(User.id.in_(user_ids), User.is_delete == 0).all()
return {item.id: {'username': item.username, 'real_name': item.real_name} for item in items}