1
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import shutil
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any
|
||||
@@ -116,6 +117,69 @@ async def list_all_projects() -> list[dict[str, Any]]:
|
||||
return [_project_row(row) for row in await cursor.fetchall()]
|
||||
|
||||
|
||||
async def get_project(project_id: str) -> dict[str, Any] | None:
|
||||
pool = get_db_pool()
|
||||
async with pool.acquire() as connection, connection.cursor(aiomysql.DictCursor) as cursor:
|
||||
await cursor.execute(
|
||||
"""SELECT id, user_id, company_id, name, region, road_type, project_year,
|
||||
estimated_length_m, memo, status
|
||||
FROM projects WHERE id = %s AND deleted_at IS NULL""",
|
||||
(project_id,),
|
||||
)
|
||||
return await cursor.fetchone()
|
||||
|
||||
|
||||
async def update_project(project_id: str, data: dict[str, Any], actor_id: int) -> bool:
|
||||
pool = get_db_pool()
|
||||
async with pool.acquire() as connection, connection.cursor() as cursor:
|
||||
await connection.begin()
|
||||
await cursor.execute(
|
||||
"""UPDATE projects
|
||||
SET name = %s, region = %s, road_type = %s, project_year = %s,
|
||||
estimated_length_m = %s, memo = %s, status = COALESCE(%s, status)
|
||||
WHERE id = %s AND deleted_at IS NULL""",
|
||||
(
|
||||
data["name"],
|
||||
data.get("region"),
|
||||
data.get("road_type"),
|
||||
data.get("project_year"),
|
||||
data.get("estimated_length_m"),
|
||||
data.get("memo"),
|
||||
data.get("status"),
|
||||
project_id,
|
||||
),
|
||||
)
|
||||
changed = cursor.rowcount > 0
|
||||
if changed:
|
||||
await cursor.execute(
|
||||
"""INSERT INTO system_audit_logs (user_id, action, resource_type, resource_id)
|
||||
VALUES (%s, 'PROJECT_UPDATE', 'project', NULL)""",
|
||||
(actor_id,),
|
||||
)
|
||||
await connection.commit()
|
||||
return changed
|
||||
|
||||
|
||||
async def soft_delete_project(project_id: str, actor_id: int) -> bool:
|
||||
pool = get_db_pool()
|
||||
async with pool.acquire() as connection, connection.cursor() as cursor:
|
||||
await connection.begin()
|
||||
await cursor.execute(
|
||||
"""UPDATE projects SET deleted_at = CURRENT_TIMESTAMP
|
||||
WHERE id = %s AND deleted_at IS NULL""",
|
||||
(project_id,),
|
||||
)
|
||||
changed = cursor.rowcount > 0
|
||||
if changed:
|
||||
await cursor.execute(
|
||||
"""INSERT INTO system_audit_logs (user_id, action, resource_type, resource_id)
|
||||
VALUES (%s, 'PROJECT_DELETE', 'project', NULL)""",
|
||||
(actor_id,),
|
||||
)
|
||||
await connection.commit()
|
||||
return changed
|
||||
|
||||
|
||||
async def get_user_company(company_id: int | None) -> dict[str, Any] | None:
|
||||
if company_id is None:
|
||||
return None
|
||||
@@ -358,6 +422,55 @@ async def change_user_role(user_id: int, role: str) -> bool:
|
||||
return changed
|
||||
|
||||
|
||||
async def get_user_admin_target(user_id: int) -> dict[str, Any] | None:
|
||||
pool = get_db_pool()
|
||||
async with pool.acquire() as connection, connection.cursor(aiomysql.DictCursor) as cursor:
|
||||
await cursor.execute(
|
||||
"""SELECT id, company_id, role, is_master, status
|
||||
FROM users WHERE id = %s AND deleted_at IS NULL""",
|
||||
(user_id,),
|
||||
)
|
||||
row = await cursor.fetchone()
|
||||
if row:
|
||||
row["role"] = _role(row.get("role"))
|
||||
row["is_master"] = bool(row.get("is_master"))
|
||||
return row
|
||||
|
||||
|
||||
async def update_admin_user(user_id: int, data: dict[str, Any]) -> bool:
|
||||
pool = get_db_pool()
|
||||
async with pool.acquire() as connection, connection.cursor() as cursor:
|
||||
await cursor.execute(
|
||||
"""UPDATE users
|
||||
SET name = %s, position = %s, department = %s, phone = %s,
|
||||
status = COALESCE(%s, status)
|
||||
WHERE id = %s AND deleted_at IS NULL""",
|
||||
(
|
||||
data["name"],
|
||||
data.get("position"),
|
||||
data.get("department"),
|
||||
data.get("phone"),
|
||||
data.get("status"),
|
||||
user_id,
|
||||
),
|
||||
)
|
||||
changed = cursor.rowcount > 0
|
||||
await connection.commit()
|
||||
return changed
|
||||
|
||||
|
||||
async def count_company_admins(company_id: int) -> int:
|
||||
pool = get_db_pool()
|
||||
async with pool.acquire() as connection, connection.cursor(aiomysql.DictCursor) as cursor:
|
||||
await cursor.execute(
|
||||
"""SELECT COUNT(*) AS cnt FROM users
|
||||
WHERE company_id = %s AND role = 'ADMIN' AND deleted_at IS NULL""",
|
||||
(company_id,),
|
||||
)
|
||||
row = await cursor.fetchone()
|
||||
return int(row["cnt"] if row else 0)
|
||||
|
||||
|
||||
async def assign_user_company(user_id: int, company_id: int | None) -> bool:
|
||||
status = "ACTIVE" if company_id else "NO_COMPANY"
|
||||
pool = get_db_pool()
|
||||
@@ -442,3 +555,114 @@ async def get_system_resources(days: int = 30) -> dict[str, Any]:
|
||||
(bucket_seconds, bucket_seconds, since, bucket_seconds),
|
||||
)
|
||||
return {"current": current, "history": list(await cursor.fetchall()), "stats": current}
|
||||
|
||||
|
||||
async def list_project_automations(project_id: str) -> list[dict[str, Any]]:
|
||||
pool = get_db_pool()
|
||||
async with pool.acquire() as connection, connection.cursor(aiomysql.DictCursor) as cursor:
|
||||
await cursor.execute(
|
||||
"""SELECT id, project_id, name, logic_type, config_json, status,
|
||||
last_executed_at, created_at, updated_at
|
||||
FROM project_automations
|
||||
WHERE project_id = %s AND deleted_at IS NULL
|
||||
ORDER BY updated_at DESC, created_at DESC""",
|
||||
(project_id,),
|
||||
)
|
||||
return list(await cursor.fetchall())
|
||||
|
||||
|
||||
async def create_project_automation(
|
||||
project_id: str, actor_id: int, data: dict[str, Any]
|
||||
) -> dict[str, Any]:
|
||||
pool = get_db_pool()
|
||||
async with pool.acquire() as connection, connection.cursor(aiomysql.DictCursor) as cursor:
|
||||
await connection.begin()
|
||||
await cursor.execute(
|
||||
"""INSERT INTO project_automations
|
||||
(project_id, name, logic_type, config_json, status, created_by, updated_by)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s)""",
|
||||
(
|
||||
project_id,
|
||||
data["name"],
|
||||
data["logic_type"],
|
||||
json.dumps(data["config_json"], ensure_ascii=False),
|
||||
data["status"],
|
||||
actor_id,
|
||||
actor_id,
|
||||
),
|
||||
)
|
||||
automation_id = cursor.lastrowid
|
||||
await connection.commit()
|
||||
await cursor.execute("SELECT * FROM project_automations WHERE id = %s", (automation_id,))
|
||||
return await cursor.fetchone()
|
||||
|
||||
|
||||
async def get_project_automation(automation_id: int) -> dict[str, Any] | None:
|
||||
pool = get_db_pool()
|
||||
async with pool.acquire() as connection, connection.cursor(aiomysql.DictCursor) as cursor:
|
||||
await cursor.execute(
|
||||
"""SELECT a.*, p.company_id
|
||||
FROM project_automations a
|
||||
JOIN projects p ON p.id = a.project_id
|
||||
WHERE a.id = %s AND a.deleted_at IS NULL AND p.deleted_at IS NULL""",
|
||||
(automation_id,),
|
||||
)
|
||||
return await cursor.fetchone()
|
||||
|
||||
|
||||
async def update_project_automation(
|
||||
automation_id: int, actor_id: int, data: dict[str, Any]
|
||||
) -> bool:
|
||||
pool = get_db_pool()
|
||||
async with pool.acquire() as connection, connection.cursor() as cursor:
|
||||
await cursor.execute(
|
||||
"""UPDATE project_automations
|
||||
SET name = %s, logic_type = %s, config_json = %s, status = %s, updated_by = %s
|
||||
WHERE id = %s AND deleted_at IS NULL""",
|
||||
(
|
||||
data["name"],
|
||||
data["logic_type"],
|
||||
json.dumps(data["config_json"], ensure_ascii=False),
|
||||
data["status"],
|
||||
actor_id,
|
||||
automation_id,
|
||||
),
|
||||
)
|
||||
changed = cursor.rowcount > 0
|
||||
await connection.commit()
|
||||
return changed
|
||||
|
||||
|
||||
async def delete_project_automation(automation_id: int, actor_id: int) -> bool:
|
||||
pool = get_db_pool()
|
||||
async with pool.acquire() as connection, connection.cursor() as cursor:
|
||||
await connection.begin()
|
||||
await cursor.execute(
|
||||
"""UPDATE project_automations
|
||||
SET deleted_at = CURRENT_TIMESTAMP, updated_by = %s
|
||||
WHERE id = %s AND deleted_at IS NULL""",
|
||||
(actor_id, automation_id),
|
||||
)
|
||||
changed = cursor.rowcount > 0
|
||||
if changed:
|
||||
await cursor.execute(
|
||||
"""INSERT INTO system_audit_logs (user_id, action, resource_type, resource_id)
|
||||
VALUES (%s, 'AUTOMATION_DELETE', 'automation', %s)""",
|
||||
(actor_id, automation_id),
|
||||
)
|
||||
await connection.commit()
|
||||
return changed
|
||||
|
||||
|
||||
async def mark_project_automation_executed(automation_id: int, actor_id: int) -> bool:
|
||||
pool = get_db_pool()
|
||||
async with pool.acquire() as connection, connection.cursor() as cursor:
|
||||
await cursor.execute(
|
||||
"""UPDATE project_automations
|
||||
SET last_executed_at = CURRENT_TIMESTAMP, updated_by = %s
|
||||
WHERE id = %s AND deleted_at IS NULL""",
|
||||
(actor_id, automation_id),
|
||||
)
|
||||
changed = cursor.rowcount > 0
|
||||
await connection.commit()
|
||||
return changed
|
||||
|
||||
Reference in New Issue
Block a user