@@ -0,0 +1,137 @@
|
||||
"""Доступ к модулю Lab — per-user lab_access и server-side guards."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from app import create_app, db
|
||||
from app.models import Recipe, WebUser
|
||||
from app.models.base import default_uuid
|
||||
from app.services.setup_state import mark_setup_complete
|
||||
from tests.helpers.zootech_test_helpers import ZootechTestConfig
|
||||
from werkzeug.security import generate_password_hash
|
||||
|
||||
|
||||
class LabAccessControlTests(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.app = create_app(ZootechTestConfig)
|
||||
self.client = self.app.test_client()
|
||||
self.ctx = self.app.app_context()
|
||||
self.ctx.push()
|
||||
db.create_all()
|
||||
mark_setup_complete(self.app)
|
||||
recipe = Recipe(id=default_uuid(), name="Lab access test", heads_per_trip=10, mixing_time=5)
|
||||
db.session.add(recipe)
|
||||
db.session.add(
|
||||
WebUser(
|
||||
login="zootech-test-admin",
|
||||
password_hash=generate_password_hash("zootech-test-secret"),
|
||||
is_superuser=True,
|
||||
)
|
||||
)
|
||||
db.session.add(
|
||||
WebUser(
|
||||
login="zootech-no-lab",
|
||||
password_hash=generate_password_hash("zootech-no-lab-secret"),
|
||||
is_superuser=False,
|
||||
lab_access=False,
|
||||
)
|
||||
)
|
||||
db.session.add(
|
||||
WebUser(
|
||||
login="zootech-with-lab",
|
||||
password_hash=generate_password_hash("zootech-with-lab-secret"),
|
||||
is_superuser=False,
|
||||
lab_access=True,
|
||||
)
|
||||
)
|
||||
db.session.commit()
|
||||
self.recipe_id = recipe.id
|
||||
|
||||
def tearDown(self) -> None:
|
||||
db.session.remove()
|
||||
db.drop_all()
|
||||
self.ctx.pop()
|
||||
|
||||
def _login(self, login: str, password: str) -> None:
|
||||
r = self.client.post("/api/auth/login", json={"login": login, "password": password})
|
||||
self.assertEqual(r.status_code, 200, r.get_data(as_text=True))
|
||||
|
||||
def test_auth_check_can_lab_for_superuser(self) -> None:
|
||||
self._login("zootech-test-admin", "zootech-test-secret")
|
||||
body = self.client.get("/api/auth/check").get_json()
|
||||
self.assertTrue(body.get("can_lab"))
|
||||
|
||||
def test_auth_check_can_lab_disabled_for_zootech(self) -> None:
|
||||
self._login("zootech-no-lab", "zootech-no-lab-secret")
|
||||
body = self.client.get("/api/auth/check").get_json()
|
||||
self.assertFalse(body.get("can_lab"))
|
||||
|
||||
def test_auth_check_can_lab_enabled_for_zootech(self) -> None:
|
||||
self._login("zootech-with-lab", "zootech-with-lab-secret")
|
||||
body = self.client.get("/api/auth/check").get_json()
|
||||
self.assertTrue(body.get("can_lab"))
|
||||
|
||||
def test_lab_page_redirect_without_access(self) -> None:
|
||||
self._login("zootech-no-lab", "zootech-no-lab-secret")
|
||||
r = self.client.get("/lab", follow_redirects=False)
|
||||
self.assertEqual(r.status_code, 302)
|
||||
self.assertIn("/recipes", r.headers.get("Location", ""))
|
||||
|
||||
def test_lab_page_ok_with_access(self) -> None:
|
||||
self._login("zootech-with-lab", "zootech-with-lab-secret")
|
||||
r = self.client.get("/lab")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_lab_api_forbidden_without_access(self) -> None:
|
||||
self._login("zootech-no-lab", "zootech-no-lab-secret")
|
||||
r = self.client.get("/api/lab/recipes")
|
||||
self.assertEqual(r.status_code, 403, r.get_data(as_text=True))
|
||||
|
||||
def test_lab_api_ok_with_access(self) -> None:
|
||||
self._login("zootech-with-lab", "zootech-with-lab-secret")
|
||||
r = self.client.get("/api/lab/recipes")
|
||||
self.assertEqual(r.status_code, 200, r.get_data(as_text=True))
|
||||
|
||||
def test_components_nutrients_hidden_without_lab_access(self) -> None:
|
||||
self._login("zootech-no-lab", "zootech-no-lab-secret")
|
||||
create = self.client.post(
|
||||
"/api/components",
|
||||
json={
|
||||
"name": "Сено",
|
||||
"type": "Грубые корма",
|
||||
"dry_matter": 88,
|
||||
"price": 10,
|
||||
"nutrients": {"Сырая зола": 50},
|
||||
},
|
||||
)
|
||||
self.assertEqual(create.status_code, 403, create.get_data(as_text=True))
|
||||
|
||||
create_ok = self.client.post(
|
||||
"/api/components",
|
||||
json={"name": "Сено", "type": "Грубые корма", "dry_matter": 88, "price": 10},
|
||||
)
|
||||
self.assertEqual(create_ok.status_code, 201, create_ok.get_data(as_text=True))
|
||||
comp_id = create_ok.get_json()["id"]
|
||||
get_one = self.client.get(f"/api/components/{comp_id}").get_json()
|
||||
self.assertEqual(get_one.get("nutrients"), {})
|
||||
|
||||
def test_admin_can_toggle_lab_access(self) -> None:
|
||||
self._login("zootech-test-admin", "zootech-test-secret")
|
||||
user = db.session.query(WebUser).filter_by(login="zootech-no-lab").one()
|
||||
patch = self.client.patch(
|
||||
f"/api/admin/users/{user.id}",
|
||||
json={"lab_access": True},
|
||||
)
|
||||
self.assertEqual(patch.status_code, 200, patch.get_data(as_text=True))
|
||||
db.session.refresh(user)
|
||||
self.assertTrue(user.lab_access)
|
||||
|
||||
self.client.post("/api/auth/logout")
|
||||
self._login("zootech-no-lab", "zootech-no-lab-secret")
|
||||
r = self.client.get("/api/lab/recipes")
|
||||
self.assertEqual(r.status_code, 200, r.get_data(as_text=True))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user