Merge pull request 'Логи с уходом от орм' (#16) from future/AURORA-1012 into test
Reviewed-on: #16 Reviewed-by: tsygankoviva <tsygankov.itis@gmail.com>
This commit is contained in:
commit
e37eb09e0a
@ -15,6 +15,9 @@ async def get_db() -> AsyncGenerator:
|
|||||||
try:
|
try:
|
||||||
yield db
|
yield db
|
||||||
await db.commit()
|
await db.commit()
|
||||||
|
except Exception:
|
||||||
|
await db.rollback()
|
||||||
|
raise
|
||||||
finally:
|
finally:
|
||||||
await db.close()
|
await db.close()
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from sqlalchemy import delete, select, update
|
from sqlalchemy import select, text
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from src.db.models.form_phase import FormPhase
|
from src.db.models.form_phase import FormPhase
|
||||||
@ -45,40 +45,79 @@ class FormPhaseRepository:
|
|||||||
opens_at: datetime,
|
opens_at: datetime,
|
||||||
closes_at: datetime,
|
closes_at: datetime,
|
||||||
) -> FormPhase:
|
) -> FormPhase:
|
||||||
form_phase = FormPhase(
|
result = await self.db.execute(
|
||||||
budget_form_id=budget_form_id,
|
text(
|
||||||
sheet=sheet,
|
"""
|
||||||
phase_code=phase_code,
|
SELECT
|
||||||
role=role,
|
(v3.add_form_phase(
|
||||||
column_keys=column_keys,
|
:budget_form_id,
|
||||||
opens_at=opens_at,
|
:sheet,
|
||||||
closes_at=closes_at,
|
:phase_code,
|
||||||
|
:role,
|
||||||
|
:column_keys,
|
||||||
|
:opens_at,
|
||||||
|
:closes_at
|
||||||
|
)).budget_form_id
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"budget_form_id": budget_form_id,
|
||||||
|
"sheet": sheet,
|
||||||
|
"phase_code": phase_code,
|
||||||
|
"role": role,
|
||||||
|
"column_keys": column_keys,
|
||||||
|
"opens_at": opens_at,
|
||||||
|
"closes_at": closes_at,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
self.db.add(form_phase)
|
if result.scalar_one_or_none() is None:
|
||||||
await self.db.flush()
|
return None
|
||||||
return form_phase
|
return await self.get(budget_form_id, sheet, phase_code)
|
||||||
|
|
||||||
async def update(
|
async def update(
|
||||||
self, budget_form_id: int, sheet: str, phase_code: str, data: dict
|
self, budget_form_id: int, sheet: str, phase_code: str, data: dict
|
||||||
) -> FormPhase | None:
|
) -> FormPhase | None:
|
||||||
query = (
|
result = await self.db.execute(
|
||||||
update(FormPhase)
|
text(
|
||||||
.where(FormPhase.budget_form_id == budget_form_id)
|
"""
|
||||||
.where(FormPhase.sheet == sheet)
|
SELECT
|
||||||
.where(FormPhase.phase_code == phase_code)
|
(v3.upd_form_phase(
|
||||||
.values(**data)
|
:budget_form_id,
|
||||||
.returning(FormPhase)
|
:sheet,
|
||||||
|
:phase_code,
|
||||||
|
:role,
|
||||||
|
:column_keys,
|
||||||
|
:opens_at,
|
||||||
|
:closes_at
|
||||||
|
)).budget_form_id
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"budget_form_id": budget_form_id,
|
||||||
|
"sheet": sheet,
|
||||||
|
"phase_code": phase_code,
|
||||||
|
"role": data.get("role"),
|
||||||
|
"column_keys": data.get("column_keys"),
|
||||||
|
"opens_at": data.get("opens_at"),
|
||||||
|
"closes_at": data.get("closes_at"),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
return (await self.db.execute(query)).scalar_one_or_none()
|
if result.scalar_one_or_none() is None:
|
||||||
|
return None
|
||||||
|
return await self.get(budget_form_id, sheet, phase_code)
|
||||||
|
|
||||||
async def delete(
|
async def delete(
|
||||||
self, budget_form_id: int, sheet: str, phase_code: str
|
self, budget_form_id: int, sheet: str, phase_code: str
|
||||||
) -> bool:
|
) -> bool:
|
||||||
query = (
|
result = await self.db.execute(
|
||||||
delete(FormPhase)
|
text(
|
||||||
.where(FormPhase.budget_form_id == budget_form_id)
|
"SELECT v3.del_form_phase(:budget_form_id, :sheet, :phase_code)"
|
||||||
.where(FormPhase.sheet == sheet)
|
),
|
||||||
.where(FormPhase.phase_code == phase_code)
|
{
|
||||||
|
"budget_form_id": budget_form_id,
|
||||||
|
"sheet": sheet,
|
||||||
|
"phase_code": phase_code,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
result = await self.db.execute(query)
|
deleted = result.scalar_one_or_none()
|
||||||
return result.rowcount > 0
|
return bool(deleted)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from sqlalchemy import delete, select, text, update
|
from sqlalchemy import select, text, update
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.orm import selectinload
|
from sqlalchemy.orm import selectinload
|
||||||
|
|
||||||
@ -75,36 +75,6 @@ class UserRepository:
|
|||||||
)
|
)
|
||||||
return (await self.db.execute(query)).scalars().all()
|
return (await self.db.execute(query)).scalars().all()
|
||||||
|
|
||||||
async def create(self, user_data: dict) -> AppUser:
|
|
||||||
hashed_password = (
|
|
||||||
get_password_hash(user_data["password"]) if user_data.get("password") else None
|
|
||||||
)
|
|
||||||
db_user = AppUser(
|
|
||||||
email=user_data["email"],
|
|
||||||
username=user_data["username"],
|
|
||||||
hashed_password=hashed_password,
|
|
||||||
full_name=user_data.get("full_name"),
|
|
||||||
role_id=user_data.get("role_id"),
|
|
||||||
)
|
|
||||||
self.db.add(db_user)
|
|
||||||
await self.db.commit()
|
|
||||||
await self.db.refresh(db_user)
|
|
||||||
return db_user
|
|
||||||
|
|
||||||
async def update(self, user_id: int, user_data: dict) -> Optional[AppUser]:
|
|
||||||
user = await self.get(user_id)
|
|
||||||
if not user:
|
|
||||||
return None
|
|
||||||
|
|
||||||
for field, value in user_data.items():
|
|
||||||
if field == "password" and value:
|
|
||||||
value = get_password_hash(value)
|
|
||||||
setattr(user, field, value)
|
|
||||||
|
|
||||||
await self.db.commit()
|
|
||||||
await self.db.refresh(user)
|
|
||||||
return user
|
|
||||||
|
|
||||||
async def logical_delete(self, user_id: int) -> bool:
|
async def logical_delete(self, user_id: int) -> bool:
|
||||||
query = update(AppUser).where(AppUser.id == user_id).values(is_active=False)
|
query = update(AppUser).where(AppUser.id == user_id).values(is_active=False)
|
||||||
result = await self.db.execute(query)
|
result = await self.db.execute(query)
|
||||||
@ -126,45 +96,108 @@ class UserRepository:
|
|||||||
return (await self.db.execute(select(Role).order_by(Role.id))).scalars().all()
|
return (await self.db.execute(select(Role).order_by(Role.id))).scalars().all()
|
||||||
|
|
||||||
async def get_many_ssp(self, user_id: int) -> list[OrgUnit]:
|
async def get_many_ssp(self, user_id: int) -> list[OrgUnit]:
|
||||||
query = select(OrgUnit).join(UserOrg, UserOrg.ssp_id == OrgUnit.id).where(
|
query = select(OrgUnit).join(UserOrg, UserOrg.org_unit_id == OrgUnit.id).where(
|
||||||
UserOrg.user_id == user_id
|
UserOrg.user_id == user_id
|
||||||
)
|
)
|
||||||
return (await self.db.execute(query)).scalars().all()
|
return (await self.db.execute(query)).scalars().all()
|
||||||
|
|
||||||
async def get_many_ssp_ids(self, user_id: int) -> list[int]:
|
async def get_many_ssp_ids(self, user_id: int) -> list[int]:
|
||||||
query = select(UserOrg.ssp_id).where(UserOrg.user_id == user_id)
|
query = select(UserOrg.org_unit_id).where(UserOrg.user_id == user_id)
|
||||||
return (await self.db.execute(query)).scalars().all()
|
return (await self.db.execute(query)).scalars().all()
|
||||||
|
|
||||||
async def set_many_ssp(self, user_id: int, ssp_ids: list[int]) -> bool:
|
async def set_many_ssp(self, user_id: int, ssp_ids: list[int]) -> bool:
|
||||||
try:
|
for ssp_id in ssp_ids:
|
||||||
for ssp_id in ssp_ids:
|
await self.db.execute(
|
||||||
link = UserOrg(user_id=user_id, ssp_id=ssp_id)
|
text(
|
||||||
self.db.add(link)
|
"SELECT v3.grant_user_org_access(:user_id, :org_unit_id)"
|
||||||
await self.db.commit()
|
),
|
||||||
return True
|
{"user_id": user_id, "org_unit_id": ssp_id},
|
||||||
except Exception:
|
)
|
||||||
await self.db.rollback()
|
await self.db.commit()
|
||||||
return False
|
return True
|
||||||
|
|
||||||
async def unset_many_ssp(self, user_id: int, ssp_ids: list[int]) -> bool:
|
async def unset_many_ssp(self, user_id: int, ssp_ids: list[int]) -> bool:
|
||||||
try:
|
for ssp_id in ssp_ids:
|
||||||
for ssp_id in ssp_ids:
|
await self.db.execute(
|
||||||
query = delete(UserOrg).where(
|
text(
|
||||||
(UserOrg.user_id == user_id) & (UserOrg.ssp_id == ssp_id)
|
"SELECT v3.revoke_user_org_access(:user_id, :org_unit_id)"
|
||||||
)
|
),
|
||||||
await self.db.execute(query)
|
{"user_id": user_id, "org_unit_id": ssp_id},
|
||||||
await self.db.commit()
|
)
|
||||||
return True
|
await self.db.commit()
|
||||||
except Exception:
|
return True
|
||||||
await self.db.rollback()
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def clear_many_ssp(self, user_id: int) -> bool:
|
async def clear_many_ssp(self, user_id: int) -> None:
|
||||||
try:
|
org_unit_ids = await self.get_many_ssp_ids(user_id)
|
||||||
query = delete(UserOrg).where(UserOrg.user_id == user_id)
|
await self.db.execute(
|
||||||
await self.db.execute(query)
|
text(
|
||||||
await self.db.commit()
|
"SELECT v3.revoke_many_user_org_access(:user_id, :org_unit_ids)"
|
||||||
return True
|
),
|
||||||
except Exception:
|
{"user_id": user_id, "org_unit_ids": org_unit_ids},
|
||||||
await self.db.rollback()
|
)
|
||||||
return False
|
await self.db.commit()
|
||||||
|
|
||||||
|
async def create(self, user_data: dict) -> AppUser:
|
||||||
|
hashed_password = (
|
||||||
|
get_password_hash(user_data["password"]) if user_data.get("password") else None
|
||||||
|
)
|
||||||
|
user_id = (
|
||||||
|
await self.db.execute(
|
||||||
|
text(
|
||||||
|
"""
|
||||||
|
SELECT (v3.add_user(
|
||||||
|
:email,
|
||||||
|
:username,
|
||||||
|
:hashed_password,
|
||||||
|
:full_name,
|
||||||
|
:role_id
|
||||||
|
)).id
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"email": user_data["email"],
|
||||||
|
"username": user_data["username"],
|
||||||
|
"hashed_password": hashed_password,
|
||||||
|
"full_name": user_data.get("full_name"),
|
||||||
|
"role_id": user_data.get("role_id"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
).scalar_one()
|
||||||
|
await self.db.commit()
|
||||||
|
return await self.get(user_id)
|
||||||
|
|
||||||
|
async def update(self, user_id: int, user_data: dict) -> Optional[AppUser]:
|
||||||
|
user = await self.get(user_id)
|
||||||
|
if not user:
|
||||||
|
return None
|
||||||
|
|
||||||
|
hashed_password = None
|
||||||
|
if "password" in user_data and user_data["password"]:
|
||||||
|
hashed_password = get_password_hash(user_data["password"])
|
||||||
|
|
||||||
|
await self.db.execute(
|
||||||
|
text(
|
||||||
|
"""
|
||||||
|
SELECT (v3.upd_user(
|
||||||
|
:user_id,
|
||||||
|
:email,
|
||||||
|
:username,
|
||||||
|
:hashed_password,
|
||||||
|
:full_name,
|
||||||
|
:role_id,
|
||||||
|
:is_active
|
||||||
|
)).id
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"user_id": user_id,
|
||||||
|
"email": user_data.get("email"),
|
||||||
|
"username": user_data.get("username"),
|
||||||
|
"hashed_password": hashed_password,
|
||||||
|
"full_name": user_data.get("full_name"),
|
||||||
|
"role_id": user_data.get("role_id"),
|
||||||
|
"is_active": user_data.get("is_active"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await self.db.commit()
|
||||||
|
return await self.get(user_id)
|
||||||
|
|||||||
276
api/tests/integration/test_audit_events_integration.py
Normal file
276
api/tests/integration/test_audit_events_integration.py
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
#
|
||||||
|
# закоментированы для избежания переполнения бд
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# from datetime import datetime, timedelta
|
||||||
|
# import uuid
|
||||||
|
|
||||||
|
# import pytest
|
||||||
|
|
||||||
|
|
||||||
|
# def _find_event(
|
||||||
|
# client,
|
||||||
|
# admin_tokens: dict,
|
||||||
|
# auth_headers,
|
||||||
|
# event_type: str,
|
||||||
|
# predicate,
|
||||||
|
# limit: int = 100,
|
||||||
|
# ):
|
||||||
|
# response = client.get(
|
||||||
|
# f"/api/v1/audit-logs?event_type={event_type}&limit={limit}",
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# assert response.status_code == 200
|
||||||
|
# result = response.json().get("result", [])
|
||||||
|
# for item in result:
|
||||||
|
# payload = item.get("payload_json") or {}
|
||||||
|
# if predicate(payload):
|
||||||
|
# return item
|
||||||
|
# return None
|
||||||
|
|
||||||
|
|
||||||
|
# def _event_count(client, admin_tokens: dict, auth_headers, event_type: str) -> int:
|
||||||
|
# response = client.get(
|
||||||
|
# f"/api/v1/audit-logs?event_type={event_type}&limit=1",
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# assert response.status_code == 200
|
||||||
|
# return int(response.json().get("count") or 0)
|
||||||
|
|
||||||
|
|
||||||
|
# def _pick_target_user_id(client, admin_tokens: dict, auth_headers) -> int:
|
||||||
|
# me_resp = client.get(
|
||||||
|
# "/api/v1/users/me",
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# assert me_resp.status_code == 200
|
||||||
|
# me = me_resp.json() or {}
|
||||||
|
# assert me.get("id") is not None
|
||||||
|
# return int(me["id"])
|
||||||
|
|
||||||
|
|
||||||
|
# def _pick_org_unit_id(client, admin_tokens: dict, auth_headers, user_id: int) -> int:
|
||||||
|
# forms_resp = client.get(
|
||||||
|
# "/api/v1/form/?limit=100",
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# assert forms_resp.status_code == 200
|
||||||
|
# forms = forms_resp.json().get("result") or []
|
||||||
|
# candidate_ids = [f.get("org_unit_id") for f in forms if f.get("org_unit_id") is not None]
|
||||||
|
# assert candidate_ids
|
||||||
|
|
||||||
|
# assigned_resp = client.get(
|
||||||
|
# f"/api/v1/users/dfip-many-ssp/?user_id={user_id}",
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# assert assigned_resp.status_code == 200
|
||||||
|
# assigned = {
|
||||||
|
# int(item["id"])
|
||||||
|
# for item in (assigned_resp.json().get("result") or {}).get("ssp", [])
|
||||||
|
# if item.get("id") is not None
|
||||||
|
# }
|
||||||
|
# for org_unit_id in candidate_ids:
|
||||||
|
# if int(org_unit_id) not in assigned:
|
||||||
|
# return int(org_unit_id)
|
||||||
|
# raise AssertionError("Не найден org_unit_id, который можно прикрепить пользователю")
|
||||||
|
|
||||||
|
|
||||||
|
# def _create_temp_user(client, admin_tokens: dict, auth_headers, role_id: int = 2) -> int:
|
||||||
|
# suffix = uuid.uuid4().hex[:8]
|
||||||
|
# username = f"audit_u_{suffix}"
|
||||||
|
# response = client.put(
|
||||||
|
# "/api/v1/users/",
|
||||||
|
# json={
|
||||||
|
# "email": f"{username}@example.com",
|
||||||
|
# "username": username,
|
||||||
|
# "password": "pass123",
|
||||||
|
# "full_name": "Audit User",
|
||||||
|
# "role_id": role_id,
|
||||||
|
# },
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# assert response.status_code == 200, response.text
|
||||||
|
# result = response.json().get("result") or {}
|
||||||
|
# return int(result["id"])
|
||||||
|
|
||||||
|
|
||||||
|
# def _create_project(client, admin_tokens: dict, auth_headers) -> int:
|
||||||
|
# response = client.post(
|
||||||
|
# "/api/v1/projects",
|
||||||
|
# json={"name": f"PT_{uuid.uuid4().hex[:10]}", "year": 2026, "branch_id": 1},
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# assert response.status_code == 200, response.text
|
||||||
|
# return int(response.json()["project_id"])
|
||||||
|
|
||||||
|
|
||||||
|
# def _add_project_line(client, admin_tokens: dict, auth_headers, project_id: int) -> int:
|
||||||
|
# for expense_item_id in range(1, 80):
|
||||||
|
# response = client.post(
|
||||||
|
# f"/api/v1/projects/{project_id}/report/2026/LIMIT/line",
|
||||||
|
# json={"expense_item_id": expense_item_id},
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# if response.status_code != 200:
|
||||||
|
# continue
|
||||||
|
# rows = response.json()
|
||||||
|
# input_row = next(
|
||||||
|
# (
|
||||||
|
# row
|
||||||
|
# for row in rows
|
||||||
|
# if row.get("row_type") == "INPUT" and row.get("data", {}).get("line_id")
|
||||||
|
# ),
|
||||||
|
# None,
|
||||||
|
# )
|
||||||
|
# if input_row:
|
||||||
|
# return int(input_row["data"]["line_id"])
|
||||||
|
# raise AssertionError("Не удалось добавить строку в проектный отчёт для ROW_* тестов")
|
||||||
|
|
||||||
|
|
||||||
|
# def _create_stage(client, admin_tokens, auth_headers, form_id: int, sheet: str) -> dict:
|
||||||
|
# phase_code = f"autotest_{uuid.uuid4().hex[:8]}"
|
||||||
|
# opens_at = datetime.utcnow().replace(microsecond=0)
|
||||||
|
# closes_at = opens_at + timedelta(days=2)
|
||||||
|
# response = client.post(
|
||||||
|
# f"/api/v1/stages/form/{form_id}",
|
||||||
|
# json={
|
||||||
|
# "sheet": sheet,
|
||||||
|
# "phase_code": phase_code,
|
||||||
|
# "role": "DFIP",
|
||||||
|
# "column_keys": ["plan.q1"],
|
||||||
|
# "opens_at": opens_at.isoformat() + "Z",
|
||||||
|
# "closes_at": closes_at.isoformat() + "Z",
|
||||||
|
# },
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# assert response.status_code == 200, response.text
|
||||||
|
# result = response.json().get("result") or {}
|
||||||
|
# assert result.get("phase_code") == phase_code
|
||||||
|
# return result
|
||||||
|
|
||||||
|
|
||||||
|
# def test_audit_user_access_granted_event(client, admin_tokens, auth_headers):
|
||||||
|
# user_id = _pick_target_user_id(client, admin_tokens, auth_headers)
|
||||||
|
# org_unit_id = _pick_org_unit_id(client, admin_tokens, auth_headers, user_id)
|
||||||
|
|
||||||
|
# response = client.put(
|
||||||
|
# f"/api/v1/users/dfip-many-ssp/?user_id={user_id}",
|
||||||
|
# json={"ssp_ids": [org_unit_id]},
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# assert response.status_code == 200
|
||||||
|
# assert response.json().get("success") is True
|
||||||
|
|
||||||
|
# event = _find_event(
|
||||||
|
# client,
|
||||||
|
# admin_tokens,
|
||||||
|
# auth_headers,
|
||||||
|
# "USER_ACCESS_GRANTED",
|
||||||
|
# lambda payload: int(payload.get("user_id", -1)) == user_id
|
||||||
|
# and int(payload.get("org_unit_id", -1)) == org_unit_id,
|
||||||
|
# )
|
||||||
|
# assert event is not None
|
||||||
|
|
||||||
|
|
||||||
|
# def test_audit_user_access_revoked_event(client, admin_tokens, auth_headers):
|
||||||
|
# user_id = _pick_target_user_id(client, admin_tokens, auth_headers)
|
||||||
|
# assigned_resp = client.get(
|
||||||
|
# f"/api/v1/users/dfip-many-ssp/?user_id={user_id}",
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# assert assigned_resp.status_code == 200
|
||||||
|
# assigned = (assigned_resp.json().get("result") or {}).get("ssp", [])
|
||||||
|
|
||||||
|
# if assigned:
|
||||||
|
# org_unit_id = int(assigned[0]["id"])
|
||||||
|
# else:
|
||||||
|
# org_unit_id = _pick_org_unit_id(client, admin_tokens, auth_headers, user_id)
|
||||||
|
# attach_resp = client.put(
|
||||||
|
# f"/api/v1/users/dfip-many-ssp/?user_id={user_id}",
|
||||||
|
# json={"ssp_ids": [org_unit_id]},
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# assert attach_resp.status_code == 200
|
||||||
|
# assert attach_resp.json().get("success") is True
|
||||||
|
|
||||||
|
# response = client.request(
|
||||||
|
# "DELETE",
|
||||||
|
# f"/api/v1/users/dfip-many-ssp/?user_id={user_id}",
|
||||||
|
# json={"ssp_ids": [org_unit_id]},
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# assert response.status_code == 200
|
||||||
|
# assert response.json().get("success") is True
|
||||||
|
|
||||||
|
# event = _find_event(
|
||||||
|
# client,
|
||||||
|
# admin_tokens,
|
||||||
|
# auth_headers,
|
||||||
|
# "USER_ACCESS_REVOKED",
|
||||||
|
# lambda payload: int(payload.get("user_id", -1)) == user_id
|
||||||
|
# and int(payload.get("org_unit_id", -1)) == org_unit_id,
|
||||||
|
# )
|
||||||
|
# assert event is not None
|
||||||
|
|
||||||
|
|
||||||
|
# def test_audit_user_create_event(client, admin_tokens, auth_headers):
|
||||||
|
# before = _event_count(client, admin_tokens, auth_headers, "USER_CREATE")
|
||||||
|
# user_id = _create_temp_user(client, admin_tokens, auth_headers, role_id=2)
|
||||||
|
# after = _event_count(client, admin_tokens, auth_headers, "USER_CREATE")
|
||||||
|
# assert after > before
|
||||||
|
|
||||||
|
# delete_resp = client.delete(
|
||||||
|
# f"/api/v1/users/{user_id}",
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# assert delete_resp.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
# def test_audit_user_role_change_event(client, admin_tokens, auth_headers):
|
||||||
|
# user_id = _create_temp_user(client, admin_tokens, auth_headers, role_id=2)
|
||||||
|
# before = _event_count(client, admin_tokens, auth_headers, "USER_ROLE_CHANGE")
|
||||||
|
|
||||||
|
# update_resp = client.patch(
|
||||||
|
# f"/api/v1/users/{user_id}",
|
||||||
|
# json={"role_id": 3},
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# assert update_resp.status_code == 200, update_resp.text
|
||||||
|
# after = _event_count(client, admin_tokens, auth_headers, "USER_ROLE_CHANGE")
|
||||||
|
# assert after > before
|
||||||
|
|
||||||
|
# delete_resp = client.delete(
|
||||||
|
# f"/api/v1/users/{user_id}",
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# assert delete_resp.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
# def test_audit_project_create_event(client, admin_tokens, auth_headers):
|
||||||
|
# before = _event_count(client, admin_tokens, auth_headers, "PROJECT_CREATE")
|
||||||
|
# _create_project(client, admin_tokens, auth_headers)
|
||||||
|
# after = _event_count(client, admin_tokens, auth_headers, "PROJECT_CREATE")
|
||||||
|
# assert after > before
|
||||||
|
|
||||||
|
|
||||||
|
# def test_audit_row_create_event(client, admin_tokens, auth_headers):
|
||||||
|
# project_id = _create_project(client, admin_tokens, auth_headers)
|
||||||
|
# before = _event_count(client, admin_tokens, auth_headers, "ROW_CREATE")
|
||||||
|
# _add_project_line(client, admin_tokens, auth_headers, project_id)
|
||||||
|
# after = _event_count(client, admin_tokens, auth_headers, "ROW_CREATE")
|
||||||
|
# assert after > before
|
||||||
|
|
||||||
|
|
||||||
|
# def test_audit_row_delete_event(client, admin_tokens, auth_headers):
|
||||||
|
# project_id = _create_project(client, admin_tokens, auth_headers)
|
||||||
|
# line_id = _add_project_line(client, admin_tokens, auth_headers, project_id)
|
||||||
|
# before = _event_count(client, admin_tokens, auth_headers, "ROW_DELETE")
|
||||||
|
|
||||||
|
# delete_resp = client.delete(
|
||||||
|
# f"/api/v1/projects/{project_id}/report/2026/LIMIT/line/{line_id}",
|
||||||
|
# headers=auth_headers(admin_tokens),
|
||||||
|
# )
|
||||||
|
# assert delete_resp.status_code == 200, delete_resp.text
|
||||||
|
# after = _event_count(client, admin_tokens, auth_headers, "ROW_DELETE")
|
||||||
|
# assert after > before
|
||||||
@ -16,6 +16,12 @@ def _result_with_scalars(items):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _result_with_scalar_one(value):
|
||||||
|
result = MagicMock()
|
||||||
|
result.scalar_one.return_value = value
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_db():
|
def mock_db():
|
||||||
return AsyncMock(spec=AsyncSession)
|
return AsyncMock(spec=AsyncSession)
|
||||||
@ -49,9 +55,12 @@ async def test_get_returns_none_for_missing_id(repository, mock_db):
|
|||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_get_all_applies_filters(repository, mock_db):
|
async def test_get_all_applies_filters(repository, mock_db):
|
||||||
row = MagicMock(id=11, user_id=2, org_unit_id=7, event_type="UPDATE")
|
row = MagicMock(id=11, user_id=2, org_unit_id=7, event_type="UPDATE")
|
||||||
mock_db.execute.return_value = _result_with_scalars([row])
|
mock_db.execute.side_effect = [
|
||||||
|
_result_with_scalars([row]),
|
||||||
|
_result_with_scalar_one(1),
|
||||||
|
]
|
||||||
|
|
||||||
result = await repository.get_all(
|
result, count = await repository.get_all(
|
||||||
limit=10,
|
limit=10,
|
||||||
offset=5,
|
offset=5,
|
||||||
user_id=2,
|
user_id=2,
|
||||||
@ -64,5 +73,6 @@ async def test_get_all_applies_filters(repository, mock_db):
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert result == [row]
|
assert result == [row]
|
||||||
mock_db.execute.assert_awaited_once()
|
assert count == 1
|
||||||
|
assert mock_db.execute.await_count == 2
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user