Files
audit-web/app/authenticator/crud.py
T
2026-08-26 14:11:37 +07:00

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()