2438 lines
84 KiB
Python
2438 lines
84 KiB
Python
from sqlalchemy.orm import Session,defer
|
|
from sqlalchemy import func, or_
|
|
from sqlalchemy import desc
|
|
from app import models, schemas
|
|
from .utils import hash_password, verify_password
|
|
from typing import List, Optional, Dict, Any
|
|
import datetime
|
|
import re
|
|
|
|
|
|
# Status mapping
|
|
STATUS_NAMES = {
|
|
1: "created",
|
|
2: "active",
|
|
3: "disabled",
|
|
}
|
|
|
|
|
|
def authenticate_user(db: Session, email: str, password: str) -> Optional[models.User]:
|
|
"""Authenticate user by email and password.
|
|
|
|
Returns user if credentials are valid, None otherwise.
|
|
"""
|
|
user = db.query(models.User).filter(models.User.email == email).first()
|
|
if not user:
|
|
return None
|
|
# print(user.hashed_password)
|
|
if not verify_password(password, user.hashed_password or ""):
|
|
return None
|
|
return user
|
|
|
|
|
|
def get_unit_name(db: Session, unit_id: int) -> Optional[str]:
|
|
"""Get unit name by unit_id."""
|
|
if not unit_id:
|
|
return None
|
|
unit = db.query(models.Unit).filter(models.Unit.id == unit_id).first()
|
|
return unit.name if unit else None
|
|
|
|
|
|
def get_system_name(db: Session, system_id: int) -> Optional[str]:
|
|
"""Get system name by system_id."""
|
|
if not system_id:
|
|
return None
|
|
system = db.query(models.ManageSystem).filter(models.ManageSystem.id == system_id).first()
|
|
return system.name if system else None
|
|
|
|
|
|
def get_system_type_name(system_type: Optional[int]) -> Optional[str]:
|
|
"""Get system type name by system_type."""
|
|
types = {1: "Trọng điểm", 2: "Cốt lõi", 3: "Nền tảng", 4: "Vệ tinh", 5: "Khác"}
|
|
return types.get(system_type)
|
|
|
|
def get_soc_type_name(db: Session, type_id: Optional[int]) -> Optional[str]:
|
|
"""Get SOC target type name by id."""
|
|
if not type_id:
|
|
return None
|
|
row = db.query(models.SocTargetType).filter(models.SocTargetType.id == type_id).first()
|
|
return row.name if row else None
|
|
|
|
def list_soc_target_types(db: Session) -> List[models.SocTargetType]:
|
|
"""List all SOC target types."""
|
|
return db.query(models.SocTargetType).all()
|
|
|
|
def get_ticket_related_list(db: Session, target_id: int) -> List[schemas.TicketRelated]:
|
|
"""Get related tickets for a target."""
|
|
rows = db.query(models.TicketRelated).filter(models.TicketRelated.soc_target_id == target_id).all()
|
|
res = []
|
|
for r in rows:
|
|
tr = schemas.TicketRelated.model_validate(r)
|
|
# Fetch related ticket details for name/code
|
|
related = db.query(models.SocTarget).filter(models.SocTarget.id == r.related_soc_target_id).first()
|
|
if related:
|
|
tr.related_ticket_name = related.name
|
|
tr.related_ticket_code = related.code
|
|
res.append(tr)
|
|
return res
|
|
if system_type is None:
|
|
return None
|
|
mapping = {
|
|
1: "Trọng điểm",
|
|
2: "Cốt lõi",
|
|
3: "Nền tảng",
|
|
4: "Vệ tinh",
|
|
5: "Khác"
|
|
}
|
|
return mapping.get(system_type)
|
|
|
|
|
|
def get_user_with_details(db: Session, user: models.User) -> Dict[str, Any]:
|
|
"""Convert user model to dict with unit_name and status_name."""
|
|
unit_name = get_unit_name(db, user.unit_id)
|
|
status_name = STATUS_NAMES.get(user.status, "unknown")
|
|
role_name = None
|
|
if getattr(user, "role_id", None):
|
|
r = db.query(models.Role).filter(models.Role.id == user.role_id).first()
|
|
role_name = r.name if r else None
|
|
|
|
return {
|
|
"id": user.id,
|
|
"email": user.email,
|
|
"fullname": user.fullname,
|
|
"unit_id": user.unit_id,
|
|
"unit_name": unit_name,
|
|
"role_id": getattr(user, "role_id", None),
|
|
"role_name": role_name,
|
|
"status": user.status,
|
|
"status_name": status_name,
|
|
"created_at": user.created_at,
|
|
"updated_at": user.updated_at,
|
|
}
|
|
|
|
|
|
# Role
|
|
def create_role(db: Session, role_in: schemas.RoleCreate) -> models.Role:
|
|
db_obj = models.Role(name=role_in.name, description=role_in.description)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def bulk_create_log_sources(db: Session, items: list[schemas.LogSourceCreate]) -> int:
|
|
"""Batch insert log source records."""
|
|
if not items:
|
|
return 0
|
|
|
|
db_objs = [
|
|
models.LogSource(
|
|
month_id=item.month_id,
|
|
unit_id=item.unit_id,
|
|
log_id=item.log_id,
|
|
name=item.name,
|
|
description=item.description,
|
|
is_enabled=item.is_enabled if item.is_enabled is not None else True,
|
|
source_type_id=item.source_type_id,
|
|
status=item.status,
|
|
message=item.message,
|
|
other=item.other,
|
|
file_id=item.file_id,
|
|
created_at=item.created_at if getattr(item, "created_at", None) is not None else None,
|
|
)
|
|
for item in items
|
|
]
|
|
db.add_all(db_objs)
|
|
db.commit()
|
|
return len(db_objs)
|
|
|
|
# -------- PentestService CRUD --------
|
|
PENTEST_STATUS_NAMES = {
|
|
0: "Nháp",
|
|
1: "Gửi yêu cầu",
|
|
2: "Tiếp nhận",
|
|
3: "Đang xử lý",
|
|
4: "Đóng",
|
|
5: "Hủy"
|
|
}
|
|
|
|
def generate_pentest_code(db: Session) -> str:
|
|
now = datetime.datetime.now()
|
|
month_str = now.strftime("%m%Y")
|
|
prefix = f"ANTT.{month_str}."
|
|
|
|
# Find the latest code for this month to avoid Duplicate Entry errors
|
|
last_record = db.query(models.PentestService.code).filter(
|
|
models.PentestService.code.like(f"{prefix}%")
|
|
).order_by(desc(models.PentestService.code)).first()
|
|
|
|
if last_record:
|
|
try:
|
|
# Extract number from format ANTT.MMYYYY.NNN
|
|
last_code = last_record[0]
|
|
num_part = last_code.split('.')[-1]
|
|
new_number = int(num_part) + 1
|
|
except (ValueError, IndexError):
|
|
# Fallback if parsing fails
|
|
new_number = db.query(models.PentestService).filter(models.PentestService.code.like(f"{prefix}%")).count() + 1
|
|
else:
|
|
new_number = 1
|
|
|
|
return f"{prefix}{new_number:03d}"
|
|
|
|
def create_pentest_service(
|
|
db: Session,
|
|
obj_in: schemas.PentestServiceCreate,
|
|
user_id: int,
|
|
is_admin_user: bool = False
|
|
) -> models.PentestService:
|
|
# Rule check: Chỉ Admin/Administrator mới được set target_id khi tạo
|
|
if obj_in.target_id is not None and not is_admin_user:
|
|
raise ValueError("Bạn không có quyền thiết lập target_id.")
|
|
|
|
# Rule check: list_process chỉ nhóm Admin/Administrator có quyền
|
|
if obj_in.list_process and not is_admin_user:
|
|
raise ValueError("Bạn không có quyền gán người dùng.")
|
|
|
|
# Nếu là admin và có truyền user_id thì dùng user_id đó, ngược lại dùng user_id của người tạo
|
|
final_user_id = obj_in.user_id if is_admin_user and obj_in.user_id is not None else user_id
|
|
|
|
code = generate_pentest_code(db)
|
|
|
|
# Loại bỏ user_id và list_process khỏi dict để tránh duplicate keyword argument
|
|
obj_dict = obj_in.dict()
|
|
obj_dict.pop("user_id", None)
|
|
list_process = obj_dict.pop("list_process", None)
|
|
other_assign = obj_dict.pop("other_assign", None)
|
|
|
|
db_obj = models.PentestService(
|
|
**obj_dict,
|
|
code=code,
|
|
status=0, # Default is draft
|
|
user_id=final_user_id
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
|
|
# Lưu danh sách gán nếu có (user_id)
|
|
if list_process:
|
|
for uid in list_process:
|
|
db.add(models.PentestServiceAssign(
|
|
user_id=uid,
|
|
pentest_service_id=db_obj.id
|
|
))
|
|
|
|
# Lưu danh sách gán email nếu có (other_assign)
|
|
if other_assign:
|
|
for email in other_assign:
|
|
db.add(models.PentestServiceAssign(
|
|
email=email,
|
|
pentest_service_id=db_obj.id
|
|
))
|
|
|
|
if list_process or other_assign:
|
|
db.commit()
|
|
|
|
# Log history
|
|
history = models.PentestServiceHistory(
|
|
pentest_service_id=db_obj.id,
|
|
new_status=0,
|
|
user_id=user_id # Người thực hiện hành động
|
|
)
|
|
db.add(history)
|
|
db.commit()
|
|
|
|
return db_obj
|
|
|
|
def get_pentest_service(db: Session, id: int) -> models.PentestService | None:
|
|
return db.query(models.PentestService).filter(models.PentestService.id == id).first()
|
|
|
|
def get_pentest_assigned_emails(db: Session, service_id: int) -> list[str]:
|
|
"""Get emails of users assigned to a pentest service."""
|
|
rows = db.query(models.User.email).join(
|
|
models.PentestServiceAssign, models.User.id == models.PentestServiceAssign.user_id
|
|
).filter(models.PentestServiceAssign.pentest_service_id == service_id).all()
|
|
return [r[0] for r in rows]
|
|
|
|
def get_pentest_assigned_names(db: Session, service_id: int) -> list[str]:
|
|
"""Get fullnames of users assigned to a pentest service."""
|
|
rows = db.query(models.User.fullname).join(
|
|
models.PentestServiceAssign, models.User.id == models.PentestServiceAssign.user_id
|
|
).filter(models.PentestServiceAssign.pentest_service_id == service_id).all()
|
|
return [r[0] for r in rows]
|
|
|
|
def get_pentest_assigned_user_ids(db: Session, service_id: int) -> list[int]:
|
|
"""Get IDs of users assigned to a pentest service."""
|
|
rows = db.query(models.PentestServiceAssign.user_id).filter(
|
|
models.PentestServiceAssign.pentest_service_id == service_id,
|
|
models.PentestServiceAssign.user_id.isnot(None)
|
|
).all()
|
|
return [int(r[0]) for r in rows if r[0] is not None]
|
|
|
|
def get_pentest_other_assigned_emails(db: Session, service_id: int) -> list[str]:
|
|
"""Get other assigned emails (where user_id is null) for a pentest service."""
|
|
rows = db.query(models.PentestServiceAssign.email).filter(
|
|
models.PentestServiceAssign.pentest_service_id == service_id,
|
|
models.PentestServiceAssign.user_id == None
|
|
).all()
|
|
return [r[0] for r in rows if r[0]]
|
|
|
|
def list_pentest_services(
|
|
db: Session,
|
|
unit_id: int | None = None,
|
|
user_id: int | None = None,
|
|
status: int | None = None,
|
|
month_id: int | None = None,
|
|
skip: int = 0,
|
|
limit: int = 100
|
|
) -> tuple[list[models.PentestService], int]:
|
|
query = db.query(models.PentestService)
|
|
if unit_id is not None:
|
|
query = query.filter(models.PentestService.unit_id == unit_id)
|
|
if user_id is not None:
|
|
# Show tasks created by the user OR assigned to the user
|
|
assigned_ids = db.query(models.PentestServiceAssign.pentest_service_id).filter(
|
|
models.PentestServiceAssign.user_id == user_id
|
|
).subquery()
|
|
query = query.filter(
|
|
or_(
|
|
models.PentestService.user_id == user_id,
|
|
models.PentestService.id.in_(assigned_ids)
|
|
)
|
|
)
|
|
if status is not None:
|
|
query = query.filter(models.PentestService.status == status)
|
|
|
|
if month_id is not None:
|
|
month_obj = db.query(models.Month).filter(models.Month.id == month_id).first()
|
|
if month_obj:
|
|
query = query.filter(
|
|
models.PentestService.created_at >= month_obj.from_date,
|
|
models.PentestService.created_at <= month_obj.end_date
|
|
)
|
|
|
|
total = query.count()
|
|
items = query.order_by(models.PentestService.id.desc()).offset(skip).limit(limit).all()
|
|
return items, total
|
|
|
|
def update_pentest_service(
|
|
db: Session,
|
|
id: int,
|
|
obj_in: schemas.PentestServiceUpdate,
|
|
user_id: int,
|
|
is_admin_user: bool = False
|
|
) -> models.PentestService | None:
|
|
db_obj = get_pentest_service(db, id)
|
|
if not db_obj:
|
|
return None
|
|
|
|
old_status = db_obj.status
|
|
new_status = obj_in.status if obj_in.status is not None else old_status
|
|
|
|
# Rule check: Đã update sang 1 (Tạo mới) thì không chỉnh sửa được nội dung task.
|
|
if old_status >= 1 and any(v is not None for k, v in obj_in.dict(exclude={"status", "list_process"}).items() if v is not None):
|
|
if not is_admin_user: # Admin might still be able to edit? Request says "không chỉnh sửa được nội dung task"
|
|
raise ValueError("Task đã được gửi, không thể chỉnh sửa nội dung.")
|
|
|
|
# Rule check: Update status từ 0 sang 1 thì chỉ nhóm quyền Manager, Member.
|
|
# Không cho phép update từ 1 về 0.
|
|
if old_status == 0 and new_status == 1:
|
|
# Check permissions in router, but logic here:
|
|
pass
|
|
elif old_status >= 1 and new_status == 0:
|
|
raise ValueError("Không thể chuyển trạng thái từ đã gửi về nháp.")
|
|
|
|
# Rule check: Update các trạng thái 2,3,4,5 thì chỉ nhóm Administator, Admin được phép.
|
|
if new_status in [2, 3, 4, 5] and not is_admin_user:
|
|
raise ValueError("Bạn không có quyền chuyển sang trạng thái này.")
|
|
|
|
# Rule check: Chỉ Admin/Administrator mới được cập nhật target_id
|
|
if obj_in.target_id is not None and not is_admin_user:
|
|
raise ValueError("Bạn không có quyền cập nhật target_id.")
|
|
|
|
# Rule check: list_process chỉ Admin/Administrator có quyền
|
|
if obj_in.list_process and not is_admin_user:
|
|
raise ValueError("Bạn không có quyền gán người dùng.")
|
|
|
|
data = obj_in.dict(exclude_unset=True)
|
|
list_process = data.pop("list_process", None)
|
|
other_assign = data.pop("other_assign", None)
|
|
|
|
# Nếu không phải admin, không cho phép cập nhật unit_id và user_id
|
|
if not is_admin_user:
|
|
data.pop("unit_id", None)
|
|
data.pop("user_id", None)
|
|
|
|
for k, v in data.items():
|
|
setattr(db_obj, k, v)
|
|
|
|
# Cập nhật danh sách gán nếu là admin
|
|
if list_process is not None or other_assign is not None:
|
|
# Xóa các gán cũ
|
|
db.query(models.PentestServiceAssign).filter(
|
|
models.PentestServiceAssign.pentest_service_id == id
|
|
).delete()
|
|
|
|
# Thêm các gán mới (user_id)
|
|
if list_process:
|
|
for uid in list_process:
|
|
db.add(models.PentestServiceAssign(
|
|
user_id=uid,
|
|
pentest_service_id=id
|
|
))
|
|
|
|
# Thêm các gán mới (email)
|
|
if other_assign:
|
|
for email in other_assign:
|
|
db.add(models.PentestServiceAssign(
|
|
email=email,
|
|
pentest_service_id=id
|
|
))
|
|
db.commit()
|
|
|
|
db.add(db_obj)
|
|
|
|
if old_status != new_status:
|
|
history = models.PentestServiceHistory(
|
|
pentest_service_id=id,
|
|
old_status=old_status,
|
|
new_status=new_status,
|
|
user_id=user_id
|
|
)
|
|
db.add(history)
|
|
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def delete_pentest_service(db: Session, id: int) -> bool:
|
|
db_obj = get_pentest_service(db, id)
|
|
if not db_obj:
|
|
return False
|
|
if db_obj.status != 0:
|
|
raise ValueError("Chỉ có thể xóa task ở trạng thái nháp.")
|
|
|
|
# Xóa comments liên quan
|
|
db.query(models.PentestServiceComment).filter(models.PentestServiceComment.pentest_service_id == id).delete()
|
|
|
|
# Xóa history liên quan
|
|
db.query(models.PentestServiceHistory).filter(models.PentestServiceHistory.pentest_service_id == id).delete()
|
|
|
|
# Xóa gán liên quan
|
|
db.query(models.PentestServiceAssign).filter(models.PentestServiceAssign.pentest_service_id == id).delete()
|
|
|
|
db.delete(db_obj)
|
|
db.commit()
|
|
return True
|
|
|
|
# Comment CRUD
|
|
def create_pentest_comment(db: Session, obj_in: schemas.PentestServiceCommentCreate, user_id: int) -> models.PentestServiceComment:
|
|
db_obj = models.PentestServiceComment(
|
|
**obj_in.dict(),
|
|
user_id=user_id
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def list_pentest_comments(db: Session, pentest_service_id: int) -> list[models.PentestServiceComment]:
|
|
return db.query(models.PentestServiceComment).filter(
|
|
models.PentestServiceComment.pentest_service_id == pentest_service_id
|
|
).order_by(models.PentestServiceComment.id.asc()).all()
|
|
|
|
def delete_pentest_comment(db: Session, id: int) -> bool:
|
|
db_obj = db.query(models.PentestServiceComment).filter(models.PentestServiceComment.id == id).first()
|
|
if not db_obj:
|
|
return False
|
|
db.delete(db_obj)
|
|
db.commit()
|
|
return True
|
|
|
|
# History CRUD
|
|
def list_pentest_histories(db: Session, pentest_service_id: int) -> list[models.PentestServiceHistory]:
|
|
return db.query(models.PentestServiceHistory).filter(
|
|
models.PentestServiceHistory.pentest_service_id == pentest_service_id
|
|
).order_by(models.PentestServiceHistory.id.desc()).all()
|
|
|
|
|
|
|
|
def list_roles(db: Session, skip: int = 0, limit: int = 100) -> List[models.Role]:
|
|
return db.query(models.Role).offset(skip).limit(limit).all()
|
|
|
|
|
|
def get_role(db: Session, role_id: int) -> Optional[models.Role]:
|
|
return db.query(models.Role).filter(models.Role.id == role_id).first()
|
|
|
|
|
|
def update_role(db: Session, role_id: int, role_in: schemas.RoleCreate) -> Optional[models.Role]:
|
|
"""Update a role by ID."""
|
|
db_obj = db.query(models.Role).filter(models.Role.id == role_id).first()
|
|
if not db_obj:
|
|
return None
|
|
db_obj.name = role_in.name
|
|
db_obj.description = role_in.description
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
|
|
def delete_role(db: Session, role_id: int) -> bool:
|
|
"""Delete a role by ID. Returns True if deleted, False if not found."""
|
|
db_obj = db.query(models.Role).filter(models.Role.id == role_id).first()
|
|
if not db_obj:
|
|
return False
|
|
db.delete(db_obj)
|
|
db.commit()
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
# Units & Users
|
|
def create_unit(db: Session, unit_in: schemas.UnitCreate) -> models.Unit:
|
|
db_obj = models.Unit(name=unit_in.name, description=unit_in.description)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
|
|
def list_units(db: Session, skip: int = 0, limit: int = 100) -> List[models.Unit]:
|
|
return db.query(models.Unit).offset(skip).limit(limit).all()
|
|
|
|
|
|
def get_unit(db: Session, unit_id: int) -> Optional[models.Unit]:
|
|
return db.query(models.Unit).filter(models.Unit.id == unit_id).first()
|
|
|
|
def update_unit(db: Session, unit_id: int, unit_in: schemas.UnitCreate) -> Optional[models.Unit]:
|
|
db_obj = db.query(models.Unit).filter(models.Unit.id == unit_id).first()
|
|
if not db_obj:
|
|
return None
|
|
db_obj.name = unit_in.name
|
|
db_obj.description = unit_in.description
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def delete_unit(db: Session, unit_id: int) -> bool:
|
|
db_obj = db.query(models.Unit).filter(models.Unit.id == unit_id).first()
|
|
if not db_obj:
|
|
return False
|
|
db.delete(db_obj)
|
|
db.commit()
|
|
return True
|
|
|
|
def create_user(db: Session, user_in: schemas.UserCreate) -> models.User:
|
|
hashed = None
|
|
if getattr(user_in, 'password', None):
|
|
pw = user_in.password or ""
|
|
email = user_in.email
|
|
if len(pw) < 8 or not re.search(r"[A-Z]", pw) or not re.search(r"[a-z]", pw) or not re.search(r"\d", pw) or not re.search(r"[^\w\s]", pw) or (email and email.lower() in pw.lower()):
|
|
raise ValueError("Mật khẩu không đủ mạnh")
|
|
hashed = hash_password(user_in.password)
|
|
db_obj = models.User(
|
|
email=user_in.email,
|
|
fullname=user_in.fullname,
|
|
unit_id=user_in.unit_id,
|
|
role_id=user_in.role_id,
|
|
hashed_password=hashed,
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
|
|
def get_user_by_email(db: Session, email: str) -> Optional[models.User]:
|
|
return db.query(models.User).filter(models.User.email == email).first()
|
|
|
|
|
|
def list_users(db: Session, skip: int = 0, limit: int = 100, unit_id: Optional[int] = None) -> List[models.User]:
|
|
query = db.query(models.User)
|
|
if unit_id is not None:
|
|
query = query.filter(models.User.unit_id == unit_id)
|
|
return query.order_by(models.User.id.desc()).offset(skip).limit(limit).all()
|
|
|
|
|
|
def search_users(db: Session, query: str, skip: int = 0, limit: int = 100) -> List[models.User]:
|
|
"""Search users by email or fullname."""
|
|
search = f"%{query}%"
|
|
return db.query(models.User).filter(
|
|
or_(
|
|
models.User.email.ilike(search),
|
|
models.User.fullname.ilike(search)
|
|
)
|
|
).order_by(models.User.id.desc()).offset(skip).limit(limit).all()
|
|
|
|
|
|
def get_user(db: Session, user_id: int) -> Optional[models.User]:
|
|
return db.query(models.User).filter(models.User.id == user_id).first()
|
|
|
|
def list_user_emails_by_role(db: Session, role_id: int) -> List[str]:
|
|
rows = db.query(models.User.email).filter(models.User.role_id == role_id).all()
|
|
return [r[0] for r in rows]
|
|
|
|
def update_user(db: Session, user_id: int, user_in: schemas.UserUpdate) -> Optional[models.User]:
|
|
db_obj = db.query(models.User).filter(models.User.id == user_id).first()
|
|
if not db_obj:
|
|
return None
|
|
|
|
if user_in.email and user_in.email != db_obj.email:
|
|
existing = db.query(models.User).filter(
|
|
models.User.email == user_in.email,
|
|
models.User.id != user_id
|
|
).first()
|
|
if existing:
|
|
raise ValueError("Email already registered")
|
|
db_obj.email = user_in.email
|
|
|
|
if user_in.fullname is not None:
|
|
db_obj.fullname = user_in.fullname
|
|
|
|
if user_in.unit_id is not None:
|
|
db_obj.unit_id = user_in.unit_id
|
|
if getattr(user_in, "role_id", None) is not None:
|
|
db_obj.role_id = user_in.role_id
|
|
|
|
if user_in.status is not None:
|
|
db_obj.status = user_in.status
|
|
|
|
if user_in.password:
|
|
pw = user_in.password or ""
|
|
email = user_in.email or db_obj.email
|
|
if len(pw) < 8 or not re.search(r"[A-Z]", pw) or not re.search(r"[a-z]", pw) or not re.search(r"\d", pw) or not re.search(r"[^\w\s]", pw) or (email and email.lower() in pw.lower()):
|
|
raise ValueError("Mật khẩu không đủ mạnh")
|
|
db_obj.hashed_password = hash_password(user_in.password)
|
|
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
|
|
# Category & Posts
|
|
def create_category(db: Session, cat_in: schemas.CategoryCreate) -> models.Category:
|
|
db_obj = models.Category(name=cat_in.name)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def list_categories(db: Session, skip: int = 0, limit: int = 100) -> List[models.Category]:
|
|
return db.query(models.Category).offset(skip).limit(limit).all()
|
|
|
|
# Thêm mới: CRUD cho Category
|
|
def get_category(db: Session, category_id: int) -> Optional[models.Category]:
|
|
return db.query(models.Category).filter(models.Category.id == category_id).first()
|
|
|
|
def get_category_by_name(db: Session, name: str) -> Optional[models.Category]:
|
|
return db.query(models.Category).filter(models.Category.name == name).first()
|
|
|
|
def update_category(db: Session, category_id: int, cat_in: schemas.CategoryCreate) -> Optional[models.Category]:
|
|
db_obj = db.query(models.Category).filter(models.Category.id == category_id).first()
|
|
if not db_obj:
|
|
return None
|
|
db_obj.name = cat_in.name
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def delete_category(db: Session, category_id: int) -> bool:
|
|
db_obj = db.query(models.Category).filter(models.Category.id == category_id).first()
|
|
if not db_obj:
|
|
return False
|
|
db.delete(db_obj)
|
|
db.commit()
|
|
return True
|
|
|
|
|
|
def create_post(db: Session, post_in: schemas.PostCreate) -> models.Post:
|
|
db_obj = models.Post(
|
|
content=post_in.content,
|
|
title=post_in.title,
|
|
created_by=post_in.created_by,
|
|
category_id=post_in.category_id,
|
|
status=post_in.status,
|
|
thumbnail=post_in.thumbnail,
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
|
|
def create_email_role(db: Session, obj_in: schemas.EmailRoleCreate) -> models.EmailRole:
|
|
db_obj = models.EmailRole(name=obj_in.name, description=obj_in.description)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def get_email_role(db: Session, id: int) -> models.EmailRole | None:
|
|
return db.query(models.EmailRole).filter(models.EmailRole.id == id).first()
|
|
|
|
def update_email_role(db: Session, id: int, obj_in: schemas.EmailRoleUpdate) -> models.EmailRole | None:
|
|
db_obj = get_email_role(db, id)
|
|
if not db_obj:
|
|
return None
|
|
data = obj_in.dict(exclude_unset=True)
|
|
for k, v in data.items():
|
|
setattr(db_obj, k, v)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def delete_email_role(db: Session, id: int) -> bool:
|
|
db_obj = get_email_role(db, id)
|
|
if not db_obj:
|
|
return False
|
|
db.delete(db_obj)
|
|
db.commit()
|
|
return True
|
|
|
|
def list_email_users_by_role(db: Session, role_id: int) -> list[models.EmailUser]:
|
|
return db.query(models.EmailUser).filter(models.EmailUser.role_id == role_id).all()
|
|
|
|
def list_email_users_by_role_paginated(
|
|
db: Session,
|
|
role_id: int,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
) -> list[models.EmailUser]:
|
|
return (
|
|
db.query(models.EmailUser)
|
|
.filter(models.EmailUser.role_id == role_id)
|
|
.order_by(models.EmailUser.id.desc())
|
|
.offset(skip)
|
|
.limit(limit)
|
|
.all()
|
|
)
|
|
|
|
def count_email_users_by_role(db: Session, role_id: int) -> int:
|
|
return int(db.query(func.count(models.EmailUser.id)).filter(models.EmailUser.role_id == role_id).scalar() or 0)
|
|
def list_email_roles(db: Session, skip: int = 0, limit: int = 100) -> list[models.EmailRole]:
|
|
return (
|
|
db.query(models.EmailRole)
|
|
.order_by(models.EmailRole.id.desc())
|
|
.offset(skip)
|
|
.limit(limit)
|
|
.all()
|
|
)
|
|
|
|
def create_email_user(db: Session, obj_in: schemas.EmailUserCreate) -> models.EmailUser:
|
|
db_obj = models.EmailUser(email=obj_in.email, name=obj_in.name, role_id=obj_in.role_id, type=obj_in.type)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def get_email_user(db: Session, id: int) -> models.EmailUser | None:
|
|
return db.query(models.EmailUser).filter(models.EmailUser.id == id).first()
|
|
|
|
def get_email_user_by_email_and_role(db: Session, email: str, role_id: int) -> models.EmailUser | None:
|
|
return (
|
|
db.query(models.EmailUser)
|
|
.filter(models.EmailUser.email == email, models.EmailUser.role_id == role_id)
|
|
.first()
|
|
)
|
|
|
|
def update_email_user(db: Session, id: int, obj_in: schemas.EmailUserUpdate) -> models.EmailUser | None:
|
|
db_obj = get_email_user(db, id)
|
|
if not db_obj:
|
|
return None
|
|
data = obj_in.dict(exclude_unset=True)
|
|
for k, v in data.items():
|
|
setattr(db_obj, k, v)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def delete_email_user(db: Session, id: int) -> bool:
|
|
db_obj = get_email_user(db, id)
|
|
if not db_obj:
|
|
return False
|
|
db.delete(db_obj)
|
|
db.commit()
|
|
return True
|
|
|
|
def list_email_users(
|
|
db: Session,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
role_id: Optional[int] = None,
|
|
) -> list[models.EmailUser]:
|
|
q = db.query(models.EmailUser)
|
|
if role_id is not None:
|
|
q = q.filter(models.EmailUser.role_id == role_id)
|
|
return q.order_by(models.EmailUser.id.desc()).offset(skip).limit(limit).all()
|
|
|
|
def list_posts(db: Session, skip: int = 0, limit: int = 100) -> List[models.Post]:
|
|
return (
|
|
db.query(models.Post)
|
|
.order_by(models.Post.id.desc())
|
|
.offset(skip)
|
|
.limit(limit)
|
|
.all()
|
|
)
|
|
|
|
def list_posts_by_category(db: Session, category_id: int, skip: int = 0, limit: int = 100) -> List[models.Post]:
|
|
return (
|
|
db.query(models.Post)
|
|
.filter(models.Post.category_id == category_id)
|
|
.order_by(models.Post.id.desc())
|
|
.offset(skip)
|
|
.limit(limit)
|
|
.all()
|
|
)
|
|
|
|
def get_user_fullname(db: Session, user_id: Optional[int]) -> Optional[str]:
|
|
if not user_id:
|
|
return None
|
|
user = db.query(models.User).filter(models.User.id == user_id).first()
|
|
return user.fullname if user else None
|
|
|
|
|
|
# Month & stats
|
|
def create_month(db: Session, m_in: schemas.MonthCreate) -> models.Month:
|
|
db_obj = models.Month(name=m_in.name, from_date=m_in.from_date, end_date=m_in.end_date)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
|
|
def list_months(db: Session, skip: int = 0, limit: int = 100) -> List[models.Month]:
|
|
return (
|
|
db.query(models.Month)
|
|
.order_by(models.Month.id.desc())
|
|
.offset(skip)
|
|
.limit(limit)
|
|
.all()
|
|
)
|
|
|
|
|
|
def get_month(db: Session, month_id: int) -> Optional[models.Month]:
|
|
return db.query(models.Month).filter(models.Month.id == month_id).first()
|
|
|
|
def update_month(db: Session, month_id: int, m_in: schemas.MonthCreate) -> Optional[models.Month]:
|
|
db_obj = db.query(models.Month).filter(models.Month.id == month_id).first()
|
|
if not db_obj:
|
|
return None
|
|
db_obj.name = m_in.name
|
|
db_obj.from_date = m_in.from_date
|
|
db_obj.end_date = m_in.end_date
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def delete_month(db: Session, month_id: int) -> bool:
|
|
db_obj = db.query(models.Month).filter(models.Month.id == month_id).first()
|
|
if not db_obj:
|
|
return False
|
|
db.delete(db_obj)
|
|
db.commit()
|
|
return True
|
|
|
|
|
|
def create_nac(db: Session, nac_in: schemas.NACCreate) -> models.NAC:
|
|
db_obj = models.NAC(month_id=nac_in.month_id, unit_id=nac_in.unit_id, total=nac_in.total, installed=nac_in.installed, ignored=nac_in.ignored)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
|
|
def get_nac_stats_by_month(db: Session, month_id: int) -> Dict[str, Any]:
|
|
total, installed, ignored, rate = db.query(
|
|
func.coalesce(func.sum(models.NAC.total), 0),
|
|
func.coalesce(func.sum(models.NAC.installed), 0),
|
|
func.coalesce(func.sum(models.NAC.ignored), 0),
|
|
func.coalesce(func.avg(models.NAC.rate), 0.0),
|
|
).filter(models.NAC.month_id == month_id).one()
|
|
return {
|
|
"total": int(total or 0),
|
|
"installed": int(installed or 0),
|
|
"ignored": int(ignored or 0),
|
|
"rate": round(float(rate or 0.0), 2),
|
|
}
|
|
|
|
|
|
def get_smartir_stats_by_month(db: Session, month_id: int) -> Dict[str, Any]:
|
|
total, installed, new_install, ignored, rate = db.query(
|
|
func.coalesce(func.sum(models.SmartIR.total), 0),
|
|
func.coalesce(func.sum(models.SmartIR.installed), 0),
|
|
func.coalesce(func.sum(models.SmartIR.new_install), 0),
|
|
func.coalesce(func.sum(models.SmartIR.ignored), 0),
|
|
func.coalesce(func.avg(models.SmartIR.rate), 0.0),
|
|
).filter(models.SmartIR.month_id == month_id).one()
|
|
return {
|
|
"total": int(total or 0),
|
|
"installed": int(installed or 0),
|
|
"new_install": int(new_install or 0),
|
|
"ignored": int(ignored or 0),
|
|
"rate": round(float(rate or 0.0), 2),
|
|
}
|
|
|
|
|
|
def get_nac_stats_by_month_grouped_by_unit(
|
|
db: Session, month_id: int, unit_id: Optional[int] = None
|
|
) -> List[Dict[str, Any]]:
|
|
q = db.query(
|
|
models.NAC.unit_id,
|
|
func.coalesce(func.sum(models.NAC.total), 0),
|
|
func.coalesce(func.sum(models.NAC.installed), 0),
|
|
func.coalesce(func.sum(models.NAC.ignored), 0),
|
|
func.coalesce(func.avg(models.NAC.rate), 0.0),
|
|
).filter(models.NAC.month_id == month_id)
|
|
if unit_id is not None:
|
|
q = q.filter(models.NAC.unit_id == unit_id)
|
|
rows = q.group_by(models.NAC.unit_id).order_by(models.NAC.unit_id.asc()).all()
|
|
data: List[Dict[str, Any]] = []
|
|
for uid, total, installed, ignored, rate in rows:
|
|
t = int(total or 0)
|
|
ins = int(installed or 0)
|
|
ign = int(ignored or 0)
|
|
data.append({
|
|
"unit_id": int(uid),
|
|
"unit_name": get_unit_name(db, int(uid)) if uid is not None else None,
|
|
"total": t,
|
|
"installed": ins,
|
|
"ignored": ign,
|
|
"rate": round(float(rate or 0.0), 2),
|
|
})
|
|
return data
|
|
|
|
# -------- SOC Target CRUD --------
|
|
SOC_STATUS_NAMES = {
|
|
0: "Open",
|
|
1: "In Progress",
|
|
2: "Resolved",
|
|
3: "Closed"
|
|
}
|
|
|
|
def generate_soc_code(db: Session) -> str:
|
|
now = datetime.datetime.now()
|
|
month_str = now.strftime("%Y%m")
|
|
prefix = f"SOC.{month_str}."
|
|
|
|
# Find the latest code for this month to avoid Duplicate Entry errors
|
|
last_record = db.query(models.SocTarget.code).filter(
|
|
models.SocTarget.code.like(f"{prefix}%")
|
|
).order_by(desc(models.SocTarget.code)).first()
|
|
|
|
if last_record:
|
|
try:
|
|
# Extract number from format SOC.YYYYMM.NNN
|
|
last_code = last_record[0]
|
|
num_part = last_code.split('.')[-1]
|
|
new_number = int(num_part) + 1
|
|
except (ValueError, IndexError):
|
|
# Fallback if parsing fails
|
|
new_number = db.query(models.SocTarget).filter(models.SocTarget.code.like(f"{prefix}%")).count() + 1
|
|
else:
|
|
new_number = 1
|
|
|
|
generated_code = f"{prefix}{new_number:03d}"
|
|
return generated_code
|
|
|
|
def calculate_deadline(priority: int) -> datetime.datetime:
|
|
now = datetime.datetime.utcnow()
|
|
if priority == 1:
|
|
return now + datetime.timedelta(hours=24)
|
|
elif priority == 2:
|
|
return now + datetime.timedelta(hours=48)
|
|
elif priority == 3:
|
|
return now + datetime.timedelta(days=5)
|
|
else:
|
|
return now + datetime.timedelta(days=7) # Default for other priorities
|
|
|
|
def get_sla_status(deadline: datetime.datetime, status: int, completion_time: Optional[datetime.datetime] = None) -> str:
|
|
if not deadline:
|
|
return "Trong hạn"
|
|
|
|
# Nếu đã Resolved (2) hoặc Closed (3), dùng thời gian hoàn thành để so sánh
|
|
if status >= 2:
|
|
if not completion_time:
|
|
return "Đúng hạn"
|
|
return "Đúng hạn" if completion_time <= deadline else "Quá hạn"
|
|
|
|
# Nếu chưa hoàn thành, dùng thời gian hiện tại để so sánh
|
|
now = datetime.datetime.utcnow()
|
|
if now > deadline:
|
|
return "Quá hạn"
|
|
|
|
if (deadline - now).total_seconds() < 24 * 3600: # Less than 24 hours
|
|
return "Sắp đến hạn"
|
|
|
|
return "Trong hạn"
|
|
|
|
def get_soc_completion_time(db: Session, target_id: int) -> Optional[datetime.datetime]:
|
|
# Lấy bản ghi lịch sử cập nhật status sang Resolved (2) hoặc Closed (3) gần nhất
|
|
history = db.query(models.SocTargetHistory).filter(
|
|
models.SocTargetHistory.target_id == target_id,
|
|
models.SocTargetHistory.field_name == "status",
|
|
models.SocTargetHistory.new_value.in_(["2", "3"])
|
|
).order_by(desc(models.SocTargetHistory.changed_at)).first()
|
|
|
|
return history.changed_at if history else None
|
|
|
|
def create_soc_target_attachment(db: Session, target_id: int, file_name: str, file_path: str, file_size: int, file_type: str, uploaded_by: int):
|
|
attachment = models.SocTargetAttachment(
|
|
target_id=target_id,
|
|
file_name=file_name,
|
|
file_path=file_path,
|
|
file_size=file_size,
|
|
file_type=file_type,
|
|
uploaded_by=uploaded_by
|
|
)
|
|
db.add(attachment)
|
|
db.commit()
|
|
db.refresh(attachment)
|
|
return attachment
|
|
|
|
def create_soc_target(db: Session, obj_in: schemas.SocTargetCreate, user_id: int) -> models.SocTarget:
|
|
obj_dict = obj_in.dict()
|
|
assign_internal = obj_dict.pop("assign_internal", None)
|
|
assign_external = obj_dict.pop("assign_external", None)
|
|
related_ticket_ids = obj_dict.pop("related_ticket_ids", None)
|
|
|
|
# Generate code if not provided
|
|
if not obj_in.code or obj_in.code.strip() == "":
|
|
obj_dict["code"] = generate_soc_code(db)
|
|
|
|
# Calculate deadline if not provided
|
|
if not obj_in.deadline:
|
|
obj_dict["deadline"] = calculate_deadline(obj_dict["priority"])
|
|
|
|
db_obj = models.SocTarget(**obj_dict, created_by=user_id)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
|
|
# Process related tickets
|
|
if related_ticket_ids:
|
|
r_ids = [r.strip() for r in related_ticket_ids.split(",") if r.strip()]
|
|
for r_id in r_ids:
|
|
try:
|
|
db.add(models.TicketRelated(
|
|
soc_target_id=db_obj.id,
|
|
related_soc_target_id=int(r_id)
|
|
))
|
|
except ValueError: pass
|
|
db.commit()
|
|
|
|
# Process assignees
|
|
if assign_internal:
|
|
uids = [u.strip() for u in assign_internal.split(",") if u.strip()]
|
|
for uid in uids:
|
|
try:
|
|
db.add(models.SocTargetAssign(
|
|
target_id=db_obj.id,
|
|
user_id=int(uid)
|
|
))
|
|
except ValueError:
|
|
pass
|
|
|
|
if assign_external:
|
|
emails = [e.strip() for e in assign_external.split(",") if e.strip()]
|
|
for email in emails:
|
|
db.add(models.SocTargetAssign(
|
|
target_id=db_obj.id,
|
|
email=email
|
|
))
|
|
|
|
if assign_internal or assign_external:
|
|
db.commit()
|
|
|
|
# Log history for creation
|
|
db.add(models.SocTargetHistory(
|
|
target_id=db_obj.id,
|
|
field_name="status",
|
|
new_value=str(db_obj.status),
|
|
changed_by=user_id
|
|
))
|
|
db.commit()
|
|
|
|
return db_obj
|
|
|
|
def get_soc_target(db: Session, target_id: int) -> models.SocTarget | None:
|
|
return db.query(models.SocTarget).filter(models.SocTarget.id == target_id).first()
|
|
|
|
def update_soc_target(db: Session, db_obj: models.SocTarget, obj_in: schemas.SocTargetUpdate, user_id: int) -> models.SocTarget:
|
|
old_data = {c.name: getattr(db_obj, c.name) for c in db_obj.__table__.columns}
|
|
|
|
update_data = obj_in.dict(exclude_unset=True)
|
|
assign_internal = update_data.pop("assign_internal", None)
|
|
assign_external = update_data.pop("assign_external", None)
|
|
related_ticket_ids = update_data.pop("related_ticket_ids", None)
|
|
|
|
for field, value in update_data.items():
|
|
if field in old_data and old_data[field] != value:
|
|
db.add(models.SocTargetHistory(
|
|
target_id=db_obj.id,
|
|
field_name=field,
|
|
old_value=str(old_data[field]) if old_data[field] is not None else None,
|
|
new_value=str(value) if value is not None else None,
|
|
changed_by=user_id
|
|
))
|
|
setattr(db_obj, field, value)
|
|
|
|
db.add(db_obj)
|
|
|
|
# Process related tickets if provided
|
|
if related_ticket_ids is not None:
|
|
db.query(models.TicketRelated).filter(models.TicketRelated.soc_target_id == db_obj.id).delete()
|
|
if related_ticket_ids:
|
|
r_ids = [r.strip() for r in related_ticket_ids.split(",") if r.strip()]
|
|
for r_id in r_ids:
|
|
try:
|
|
db.add(models.TicketRelated(soc_target_id=db_obj.id, related_soc_target_id=int(r_id)))
|
|
except ValueError: pass
|
|
db.commit()
|
|
|
|
# Process assignees if provided
|
|
if assign_internal is not None or assign_external is not None:
|
|
# Get existing assignees to preserve if one of the inputs is None
|
|
existing_assignees = db.query(models.SocTargetAssign).filter(models.SocTargetAssign.target_id == db_obj.id).all()
|
|
existing_internal = [str(a.user_id) for a in existing_assignees if a.user_id is not None]
|
|
existing_external = [a.email for a in existing_assignees if a.email is not None]
|
|
|
|
final_internal = assign_internal if assign_internal is not None else ",".join(existing_internal)
|
|
final_external = assign_external if assign_external is not None else ",".join(existing_external)
|
|
|
|
# Clear existing assignees
|
|
db.query(models.SocTargetAssign).filter(models.SocTargetAssign.target_id == db_obj.id).delete()
|
|
|
|
if final_internal:
|
|
uids = [u.strip() for u in final_internal.split(",") if u.strip()]
|
|
for uid in uids:
|
|
try:
|
|
db.add(models.SocTargetAssign(target_id=db_obj.id, user_id=int(uid)))
|
|
except ValueError: pass
|
|
|
|
if final_external:
|
|
emails = [e.strip() for e in final_external.split(",") if e.strip()]
|
|
for email in emails:
|
|
db.add(models.SocTargetAssign(target_id=db_obj.id, email=email))
|
|
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def delete_soc_target(db: Session, target_id: int):
|
|
# 1. Delete physical files and attachment records
|
|
attachments = db.query(models.SocTargetAttachment).filter(models.SocTargetAttachment.target_id == target_id).all()
|
|
for att in attachments:
|
|
if att.file_path and os.path.exists(att.file_path):
|
|
try:
|
|
os.remove(att.file_path)
|
|
except Exception:
|
|
pass
|
|
db.query(models.SocTargetAttachment).filter(models.SocTargetAttachment.target_id == target_id).delete(synchronize_session=False)
|
|
|
|
# 2. Delete related records in other tables
|
|
db.query(models.SocTargetComment).filter(models.SocTargetComment.target_id == target_id).delete(synchronize_session=False)
|
|
db.query(models.SocTargetHistory).filter(models.SocTargetHistory.target_id == target_id).delete(synchronize_session=False)
|
|
db.query(models.SocTargetAssign).filter(models.SocTargetAssign.target_id == target_id).delete(synchronize_session=False)
|
|
|
|
# 3. Delete the main ticket record
|
|
db.query(models.SocTarget).filter(models.SocTarget.id == target_id).delete(synchronize_session=False)
|
|
db.commit()
|
|
|
|
def list_soc_targets(
|
|
db: Session,
|
|
unit_id: int | None = None,
|
|
status: int | None = None,
|
|
priority: int | None = None,
|
|
sla_status: str | None = None,
|
|
from_date: datetime.datetime | None = None,
|
|
to_date: datetime.datetime | None = None,
|
|
q: str | None = None,
|
|
skip: int = 0,
|
|
limit: int = 10
|
|
):
|
|
query = db.query(models.SocTarget)
|
|
if unit_id is not None:
|
|
query = query.filter(models.SocTarget.unit_id == unit_id)
|
|
if status is not None:
|
|
query = query.filter(models.SocTarget.status == status)
|
|
if priority is not None:
|
|
query = query.filter(models.SocTarget.priority == priority)
|
|
if from_date:
|
|
query = query.filter(models.SocTarget.created_at >= from_date)
|
|
if to_date:
|
|
query = query.filter(models.SocTarget.created_at <= to_date)
|
|
|
|
if q:
|
|
search_filter = or_(
|
|
models.SocTarget.name.ilike(f"%{q}%"),
|
|
models.SocTarget.description.ilike(f"%{q}%"),
|
|
models.SocTarget.source_ip.ilike(f"%{q}%"),
|
|
models.SocTarget.destination_ip.ilike(f"%{q}%"),
|
|
models.SocTarget.id.in_(
|
|
db.query(models.SocTargetComment.target_id).filter(models.SocTargetComment.content.ilike(f"%{q}%"))
|
|
)
|
|
)
|
|
query = query.filter(search_filter)
|
|
|
|
query = query.order_by(desc(models.SocTarget.created_at))
|
|
|
|
if sla_status:
|
|
# If filtering by SLA status, we have to fetch more items to filter in memory
|
|
# This is a trade-off for complex calculated fields.
|
|
all_items = query.all()
|
|
filtered_items = []
|
|
for item in all_items:
|
|
completion_time = get_soc_completion_time(db, item.id) if item.status >= 2 else None
|
|
current_sla = get_sla_status(item.deadline, item.status, completion_time)
|
|
if current_sla == sla_status:
|
|
filtered_items.append(item)
|
|
|
|
total = len(filtered_items)
|
|
items = filtered_items[skip:skip+limit]
|
|
else:
|
|
total = query.count()
|
|
items = query.offset(skip).limit(limit).all()
|
|
|
|
return items, total
|
|
|
|
def get_soc_target_assignees(db: Session, target_id: int) -> List[models.SocTargetAssign]:
|
|
return db.query(models.SocTargetAssign).filter(models.SocTargetAssign.target_id == target_id).all()
|
|
|
|
def get_soc_target_attachments(db: Session, target_id: int) -> List[models.SocTargetAttachment]:
|
|
return db.query(models.SocTargetAttachment).filter(models.SocTargetAttachment.target_id == target_id).all()
|
|
|
|
def add_soc_comment(db: Session, target_id: int, content: str, user_id: int | None = None, email: str | None = None):
|
|
comment = models.SocTargetComment(
|
|
target_id=target_id,
|
|
content=content,
|
|
user_id=user_id,
|
|
email=email
|
|
)
|
|
db.add(comment)
|
|
db.commit()
|
|
db.refresh(comment)
|
|
return comment
|
|
|
|
def get_soc_comments(db: Session, target_id: int) -> List[models.SocTargetComment]:
|
|
return db.query(models.SocTargetComment).filter(models.SocTargetComment.target_id == target_id).order_by(models.SocTargetComment.created_at).all()
|
|
|
|
def get_soc_history(db: Session, target_id: int) -> List[models.SocTargetHistory]:
|
|
return db.query(models.SocTargetHistory).filter(models.SocTargetHistory.target_id == target_id).order_by(desc(models.SocTargetHistory.changed_at)).all()
|
|
|
|
def get_soc_last_updated_by(db: Session, target_id: int) -> Optional[int]:
|
|
"""Lấy ID của người cập nhật cuối cùng từ bảng history."""
|
|
last_history = db.query(models.SocTargetHistory).filter(
|
|
models.SocTargetHistory.target_id == target_id
|
|
).order_by(desc(models.SocTargetHistory.changed_at)).first()
|
|
return last_history.changed_by if last_history else None
|
|
|
|
def is_user_assigned_to_soc(db: Session, target_id: int, user_id: int) -> bool:
|
|
return db.query(models.SocTargetAssign).filter(
|
|
models.SocTargetAssign.target_id == target_id,
|
|
models.SocTargetAssign.user_id == user_id
|
|
).first() is not None
|
|
|
|
|
|
def get_smartir_stats_by_month_grouped_by_unit(
|
|
db: Session, month_id: int, unit_id: Optional[int] = None
|
|
) -> List[Dict[str, Any]]:
|
|
q = db.query(
|
|
models.SmartIR.unit_id,
|
|
func.coalesce(func.sum(models.SmartIR.total), 0),
|
|
func.coalesce(func.sum(models.SmartIR.installed), 0),
|
|
func.coalesce(func.sum(models.SmartIR.new_install), 0),
|
|
func.coalesce(func.sum(models.SmartIR.ignored), 0),
|
|
func.coalesce(func.avg(models.SmartIR.rate), 0.0),
|
|
).filter(models.SmartIR.month_id == month_id)
|
|
if unit_id is not None:
|
|
q = q.filter(models.SmartIR.unit_id == unit_id)
|
|
rows = q.group_by(models.SmartIR.unit_id).order_by(models.SmartIR.unit_id.asc()).all()
|
|
data: List[Dict[str, Any]] = []
|
|
for uid, total, installed, new_install, ignored, rate in rows:
|
|
t = int(total or 0)
|
|
ins = int(installed or 0)
|
|
newi = int(new_install or 0)
|
|
ign = int(ignored or 0)
|
|
data.append({
|
|
"unit_id": int(uid),
|
|
"unit_name": get_unit_name(db, int(uid)) if uid is not None else None,
|
|
"total": t,
|
|
"installed": ins,
|
|
"new_install": newi,
|
|
"ignored": ign,
|
|
"rate": round(float(rate or 0.0), 2),
|
|
})
|
|
return data
|
|
|
|
|
|
def get_compliance_stats_by_month_grouped_by_unit(
|
|
db: Session, month_id: int, unit_id: Optional[int] = None
|
|
) -> List[Dict[str, Any]]:
|
|
q = db.query(
|
|
models.Compliance.unit_id,
|
|
func.coalesce(func.sum(models.Compliance.windows_key), 0),
|
|
func.coalesce(func.sum(models.Compliance.office), 0),
|
|
func.coalesce(func.sum(models.Compliance.ms17010), 0),
|
|
func.coalesce(func.sum(models.Compliance.firewall), 0),
|
|
func.coalesce(func.sum(models.Compliance.uac), 0),
|
|
func.coalesce(func.sum(models.Compliance.winrar), 0),
|
|
func.coalesce(func.sum(models.Compliance.antivirus), 0),
|
|
func.coalesce(func.sum(models.Compliance.update_win), 0),
|
|
).filter(models.Compliance.month_id == month_id)
|
|
if unit_id is not None:
|
|
q = q.filter(models.Compliance.unit_id == unit_id)
|
|
rows = q.group_by(models.Compliance.unit_id).order_by(models.Compliance.unit_id.asc()).all()
|
|
data: List[Dict[str, Any]] = []
|
|
for (
|
|
uid,
|
|
windows_key,
|
|
office,
|
|
ms17010,
|
|
firewall,
|
|
uac,
|
|
winrar,
|
|
antivirus,
|
|
update_win,
|
|
) in rows:
|
|
data.append({
|
|
"unit_id": int(uid),
|
|
"unit_name": get_unit_name(db, int(uid)) if uid is not None else None,
|
|
"windows_key": int(windows_key or 0),
|
|
"office": int(office or 0),
|
|
"ms17010": int(ms17010 or 0),
|
|
"firewall": int(firewall or 0),
|
|
"uac": int(uac or 0),
|
|
"winrar": int(winrar or 0),
|
|
"antivirus": int(antivirus or 0),
|
|
"update_win": int(update_win or 0),
|
|
})
|
|
return data
|
|
|
|
|
|
# Post Comments CRUD
|
|
def create_post_comment(db: Session, post_id: int, user_id: int, content: str) -> models.PostComment:
|
|
comment = models.PostComment(
|
|
post_id=post_id,
|
|
user_id=user_id,
|
|
content=content
|
|
)
|
|
db.add(comment)
|
|
db.commit()
|
|
db.refresh(comment)
|
|
return comment
|
|
|
|
def get_post_comment(db: Session, comment_id: int) -> Optional[models.PostComment]:
|
|
return db.query(models.PostComment).filter(models.PostComment.id == comment_id).first()
|
|
|
|
def update_post_comment(db: Session, comment_id: int, content: str) -> Optional[models.PostComment]:
|
|
comment = db.query(models.PostComment).filter(models.PostComment.id == comment_id).first()
|
|
if comment:
|
|
comment.content = content
|
|
db.add(comment)
|
|
db.commit()
|
|
db.refresh(comment)
|
|
return comment
|
|
|
|
def delete_post_comment(db: Session, comment_id: int):
|
|
db.query(models.PostComment).filter(models.PostComment.id == comment_id).delete()
|
|
db.commit()
|
|
|
|
def list_post_comments(db: Session, post_id: int) -> List[models.PostComment]:
|
|
return db.query(models.PostComment).filter(models.PostComment.post_id == post_id).order_by(models.PostComment.created_at).all()
|
|
|
|
|
|
def get_compliance_heatmap_by_month(
|
|
db: Session, month_id: int, unit_id: Optional[int] = None
|
|
) -> Dict[str, Any]:
|
|
rows = get_compliance_stats_by_month_grouped_by_unit(db, month_id, unit_id=unit_id)
|
|
metrics = [
|
|
"ms17010",
|
|
"firewall",
|
|
"uac",
|
|
"winrar",
|
|
"antivirus",
|
|
"update_win",
|
|
]
|
|
units = [{"unit_id": r["unit_id"], "unit_name": r["unit_name"]} for r in rows]
|
|
values = [[int(r[m]) for m in metrics] for r in rows]
|
|
return {"metrics": metrics, "units": units, "values": values}
|
|
|
|
|
|
def get_attack_statics_by_month(db: Session, month_id: int) -> Dict[str, Any]:
|
|
siem_fintech, siem_media, ticket = db.query(
|
|
func.coalesce(func.sum(models.AttackStatics.siem_fintech), 0),
|
|
func.coalesce(func.sum(models.AttackStatics.siem_media), 0),
|
|
func.coalesce(func.sum(models.AttackStatics.ticket), 0),
|
|
).filter(models.AttackStatics.month_id == month_id).one()
|
|
return {
|
|
"siem_fintech": int(siem_fintech or 0),
|
|
"siem_media": int(siem_media or 0),
|
|
"ticket": int(ticket or 0),
|
|
}
|
|
|
|
|
|
def get_root_access_by_month_grouped_by_unit(
|
|
db: Session, month_id: int, unit_id: Optional[int] = None
|
|
) -> List[Dict[str, Any]]:
|
|
q = db.query(
|
|
models.RootAccess.unit_id,
|
|
func.coalesce(func.sum(models.RootAccess.number), 0),
|
|
).filter(models.RootAccess.month_id == month_id)
|
|
if unit_id is not None:
|
|
q = q.filter(models.RootAccess.unit_id == unit_id)
|
|
rows = q.group_by(models.RootAccess.unit_id).order_by(models.RootAccess.unit_id.asc()).all()
|
|
data: List[Dict[str, Any]] = []
|
|
for uid, number in rows:
|
|
data.append({
|
|
"unit_id": int(uid),
|
|
"unit_name": get_unit_name(db, int(uid)) if uid is not None else None,
|
|
"number": int(number or 0),
|
|
})
|
|
return data
|
|
|
|
|
|
# Ticket
|
|
def create_ticket(db: Session, t_in: schemas.TicketCreate) -> models.Ticket:
|
|
db_obj = models.Ticket(unit_id=t_in.unit_id, month_id=t_in.month_id, open_count=t_in.open_count, in_process=t_in.in_process, completed=t_in.completed)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
|
|
# Mail & uploads
|
|
def create_mail_history(db: Session, m_in: schemas.MailHistoryCreate) -> models.MailHistory:
|
|
db_obj = models.MailHistory(
|
|
post_id=m_in.post_id,
|
|
subject=m_in.subject,
|
|
role_id=m_in.role_id,
|
|
content=m_in.content,
|
|
status=m_in.status,
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
# def list_mail_histories(
|
|
# db: Session,
|
|
# skip: int = 0,
|
|
# limit: int = 100,
|
|
# role_id: Optional[int] = None,
|
|
# post_id: Optional[int] = None,
|
|
# subject: Optional[str] = None,
|
|
# ) -> List[models.MailHistory]:
|
|
# q = db.query(models.MailHistory)
|
|
# if role_id is not None:
|
|
# q = q.filter(models.MailHistory.role_id == role_id)
|
|
# if post_id is not None:
|
|
# q = q.filter(models.MailHistory.post_id == post_id)
|
|
# if subject is not None:
|
|
# q = q.filter(models.MailHistory.subject == subject)
|
|
# return q.order_by(models.MailHistory.id.desc()).offset(skip).limit(limit).all()
|
|
|
|
def get_mail_history(db: Session, mh_id: int) -> Optional[models.MailHistory]:
|
|
return db.query(models.MailHistory).filter(models.MailHistory.id == mh_id).first()
|
|
|
|
def list_mail_histories(
|
|
db: Session,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
role_id: Optional[int] = None,
|
|
post_id: Optional[int] = None,
|
|
subject: Optional[str] = None,
|
|
):
|
|
q = db.query(
|
|
models.MailHistory.id,
|
|
models.MailHistory.subject,
|
|
models.MailHistory.role_id,
|
|
models.MailHistory.post_id,
|
|
models.MailHistory.status,
|
|
models.MailHistory.created_at,
|
|
)
|
|
|
|
if role_id is not None:
|
|
q = q.filter(models.MailHistory.role_id == role_id)
|
|
if post_id is not None:
|
|
q = q.filter(models.MailHistory.post_id == post_id)
|
|
if subject is not None:
|
|
q = q.filter(models.MailHistory.subject == subject)
|
|
|
|
return (
|
|
q.order_by(desc(models.MailHistory.id))
|
|
.offset(skip)
|
|
.limit(limit)
|
|
.all()
|
|
)
|
|
|
|
def update_mail_history(db: Session, mh_id: int, m_in: schemas.MailHistoryUpdate) -> Optional[models.MailHistory]:
|
|
db_obj = db.query(models.MailHistory).filter(models.MailHistory.id == mh_id).first()
|
|
if not db_obj:
|
|
return None
|
|
if m_in.post_id is not None:
|
|
db_obj.post_id = m_in.post_id
|
|
if m_in.subject is not None:
|
|
db_obj.subject = m_in.subject
|
|
if m_in.role_id is not None:
|
|
db_obj.role_id = m_in.role_id
|
|
if m_in.content is not None:
|
|
db_obj.content = m_in.content
|
|
if m_in.status is not None:
|
|
db_obj.status = m_in.status
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def delete_mail_history(db: Session, mh_id: int) -> bool:
|
|
db_obj = db.query(models.MailHistory).filter(models.MailHistory.id == mh_id).first()
|
|
if not db_obj:
|
|
return False
|
|
db.delete(db_obj)
|
|
db.commit()
|
|
return True
|
|
def create_file_upload(db: Session, f_in: schemas.FileUploadCreate) -> models.FileUpload:
|
|
db_obj = models.FileUpload(path=f_in.path, table_name=f_in.table_name, table_id=f_in.table_id)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def create_import_history(db: Session, obj_in: schemas.ImportHistoryCreate) -> models.ImportHistory:
|
|
db_obj = models.ImportHistory(type=obj_in.type, file_path=obj_in.file_path, month_id=obj_in.month_id)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def list_import_history(
|
|
db: Session,
|
|
type: Optional[str] = None,
|
|
month_id: Optional[int] = None,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
) -> list[models.ImportHistory]:
|
|
q = db.query(models.ImportHistory)
|
|
if type is not None:
|
|
q = q.filter(models.ImportHistory.type == type)
|
|
if month_id is not None:
|
|
q = q.filter(models.ImportHistory.month_id == month_id)
|
|
return q.order_by(models.ImportHistory.id.desc()).offset(skip).limit(limit).all()
|
|
|
|
|
|
def delete_user(db: Session, user_id: int) -> bool:
|
|
db_obj = db.query(models.User).filter(models.User.id == user_id).first()
|
|
if not db_obj:
|
|
return False
|
|
db.delete(db_obj)
|
|
db.commit()
|
|
return True
|
|
|
|
|
|
def get_post(db: Session, post_id: int) -> Optional[models.Post]:
|
|
return db.query(models.Post).filter(models.Post.id == post_id).first()
|
|
|
|
def update_post(db: Session, post_id: int, post_in: schemas.PostUpdate) -> Optional[models.Post]:
|
|
db_obj = db.query(models.Post).filter(models.Post.id == post_id).first()
|
|
if not db_obj:
|
|
return None
|
|
|
|
if post_in.content is not None:
|
|
db_obj.content = post_in.content
|
|
if post_in.title is not None:
|
|
db_obj.title = post_in.title
|
|
if post_in.created_by is not None:
|
|
db_obj.created_by = post_in.created_by
|
|
if post_in.category_id is not None:
|
|
db_obj.category_id = post_in.category_id
|
|
if post_in.status is not None:
|
|
db_obj.status = post_in.status
|
|
if post_in.thumbnail is not None:
|
|
db_obj.thumbnail = post_in.thumbnail
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def delete_post(db: Session, post_id: int) -> bool:
|
|
db_obj = db.query(models.Post).filter(models.Post.id == post_id).first()
|
|
if not db_obj:
|
|
return False
|
|
db.delete(db_obj)
|
|
db.commit()
|
|
return True
|
|
|
|
def delete_file_upload_by_path(db: Session, path: str) -> bool:
|
|
obj = db.query(models.FileUpload).filter(models.FileUpload.path == path).first()
|
|
if not obj:
|
|
return False
|
|
db.delete(obj)
|
|
db.commit()
|
|
return True
|
|
|
|
def delete_file_upload_by_filename(db: Session, filename: str) -> bool:
|
|
obj = db.query(models.FileUpload).filter(models.FileUpload.path == filename).first()
|
|
if not obj:
|
|
return False
|
|
db.delete(obj)
|
|
db.commit()
|
|
return True
|
|
|
|
def create_document(db: Session, obj_in: schemas.DocumentCreate) -> models.Document:
|
|
db_obj = models.Document(
|
|
name=obj_in.name,
|
|
number_doc=obj_in.number_doc,
|
|
sign_date=obj_in.sign_date,
|
|
level=obj_in.level,
|
|
validate_date=obj_in.validate_date,
|
|
file_path=obj_in.file_path,
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def get_document(db: Session, id: int) -> models.Document | None:
|
|
return db.query(models.Document).filter(models.Document.id == id).first()
|
|
|
|
def update_document(db: Session, id: int, obj_in: schemas.DocumentUpdate) -> models.Document | None:
|
|
db_obj = get_document(db, id)
|
|
if not db_obj:
|
|
return None
|
|
data = obj_in.dict(exclude_unset=True)
|
|
for k, v in data.items():
|
|
setattr(db_obj, k, v)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def delete_document(db: Session, id: int) -> bool:
|
|
db_obj = get_document(db, id)
|
|
if not db_obj:
|
|
return False
|
|
db.delete(db_obj)
|
|
db.commit()
|
|
return True
|
|
|
|
def list_documents(
|
|
db: Session,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
) -> list[models.Document]:
|
|
return (
|
|
db.query(models.Document)
|
|
.order_by(models.Document.id.desc())
|
|
.offset(skip)
|
|
.limit(limit)
|
|
.all()
|
|
)
|
|
|
|
def list_file_filenames(db: Session, table_name: str, table_id: int) -> List[str]:
|
|
q = db.query(models.FileUpload).filter(
|
|
models.FileUpload.table_name == table_name,
|
|
models.FileUpload.table_id == table_id
|
|
).all()
|
|
return [f.path for f in q]
|
|
|
|
|
|
def create_mm_fintech(db: Session, obj_in: schemas.MMFintechCreate) -> models.MMFintech:
|
|
db_obj = models.MMFintech(
|
|
month_id=obj_in.month_id,
|
|
unit_id=obj_in.unit_id,
|
|
file_path=obj_in.file_path,
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def search_documents(db: Session, keyword: str, skip: int = 0, limit: int = 100) -> list[models.Document]:
|
|
pattern = f"%{keyword}%"
|
|
return (
|
|
db.query(models.Document)
|
|
.filter(
|
|
or_(
|
|
models.Document.name.ilike(pattern),
|
|
models.Document.number_doc.ilike(pattern),
|
|
)
|
|
)
|
|
.order_by(models.Document.id.desc())
|
|
.offset(skip)
|
|
.limit(limit)
|
|
.all()
|
|
)
|
|
|
|
def list_mm_fintech(
|
|
db: Session,
|
|
month_id: int,
|
|
unit_id: int | None = None,
|
|
skip: int = 0,
|
|
limit: int | None = 100,
|
|
) -> List[models.MMFintech]:
|
|
q = db.query(models.MMFintech).filter(models.MMFintech.month_id == month_id)
|
|
if unit_id is not None:
|
|
q = q.filter(models.MMFintech.unit_id == unit_id)
|
|
q = q.order_by(models.MMFintech.id.desc()).offset(skip)
|
|
if limit is not None:
|
|
q = q.limit(limit)
|
|
return q.all()
|
|
|
|
def get_mm_fintech(db: Session, item_id: int) -> models.MMFintech | None:
|
|
return db.query(models.MMFintech).filter(models.MMFintech.id == item_id).first()
|
|
|
|
def get_mm_fintech_latest_by_month(db: Session, month_id: int) -> models.MMFintech | None:
|
|
return (
|
|
db.query(models.MMFintech)
|
|
.filter(models.MMFintech.month_id == month_id)
|
|
.order_by(models.MMFintech.id.desc())
|
|
.first()
|
|
)
|
|
|
|
def delete_mm_fintech(db: Session, item_id: int) -> bool:
|
|
obj = get_mm_fintech(db, item_id)
|
|
if not obj:
|
|
return False
|
|
db.delete(obj)
|
|
db.commit()
|
|
return True
|
|
|
|
def create_convert_hardening(db: Session, obj_in: schemas.ConvertHardeningCreate) -> models.ConvertHardening:
|
|
db_obj = models.ConvertHardening(filename=obj_in.filename, user_id=obj_in.user_id)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def list_convert_hardening_by_user(db: Session, user_id: int, skip: int = 0, limit: int = 100) -> list[models.ConvertHardening]:
|
|
return (
|
|
db.query(models.ConvertHardening)
|
|
.filter(models.ConvertHardening.user_id == user_id)
|
|
.order_by(models.ConvertHardening.id.desc())
|
|
.offset(skip)
|
|
.limit(limit)
|
|
.all()
|
|
)
|
|
|
|
def get_convert_hardening(db: Session, item_id: int) -> models.ConvertHardening | None:
|
|
return db.query(models.ConvertHardening).filter(models.ConvertHardening.id == item_id).first()
|
|
|
|
|
|
|
|
# -------- SystemGroup CRUD --------
|
|
def create_system_group(db: Session, obj_in: schemas.SystemGroupCreate) -> models.SystemGroup:
|
|
db_obj = models.SystemGroup(**obj_in.dict())
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def list_system_groups(db: Session, name: str | None = None, skip: int = 0, limit: int = 100) -> list[models.SystemGroup]:
|
|
sg = models.SystemGroup
|
|
sys = models.System
|
|
query = (
|
|
db.query(sg, func.count(sys.id).label("count"))
|
|
.outerjoin(sys, sg.id == sys.system_group_id)
|
|
)
|
|
if name:
|
|
query = query.filter(sg.name.ilike(f"%{name}%"))
|
|
rows = (
|
|
query.group_by(sg.id)
|
|
.order_by(sg.id.desc())
|
|
.offset(skip)
|
|
.limit(limit)
|
|
.all()
|
|
)
|
|
items: list[models.SystemGroup] = []
|
|
for obj, cnt in rows:
|
|
setattr(obj, "count", int(cnt or 0))
|
|
items.append(obj)
|
|
return items
|
|
|
|
def get_system_group(db: Session, id: int) -> models.SystemGroup | None:
|
|
return db.query(models.SystemGroup).filter(models.SystemGroup.id == id).first()
|
|
|
|
def update_system_group(db: Session, id: int, obj_in: schemas.SystemGroupUpdate) -> models.SystemGroup | None:
|
|
db_obj = get_system_group(db, id)
|
|
if not db_obj:
|
|
return None
|
|
data = obj_in.dict(exclude_unset=True)
|
|
for k, v in data.items():
|
|
setattr(db_obj, k, v)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def delete_system_group(db: Session, id: int) -> bool:
|
|
db_obj = get_system_group(db, id)
|
|
if not db_obj:
|
|
return False
|
|
db.delete(db_obj)
|
|
db.commit()
|
|
return True
|
|
|
|
# -------- System CRUD --------
|
|
def create_system(db: Session, obj_in: schemas.SystemCreate) -> models.System:
|
|
db_obj = models.System(**obj_in.dict())
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def list_systems(
|
|
db: Session,
|
|
name: str | None = None,
|
|
url_ip: str | None = None,
|
|
unit_id: int | None = None,
|
|
system_group_id: int | None = None,
|
|
status: int | None = None,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
) -> list[models.System]:
|
|
query = db.query(models.System)
|
|
if name:
|
|
query = query.filter(models.System.name.ilike(f"%{name}%"))
|
|
if url_ip:
|
|
query = query.filter(models.System.url_ip.ilike(f"%{url_ip}%"))
|
|
if unit_id is not None:
|
|
query = query.filter(models.System.unit_id == unit_id)
|
|
if system_group_id is not None:
|
|
query = query.filter(models.System.system_group_id == system_group_id)
|
|
if status is not None:
|
|
query = query.filter(models.System.status == status)
|
|
return query.order_by(models.System.id.desc()).offset(skip).limit(limit).all()
|
|
|
|
def get_system(db: Session, id: int) -> models.System | None:
|
|
return db.query(models.System).filter(models.System.id == id).first()
|
|
|
|
def update_system(db: Session, id: int, obj_in: schemas.SystemUpdate) -> models.System | None:
|
|
db_obj = get_system(db, id)
|
|
if not db_obj:
|
|
return None
|
|
data = obj_in.dict(exclude_unset=True)
|
|
for k, v in data.items():
|
|
setattr(db_obj, k, v)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def delete_system(db: Session, id: int) -> bool:
|
|
db_obj = get_system(db, id)
|
|
if not db_obj:
|
|
return False
|
|
db.delete(db_obj)
|
|
db.commit()
|
|
return True
|
|
|
|
def search_systems_by_url_ip(db: Session, url_ip: str, skip: int = 0, limit: int = 100) -> list[models.System]:
|
|
return (
|
|
db.query(models.System)
|
|
.filter(models.System.url_ip.ilike(f"%{url_ip}%"))
|
|
.order_by(models.System.id.desc())
|
|
.offset(skip)
|
|
.limit(limit)
|
|
.all()
|
|
)
|
|
|
|
# -------- ManageSystem CRUD --------
|
|
def get_manage_system(db: Session, id: int) -> models.ManageSystem | None:
|
|
return db.query(models.ManageSystem).filter(models.ManageSystem.id == id).first()
|
|
|
|
def get_manage_system_by_name(db: Session, name: str) -> models.ManageSystem | None:
|
|
return db.query(models.ManageSystem).filter(models.ManageSystem.name == name).first()
|
|
|
|
def create_manage_system(db: Session, obj_in: schemas.ManageSystemCreate) -> models.ManageSystem:
|
|
db_obj = models.ManageSystem(**obj_in.dict())
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def update_manage_system(db: Session, id: int, obj_in: schemas.ManageSystemUpdate) -> models.ManageSystem | None:
|
|
db_obj = get_manage_system(db, id)
|
|
if not db_obj:
|
|
return None
|
|
data = obj_in.dict(exclude_unset=True)
|
|
for k, v in data.items():
|
|
setattr(db_obj, k, v)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def delete_manage_system(db: Session, id: int) -> bool:
|
|
db_obj = get_manage_system(db, id)
|
|
if not db_obj:
|
|
return False
|
|
db.delete(db_obj)
|
|
db.commit()
|
|
return True
|
|
|
|
def list_manage_systems(
|
|
db: Session,
|
|
unit_id: int | None = None,
|
|
parent_id: int | None = None,
|
|
level: int | None = None,
|
|
q: str | None = None,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
) -> list[models.ManageSystem]:
|
|
query = db.query(models.ManageSystem)
|
|
if unit_id is not None:
|
|
query = query.filter(models.ManageSystem.unit_id == unit_id)
|
|
if parent_id is not None:
|
|
query = query.filter(models.ManageSystem.parent_id == parent_id)
|
|
if level is not None:
|
|
query = query.filter(models.ManageSystem.level == level)
|
|
if q:
|
|
like = f"%{q}%"
|
|
query = query.filter(or_(models.ManageSystem.name.ilike(like), models.ManageSystem.url_ip.ilike(like)))
|
|
return query.order_by(models.ManageSystem.id.desc()).offset(skip).limit(limit).all()
|
|
|
|
def create_log_source(db: Session, obj_in: schemas.LogSourceCreate) -> models.LogSource:
|
|
db_obj = models.LogSource(
|
|
month_id=obj_in.month_id,
|
|
unit_id=obj_in.unit_id,
|
|
log_id=obj_in.log_id,
|
|
name=obj_in.name,
|
|
description=obj_in.description,
|
|
is_enabled=obj_in.is_enabled if obj_in.is_enabled is not None else True,
|
|
source_type_id=obj_in.source_type_id,
|
|
status=obj_in.status, # lưu số
|
|
message=obj_in.message,
|
|
other=obj_in.other,
|
|
file_id=obj_in.file_id,
|
|
created_at=obj_in.created_at if getattr(obj_in, "created_at", None) is not None else None,
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def list_log_sources_by_month(
|
|
db: Session,
|
|
month_id: int,
|
|
unit_id: int | None = None,
|
|
is_enabled: bool | None = None,
|
|
status: int | None = None,
|
|
file_id: int | None = None,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
) -> list[models.LogSource]:
|
|
q = db.query(models.LogSource).filter(models.LogSource.month_id == month_id)
|
|
if unit_id is not None:
|
|
q = q.filter(models.LogSource.unit_id == unit_id)
|
|
if is_enabled is not None:
|
|
q = q.filter(models.LogSource.is_enabled == is_enabled)
|
|
if status is not None:
|
|
try:
|
|
q = q.filter(models.LogSource.status == int(status))
|
|
except Exception:
|
|
pass
|
|
if file_id is not None:
|
|
q = q.filter(models.LogSource.file_id == file_id)
|
|
return q.order_by(models.LogSource.id.desc()).offset(skip).limit(limit).all()
|
|
|
|
def get_log_source_filenames_by_month(db: Session, month_id: int) -> List[Dict[str, Any]]:
|
|
# Get all unique file_ids for logsource in this month
|
|
file_ids = db.query(models.LogSource.file_id).filter(
|
|
models.LogSource.month_id == month_id,
|
|
models.LogSource.file_id.isnot(None)
|
|
).distinct().all()
|
|
|
|
ids = [f[0] for f in file_ids]
|
|
if not ids:
|
|
return []
|
|
|
|
# Join with ImportHistory to get file paths/names
|
|
histories = db.query(models.ImportHistory).filter(models.ImportHistory.id.in_(ids)).all()
|
|
return [{"file_id": h.id, "filename": h.file_path, "created_at": h.created_at} for h in histories]
|
|
|
|
def delete_log_sources_by_file_id(db: Session, file_id: int) -> int:
|
|
# Get all logsource IDs belonging to this file_id
|
|
ls_ids = [r[0] for r in db.query(models.LogSource.id).filter(models.LogSource.file_id == file_id).all()]
|
|
|
|
# Delete all comments associated with these logsource IDs
|
|
if ls_ids:
|
|
db.query(models.LogSourceComment).filter(models.LogSourceComment.logsource_id.in_(ls_ids)).delete(synchronize_session=False)
|
|
|
|
# Delete the logsource records
|
|
cnt = db.query(models.LogSource).filter(models.LogSource.file_id == file_id).delete(synchronize_session=False)
|
|
|
|
# Delete from import_history
|
|
db.query(models.ImportHistory).filter(models.ImportHistory.id == file_id).delete(synchronize_session=False)
|
|
|
|
db.commit()
|
|
return int(cnt or 0)
|
|
|
|
def add_logsource_comment(db: Session, logsource_id: int, user_id: int, comment_text: str) -> models.LogSourceComment:
|
|
db_obj = models.LogSourceComment(
|
|
logsource_id=logsource_id,
|
|
user_id=user_id,
|
|
comment=comment_text
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def get_logsource_comments(db: Session, logsource_id: int) -> List[models.LogSourceComment]:
|
|
return db.query(models.LogSourceComment).filter(
|
|
models.LogSourceComment.logsource_id == logsource_id
|
|
).order_by(models.LogSourceComment.created_at.asc()).all()
|
|
|
|
|
|
def get_log_source_stats_by_month(
|
|
db: Session,
|
|
month_id: int,
|
|
unit_id: int | None = None,
|
|
is_enabled: bool | None = None,
|
|
) -> Dict[str, Any]:
|
|
q = db.query(models.LogSource).filter(models.LogSource.month_id == month_id)
|
|
if unit_id is not None:
|
|
q = q.filter(models.LogSource.unit_id == unit_id)
|
|
if is_enabled is not None:
|
|
q = q.filter(models.LogSource.is_enabled == is_enabled)
|
|
total = q.count()
|
|
q_enabled = db.query(func.count(models.LogSource.id)).filter(models.LogSource.month_id == month_id, models.LogSource.is_enabled == True)
|
|
q_disabled = db.query(func.count(models.LogSource.id)).filter(models.LogSource.month_id == month_id, models.LogSource.is_enabled == False)
|
|
if unit_id is not None:
|
|
q_enabled = q_enabled.filter(models.LogSource.unit_id == unit_id)
|
|
q_disabled = q_disabled.filter(models.LogSource.unit_id == unit_id)
|
|
enabled_count = q_enabled.scalar() or 0
|
|
disabled_count = q_disabled.scalar() or 0
|
|
status_rows = db.query(models.LogSource.status, func.count(models.LogSource.id)).filter(models.LogSource.month_id == month_id)
|
|
if unit_id is not None:
|
|
status_rows = status_rows.filter(models.LogSource.unit_id == unit_id)
|
|
if is_enabled is not None:
|
|
status_rows = status_rows.filter(models.LogSource.is_enabled == is_enabled)
|
|
status_rows = status_rows.group_by(models.LogSource.status).all()
|
|
by_status: Dict[int, int] = {int(s or 0): int(c or 0) for s, c in status_rows}
|
|
return {
|
|
"total": int(total or 0),
|
|
"enabled": int(enabled_count or 0),
|
|
"disabled": int(disabled_count or 0),
|
|
"by_status": by_status,
|
|
}
|
|
|
|
def get_log_source_status_by_month_grouped_by_unit(
|
|
db: Session,
|
|
month_id: int,
|
|
) -> List[Dict[str, Any]]:
|
|
rows = (
|
|
db.query(models.LogSource.unit_id, models.LogSource.status, func.count(models.LogSource.id))
|
|
.filter(models.LogSource.month_id == month_id)
|
|
.group_by(models.LogSource.unit_id, models.LogSource.status)
|
|
.all()
|
|
)
|
|
acc: Dict[int, Dict[int, int]] = {}
|
|
for uid, status, cnt in rows:
|
|
u = int(uid) if uid is not None else None
|
|
s = int(status or 0)
|
|
c = int(cnt or 0)
|
|
if u is None:
|
|
continue
|
|
if u not in acc:
|
|
acc[u] = {}
|
|
acc[u][s] = acc[u].get(s, 0) + c
|
|
result: List[Dict[str, Any]] = []
|
|
for uid, stmap in acc.items():
|
|
result.append({
|
|
"unit_id": uid,
|
|
"unit_name": get_unit_name(db, uid),
|
|
"by_status": {
|
|
1: int(stmap.get(1, 0)),
|
|
2: int(stmap.get(2, 0)),
|
|
3: int(stmap.get(3, 0)),
|
|
4: int(stmap.get(4, 0)),
|
|
},
|
|
})
|
|
return result
|
|
|
|
def delete_log_sources_by_month(db: Session, month_id: int) -> int:
|
|
# Get all logsource IDs belonging to this month_id
|
|
ls_ids = [r[0] for r in db.query(models.LogSource.id).filter(models.LogSource.month_id == month_id).all()]
|
|
|
|
# Delete all comments associated with these logsource IDs
|
|
if ls_ids:
|
|
db.query(models.LogSourceComment).filter(models.LogSourceComment.logsource_id.in_(ls_ids)).delete(synchronize_session=False)
|
|
|
|
# Delete the logsource records
|
|
cnt = db.query(models.LogSource).filter(models.LogSource.month_id == month_id).delete(synchronize_session=False)
|
|
|
|
# Delete from import_history (only type logsource)
|
|
db.query(models.ImportHistory).filter(models.ImportHistory.month_id == month_id).filter(models.ImportHistory.type == "logsource").delete(synchronize_session=False)
|
|
|
|
db.commit()
|
|
return int(cnt or 0)
|
|
|
|
def create_smartir_detail(db: Session, obj_in: schemas.SmartIRDetailCreate) -> models.SmartIRDetail:
|
|
db_obj = models.SmartIRDetail(
|
|
month_id=obj_in.month_id,
|
|
unit_id=obj_in.unit_id,
|
|
vnpt_ma_nhan_vien=obj_in.vnpt_ma_nhan_vien,
|
|
name=obj_in.name,
|
|
email=obj_in.email,
|
|
phong_ban=obj_in.phong_ban,
|
|
ip=obj_in.ip,
|
|
pc_name=obj_in.pc_name,
|
|
mac=obj_in.mac,
|
|
agent_version=obj_in.agent_version,
|
|
last_online=obj_in.last_online,
|
|
status=obj_in.status,
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def list_smartir_detail_by_month(
|
|
db: Session,
|
|
month_id: int,
|
|
unit_id: Optional[int] = None,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
) -> List[models.SmartIRDetail]:
|
|
q = db.query(models.SmartIRDetail).filter(models.SmartIRDetail.month_id == month_id)
|
|
if unit_id is not None:
|
|
q = q.filter(models.SmartIRDetail.unit_id == unit_id)
|
|
return q.order_by(models.SmartIRDetail.id.desc()).offset(skip).limit(limit).all()
|
|
|
|
def upsert_smartir_by_month_unit(
|
|
db: Session,
|
|
month_id: int,
|
|
unit_id: int,
|
|
total: int,
|
|
installed: int,
|
|
new_install: int,
|
|
ignored: int,
|
|
rate: float,
|
|
created_at: Optional[datetime.datetime] = None,
|
|
) -> models.SmartIR:
|
|
existing = (
|
|
db.query(models.SmartIR)
|
|
.filter(models.SmartIR.month_id == month_id)
|
|
.filter(models.SmartIR.unit_id == unit_id)
|
|
.first()
|
|
)
|
|
if existing:
|
|
existing.total = int(total or 0)
|
|
existing.installed = int(installed or 0)
|
|
existing.new_install = int(new_install or 0)
|
|
existing.ignored = int(ignored or 0)
|
|
existing.rate = float(rate or 0.0)
|
|
if created_at:
|
|
existing.created_at = created_at
|
|
db.add(existing)
|
|
db.commit()
|
|
db.refresh(existing)
|
|
return existing
|
|
db_obj = models.SmartIR(
|
|
month_id=month_id,
|
|
unit_id=unit_id,
|
|
total=int(total or 0),
|
|
installed=int(installed or 0),
|
|
new_install=int(new_install or 0),
|
|
ignored=int(ignored or 0),
|
|
rate=float(rate or 0.0),
|
|
created_at=created_at or datetime.datetime.utcnow(),
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def upsert_nac_by_month_unit(
|
|
db: Session,
|
|
month_id: int,
|
|
unit_id: int,
|
|
total: int,
|
|
installed: int,
|
|
ignored: int,
|
|
rate: float,
|
|
created_at: Optional[datetime.datetime] = None,
|
|
) -> models.NAC:
|
|
existing = (
|
|
db.query(models.NAC)
|
|
.filter(models.NAC.month_id == month_id)
|
|
.filter(models.NAC.unit_id == unit_id)
|
|
.first()
|
|
)
|
|
if existing:
|
|
existing.total = int(total or 0)
|
|
existing.installed = int(installed or 0)
|
|
existing.ignored = int(ignored or 0)
|
|
existing.rate = float(rate or 0.0)
|
|
if created_at:
|
|
existing.created_at = created_at
|
|
db.add(existing)
|
|
db.commit()
|
|
db.refresh(existing)
|
|
return existing
|
|
db_obj = models.NAC(
|
|
month_id=month_id,
|
|
unit_id=unit_id,
|
|
total=int(total or 0),
|
|
installed=int(installed or 0),
|
|
ignored=int(ignored or 0),
|
|
rate=float(rate or 0.0),
|
|
created_at=created_at or datetime.datetime.utcnow(),
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def upsert_compliance_by_month_unit(
|
|
db: Session,
|
|
month_id: int,
|
|
unit_id: int,
|
|
windows_key: int,
|
|
office: int,
|
|
ms17010: int,
|
|
firewall: int,
|
|
uac: int,
|
|
winrar: int,
|
|
antivirus: int,
|
|
update_win: int,
|
|
created_at: Optional[datetime.datetime] = None,
|
|
) -> models.Compliance:
|
|
existing = (
|
|
db.query(models.Compliance)
|
|
.filter(models.Compliance.month_id == month_id)
|
|
.filter(models.Compliance.unit_id == unit_id)
|
|
.first()
|
|
)
|
|
if existing:
|
|
existing.windows_key = int(windows_key or 0)
|
|
existing.office = int(office or 0)
|
|
existing.ms17010 = int(ms17010 or 0)
|
|
existing.firewall = int(firewall or 0)
|
|
existing.uac = int(uac or 0)
|
|
existing.winrar = int(winrar or 0)
|
|
existing.antivirus = int(antivirus or 0)
|
|
existing.update_win = int(update_win or 0)
|
|
if created_at:
|
|
existing.created_at = created_at
|
|
db.add(existing)
|
|
db.commit()
|
|
db.refresh(existing)
|
|
return existing
|
|
db_obj = models.Compliance(
|
|
month_id=month_id,
|
|
unit_id=unit_id,
|
|
windows_key=int(windows_key or 0),
|
|
office=int(office or 0),
|
|
ms17010=int(ms17010 or 0),
|
|
firewall=int(firewall or 0),
|
|
uac=int(uac or 0),
|
|
winrar=int(winrar or 0),
|
|
antivirus=int(antivirus or 0),
|
|
update_win=int(update_win or 0),
|
|
created_at=created_at or datetime.datetime.utcnow(),
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def upsert_attack_statics_by_month(
|
|
db: Session,
|
|
month_id: int,
|
|
siem_fintech: int,
|
|
siem_media: int,
|
|
ticket: int,
|
|
created_at: Optional[datetime.datetime] = None,
|
|
) -> models.AttackStatics:
|
|
existing = (
|
|
db.query(models.AttackStatics)
|
|
.filter(models.AttackStatics.month_id == month_id)
|
|
.first()
|
|
)
|
|
if existing:
|
|
existing.siem_fintech = int(siem_fintech or 0)
|
|
existing.siem_media = int(siem_media or 0)
|
|
existing.ticket = int(ticket or 0)
|
|
if created_at:
|
|
existing.created_at = created_at
|
|
db.add(existing)
|
|
db.commit()
|
|
db.refresh(existing)
|
|
return existing
|
|
db_obj = models.AttackStatics(
|
|
month_id=month_id,
|
|
siem_fintech=int(siem_fintech or 0),
|
|
siem_media=int(siem_media or 0),
|
|
ticket=int(ticket or 0),
|
|
created_at=created_at or datetime.datetime.utcnow(),
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def upsert_root_access_by_month_unit(
|
|
db: Session,
|
|
month_id: int,
|
|
unit_id: int,
|
|
number: int,
|
|
created_at: Optional[datetime.datetime] = None,
|
|
) -> models.RootAccess:
|
|
existing = (
|
|
db.query(models.RootAccess)
|
|
.filter(models.RootAccess.month_id == month_id)
|
|
.filter(models.RootAccess.unit_id == unit_id)
|
|
.first()
|
|
)
|
|
if existing:
|
|
existing.number = int(number or 0)
|
|
if created_at:
|
|
existing.created_at = created_at
|
|
db.add(existing)
|
|
db.commit()
|
|
db.refresh(existing)
|
|
return existing
|
|
db_obj = models.RootAccess(
|
|
month_id=month_id,
|
|
unit_id=unit_id,
|
|
number=int(number or 0),
|
|
created_at=created_at or datetime.datetime.utcnow(),
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
def delete_smartir_detail_by_month_unit(db: Session, month_id: int, unit_id: int) -> int:
|
|
cnt = (
|
|
db.query(models.SmartIRDetail)
|
|
.filter(models.SmartIRDetail.month_id == month_id)
|
|
.filter(models.SmartIRDetail.unit_id == unit_id)
|
|
.delete(synchronize_session=False)
|
|
)
|
|
db.commit()
|
|
return int(cnt or 0)
|
|
|
|
def create_nac_detail(db: Session, obj_in: schemas.NACDetailCreate) -> models.NACDetail:
|
|
db_obj = models.NACDetail(
|
|
month_id=obj_in.month_id,
|
|
unit_id=obj_in.unit_id,
|
|
name=obj_in.name,
|
|
email=obj_in.email,
|
|
status=obj_in.status,
|
|
)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def list_nac_detail_by_month(
|
|
db: Session,
|
|
month_id: int,
|
|
unit_id: Optional[int] = None,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
) -> List[models.NACDetail]:
|
|
q = db.query(models.NACDetail).filter(models.NACDetail.month_id == month_id)
|
|
if unit_id is not None:
|
|
q = q.filter(models.NACDetail.unit_id == unit_id)
|
|
return q.order_by(models.NACDetail.id.desc()).offset(skip).limit(limit).all()
|
|
|
|
def upsert_compliance_smartir(db: Session, obj_in: schemas.ComplianceSmartIRCreate) -> models.ComplianceSmartIR:
|
|
existing = (
|
|
db.query(models.ComplianceSmartIR)
|
|
.filter(models.ComplianceSmartIR.vnpt_ma_nhan_vien == obj_in.vnpt_ma_nhan_vien)
|
|
.filter(models.ComplianceSmartIR.month_id == obj_in.month_id)
|
|
.first()
|
|
)
|
|
if existing:
|
|
for k, v in obj_in.model_dump().items():
|
|
setattr(existing, k, v)
|
|
db.add(existing)
|
|
db.commit()
|
|
db.refresh(existing)
|
|
return existing
|
|
db_obj = models.ComplianceSmartIR(**obj_in.model_dump())
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def list_compliance_smartir(
|
|
db: Session,
|
|
status: Optional[int] = None,
|
|
unit_id: Optional[int] = None,
|
|
month_id: Optional[int] = None,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
) -> List[models.ComplianceSmartIR]:
|
|
q = db.query(models.ComplianceSmartIR)
|
|
if status is not None:
|
|
q = q.filter(models.ComplianceSmartIR.status == status)
|
|
if unit_id is not None:
|
|
q = q.filter(models.ComplianceSmartIR.unit_id == unit_id)
|
|
if month_id is not None:
|
|
q = q.filter(models.ComplianceSmartIR.month_id == month_id)
|
|
return q.order_by(models.ComplianceSmartIR.id.desc()).offset(skip).limit(limit).all()
|
|
|
|
def create_compliance_detail(db: Session, obj_in: schemas.ComplianceDetailCreate) -> models.ComplianceDetail:
|
|
data: Dict[str, Any] = {
|
|
"month_id": obj_in.month_id,
|
|
"unit_id": obj_in.unit_id,
|
|
"vnpt_ma_nhan_vien": obj_in.vnpt_ma_nhan_vien,
|
|
"name": obj_in.name,
|
|
"email": obj_in.email,
|
|
"phong_ban": obj_in.phong_ban,
|
|
"windows_key": obj_in.windows_key,
|
|
"office": obj_in.office,
|
|
"ms17010": obj_in.ms17010,
|
|
"firewall": obj_in.firewall,
|
|
"uac": obj_in.uac,
|
|
"winrar": obj_in.winrar,
|
|
"antivirus": obj_in.antivirus,
|
|
"update_win": obj_in.update_win,
|
|
"status": obj_in.status,
|
|
}
|
|
clean = {k: v for k, v in data.items() if v is not None}
|
|
db_obj = models.ComplianceDetail(**clean)
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
def list_compliance_detail_by_month(
|
|
db: Session,
|
|
month_id: int,
|
|
unit_id: Optional[int] = None,
|
|
status: Optional[int] = None,
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
) -> List[models.ComplianceDetail]:
|
|
q = db.query(models.ComplianceDetail).filter(models.ComplianceDetail.month_id == month_id)
|
|
if unit_id is not None:
|
|
q = q.filter(models.ComplianceDetail.unit_id == unit_id)
|
|
if status is not None:
|
|
q = q.filter(models.ComplianceDetail.status == status)
|
|
return q.order_by(models.ComplianceDetail.id.asc()).offset(skip).limit(limit).all()
|
|
|
|
|
|
def create_security_index(db: Session, obj_in: schemas.SecurityIndexCreate) -> models.SecurityIndex:
|
|
db_obj = models.SecurityIndex(**obj_in.dict())
|
|
db.add(db_obj)
|
|
db.commit()
|
|
db.refresh(db_obj)
|
|
return db_obj
|
|
|
|
|
|
def list_security_index_by_month(db: Session, month_id: int) -> List[models.SecurityIndex]:
|
|
return db.query(models.SecurityIndex).filter(models.SecurityIndex.month_id == month_id).all()
|
|
|
|
|
|
def delete_security_index_by_month(db: Session, month_id: int):
|
|
db.query(models.SecurityIndex).filter(models.SecurityIndex.month_id == month_id).delete(synchronize_session=False)
|
|
db.commit()
|
|
|