138 lines
5.3 KiB
Python
138 lines
5.3 KiB
Python
"""Доступ к модулю 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()
|