Skip to content

Commit 767fec9

Browse files
authored
fix(db): refresh user after role update to avoid DetachedInstanceError (#6638)
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
1 parent 8a319ce commit 767fec9

4 files changed

Lines changed: 60 additions & 14 deletions

File tree

keep/api/core/db.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,10 +2139,13 @@ def update_user_role(tenant_id, username, role):
21392139
.where(User.tenant_id == tenant_id)
21402140
.where(User.username == username)
21412141
).first()
2142-
if user and user.role != role:
2142+
if not user:
2143+
return None
2144+
if user.role != role:
21432145
user.role = role
21442146
session.add(user)
21452147
session.commit()
2148+
session.refresh(user)
21462149
return user
21472150

21482151

@@ -5989,4 +5992,4 @@ def recover_prev_alert_status(alert: Alert, session: Optional[Session] = None):
59895992
)
59905993
)
59915994
session.exec(query)
5992-
session.commit()
5995+
session.commit()

tests/e2e_tests/incidents_alerts_tests/test_filtering_sort_search_on_alerts.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ def init_test(browser: Page, alerts, max_retries=3):
6666
else:
6767
raise e
6868

69-
browser.wait_for_selector("[data-testid='facet-value']", timeout=10000)
69+
browser.get_by_role("main").locator("[data-testid='facet-value']").first.wait_for(
70+
timeout=30000
71+
)
7072
browser.wait_for_selector(f"text={alerts[0]['name']}", timeout=10000)
7173
rows_count = browser.locator("[data-testid='alerts-table'] table tbody tr").count()
7274
# check that required alerts are loaded and displayed
@@ -88,9 +90,10 @@ def select_one_facet_option(browser, facet_name, option_name):
8890

8991
def assert_facet(browser, facet_name, alerts, alert_property_name: str):
9092
counters_dict = {}
91-
expect(
92-
browser.locator("[data-testid='facet']", has_text=facet_name)
93-
).to_be_visible()
93+
facet_locator = browser.get_by_role("main").locator(
94+
"[data-testid='facet']", has_text=facet_name
95+
)
96+
expect(facet_locator).to_be_visible()
9497
for alert in alerts:
9598
prop_value = None
9699
for prop in alert_property_name.split("."):
@@ -106,8 +109,6 @@ def assert_facet(browser, facet_name, alerts, alert_property_name: str):
106109
counters_dict[prop_value] += 1
107110

108111
for facet_value, count in counters_dict.items():
109-
facet_locator = browser.locator("[data-testid='facet']", has_text=facet_name)
110-
expect(facet_locator).to_be_visible()
111112
facet_value_locator = facet_locator.locator(
112113
"[data-testid='facet-value']", has_text=facet_value
113114
)

tests/e2e_tests/incidents_alerts_tests/test_filtering_sort_search_on_incidents.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ def init_test(browser: Page, incidents, max_retries=3):
3232
else:
3333
raise e
3434

35-
browser.wait_for_selector("[data-testid='facet-value']")
35+
browser.get_by_role("main").locator("[data-testid='facet-value']").first.wait_for(
36+
timeout=30000
37+
)
3638
browser.wait_for_selector("table[data-testid='incidents-table']")
3739

3840

@@ -65,9 +67,10 @@ def select_one_facet_option(browser, facet_name, option_name):
6567

6668
def assert_facet(browser, facet_name, alerts, alert_property_name: str):
6769
counters_dict = {}
68-
expect(
69-
browser.locator("[data-testid='facet']", has_text=facet_name)
70-
).to_be_visible()
70+
facet_locator = browser.get_by_role("main").locator(
71+
"[data-testid='facet']", has_text=facet_name
72+
)
73+
expect(facet_locator).to_be_visible()
7174
for alert in alerts:
7275
prop_value = None
7376
for prop in alert_property_name.split("."):
@@ -86,8 +89,6 @@ def assert_facet(browser, facet_name, alerts, alert_property_name: str):
8689
counters_dict[value] += 1
8790

8891
for facet_value, count in counters_dict.items():
89-
facet_locator = browser.locator("[data-testid='facet']", has_text=facet_name)
90-
expect(facet_locator).to_be_visible()
9192
facet_value_locator = facet_locator.locator(
9293
"[data-testid='facet-value']", has_text=facet_value
9394
)

tests/test_change_password.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,44 @@ def test_admin_can_reset_user_password_via_update(db_session, client, test_app):
177177
# managed_user can sign in with new password
178178
assert _signin(client, "managed_user", "resetpass").status_code == 200
179179
assert _signin(client, "managed_user", "initialpass").status_code == 401
180+
181+
182+
@pytest.mark.parametrize(
183+
"test_app",
184+
[{"AUTH_TYPE": "DB", "KEEP_JWT_SECRET": "somesecret"}],
185+
indirect=True,
186+
)
187+
def test_admin_can_update_user_role_via_update(db_session, client, test_app):
188+
"""An admin can update a local user's role via the update endpoint."""
189+
_create_db_user(db_session, "admin_user", "adminpass", role="admin")
190+
_create_db_user(db_session, "managed_user", "managedpass", role="noc")
191+
192+
signin = _signin(client, "admin_user", "adminpass")
193+
assert signin.status_code == 200
194+
token = signin.json()["accessToken"]
195+
headers = {"Authorization": f"Bearer {token}"}
196+
197+
response = client.put(
198+
"/auth/users/managed_user",
199+
json={"role": "admin"},
200+
headers=headers,
201+
)
202+
assert response.status_code == 200
203+
assert response.json()["role"] == "admin"
204+
assert _signin(client, "managed_user", "managedpass").json()["role"] == "admin"
205+
206+
response = client.put(
207+
"/auth/users/managed_user",
208+
json={"role": "admin"},
209+
headers=headers,
210+
)
211+
assert response.status_code == 200
212+
assert response.json()["role"] == "admin"
213+
214+
response = client.put(
215+
"/auth/users/missing_user",
216+
json={"role": "admin"},
217+
headers=headers,
218+
)
219+
assert response.status_code == 404
220+
assert response.json()["detail"] == "User not found"

0 commit comments

Comments
 (0)