Skip to content

Commit 7fef9ac

Browse files
committed
fix: fetch_score_set_by_urn permission filtering was effecting calibration permissions
When fetching score sets via this method, score calibration relationships were being unset in an unsafe manner. Because of this, functions in this router were refactored to access score sets directly and load the score set contributors directly when loading calibrations.
1 parent 746be94 commit 7fef9ac

File tree

1 file changed

+84
-23
lines changed

1 file changed

+84
-23
lines changed

src/mavedb/routers/score_calibrations.py

Lines changed: 84 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,30 @@
11
import logging
2+
from typing import Optional
23

34
from fastapi import APIRouter, Depends, HTTPException, Query
4-
from typing import Optional
5-
from sqlalchemy.orm import Session
5+
from sqlalchemy.orm import Session, selectinload
66

77
from mavedb import deps
8+
from mavedb.lib.authentication import UserData, get_current_user
9+
from mavedb.lib.authorization import require_current_user
810
from mavedb.lib.logging import LoggedRoute
911
from mavedb.lib.logging.context import (
1012
logging_context,
1113
save_to_logging_context,
1214
)
13-
from mavedb.lib.authentication import get_current_user, UserData
14-
from mavedb.lib.authorization import require_current_user
1515
from mavedb.lib.permissions import Action, assert_permission, has_permission
1616
from mavedb.lib.score_calibrations import (
1717
create_score_calibration_in_score_set,
18-
modify_score_calibration,
1918
delete_score_calibration,
2019
demote_score_calibration_from_primary,
20+
modify_score_calibration,
2121
promote_score_calibration_to_primary,
2222
publish_score_calibration,
2323
)
2424
from mavedb.models.score_calibration import ScoreCalibration
25-
from mavedb.routers.score_sets import fetch_score_set_by_urn
25+
from mavedb.models.score_set import ScoreSet
2626
from mavedb.view_models import score_calibration
2727

28-
2928
logger = logging.getLogger(__name__)
3029

3130
router = APIRouter(
@@ -52,7 +51,12 @@ def get_score_calibration(
5251
"""
5352
save_to_logging_context({"requested_resource": urn})
5453

55-
item = db.query(ScoreCalibration).where(ScoreCalibration.urn == urn).one_or_none()
54+
item = (
55+
db.query(ScoreCalibration)
56+
.options(selectinload(ScoreCalibration.score_set).selectinload(ScoreSet.contributors))
57+
.where(ScoreCalibration.urn == urn)
58+
.one_or_none()
59+
)
5660
if not item:
5761
logger.debug("The requested score calibration does not exist", extra=logging_context())
5862
raise HTTPException(status_code=404, detail="The requested score calibration does not exist")
@@ -76,12 +80,23 @@ async def get_score_calibrations_for_score_set(
7680
Retrieve all score calibrations for a given score set URN.
7781
"""
7882
save_to_logging_context({"requested_resource": score_set_urn, "resource_property": "calibrations"})
79-
score_set = await fetch_score_set_by_urn(db, score_set_urn, user_data, None, False)
83+
score_set = db.query(ScoreSet).filter(ScoreSet.urn == score_set_urn).one_or_none()
84+
85+
if not score_set:
86+
logger.debug("ScoreSet not found", extra=logging_context())
87+
raise HTTPException(status_code=404, detail=f"ScoreSet with URN '{score_set_urn}' not found")
88+
89+
assert_permission(user_data, score_set, Action.READ)
90+
91+
calibrations = (
92+
db.query(ScoreCalibration)
93+
.filter(ScoreCalibration.score_set_id == score_set.id)
94+
.options(selectinload(ScoreCalibration.score_set).selectinload(ScoreSet.contributors))
95+
.all()
96+
)
8097

8198
permitted_calibrations = [
82-
calibration
83-
for calibration in score_set.score_calibrations
84-
if has_permission(user_data, calibration, Action.READ).permitted
99+
calibration for calibration in calibrations if has_permission(user_data, calibration, Action.READ).permitted
85100
]
86101
if not permitted_calibrations:
87102
logger.debug("No score calibrations found for the requested score set", extra=logging_context())
@@ -105,12 +120,23 @@ async def get_primary_score_calibrations_for_score_set(
105120
Retrieve the primary score calibration for a given score set URN.
106121
"""
107122
save_to_logging_context({"requested_resource": score_set_urn, "resource_property": "calibrations"})
108-
score_set = await fetch_score_set_by_urn(db, score_set_urn, user_data, None, False)
123+
124+
score_set = db.query(ScoreSet).filter(ScoreSet.urn == score_set_urn).one_or_none()
125+
if not score_set:
126+
logger.debug("ScoreSet not found", extra=logging_context())
127+
raise HTTPException(status_code=404, detail=f"ScoreSet with URN '{score_set_urn}' not found")
128+
129+
assert_permission(user_data, score_set, Action.READ)
130+
131+
calibrations = (
132+
db.query(ScoreCalibration)
133+
.filter(ScoreCalibration.score_set_id == score_set.id)
134+
.options(selectinload(ScoreCalibration.score_set).selectinload(ScoreSet.contributors))
135+
.all()
136+
)
109137

110138
permitted_calibrations = [
111-
calibration
112-
for calibration in score_set.score_calibrations
113-
if has_permission(user_data, calibration, Action.READ)
139+
calibration for calibration in calibrations if has_permission(user_data, calibration, Action.READ).permitted
114140
]
115141
if not permitted_calibrations:
116142
logger.debug("No score calibrations found for the requested score set", extra=logging_context())
@@ -155,7 +181,11 @@ async def create_score_calibration_route(
155181

156182
save_to_logging_context({"requested_resource": calibration.score_set_urn, "resource_property": "calibrations"})
157183

158-
score_set = await fetch_score_set_by_urn(db, calibration.score_set_urn, user_data, None, False)
184+
score_set = db.query(ScoreSet).filter(ScoreSet.urn == calibration.score_set_urn).one_or_none()
185+
if not score_set:
186+
logger.debug("ScoreSet not found", extra=logging_context())
187+
raise HTTPException(status_code=404, detail=f"ScoreSet with URN '{calibration.score_set_urn}' not found")
188+
159189
# TODO#539: Allow any authenticated user to upload a score calibration for a score set, not just those with
160190
# permission to update the score set itself.
161191
assert_permission(user_data, score_set, Action.UPDATE)
@@ -187,13 +217,24 @@ async def modify_score_calibration_route(
187217

188218
# If the user supplies a new score_set_urn, validate it exists and the user has permission to use it.
189219
if calibration_update.score_set_urn is not None:
190-
score_set = await fetch_score_set_by_urn(db, calibration_update.score_set_urn, user_data, None, False)
220+
score_set = db.query(ScoreSet).filter(ScoreSet.urn == calibration_update.score_set_urn).one_or_none()
221+
222+
if not score_set:
223+
logger.debug("ScoreSet not found", extra=logging_context())
224+
raise HTTPException(
225+
status_code=404, detail=f"ScoreSet with URN '{calibration_update.score_set_urn}' not found"
226+
)
191227

192228
# TODO#539: Allow any authenticated user to upload a score calibration for a score set, not just those with
193229
# permission to update the score set itself.
194230
assert_permission(user_data, score_set, Action.UPDATE)
195231

196-
item = db.query(ScoreCalibration).where(ScoreCalibration.urn == urn).one_or_none()
232+
item = (
233+
db.query(ScoreCalibration)
234+
.options(selectinload(ScoreCalibration.score_set).selectinload(ScoreSet.contributors))
235+
.where(ScoreCalibration.urn == urn)
236+
.one_or_none()
237+
)
197238
if not item:
198239
logger.debug("The requested score calibration does not exist", extra=logging_context())
199240
raise HTTPException(status_code=404, detail="The requested score calibration does not exist")
@@ -225,7 +266,12 @@ async def delete_score_calibration_route(
225266
"""
226267
save_to_logging_context({"requested_resource": urn})
227268

228-
item = db.query(ScoreCalibration).where(ScoreCalibration.urn == urn).one_or_none()
269+
item = (
270+
db.query(ScoreCalibration)
271+
.options(selectinload(ScoreCalibration.score_set).selectinload(ScoreSet.contributors))
272+
.where(ScoreCalibration.urn == urn)
273+
.one_or_none()
274+
)
229275
if not item:
230276
logger.debug("The requested score calibration does not exist", extra=logging_context())
231277
raise HTTPException(status_code=404, detail="The requested score calibration does not exist")
@@ -259,7 +305,12 @@ async def promote_score_calibration_to_primary_route(
259305
{"requested_resource": urn, "resource_property": "primary", "demote_existing_primary": demote_existing_primary}
260306
)
261307

262-
item = db.query(ScoreCalibration).where(ScoreCalibration.urn == urn).one_or_none()
308+
item = (
309+
db.query(ScoreCalibration)
310+
.options(selectinload(ScoreCalibration.score_set).selectinload(ScoreSet.contributors))
311+
.where(ScoreCalibration.urn == urn)
312+
.one_or_none()
313+
)
263314
if not item:
264315
logger.debug("The requested score calibration does not exist", extra=logging_context())
265316
raise HTTPException(status_code=404, detail="The requested score calibration does not exist")
@@ -318,7 +369,12 @@ def demote_score_calibration_from_primary_route(
318369
"""
319370
save_to_logging_context({"requested_resource": urn, "resource_property": "primary"})
320371

321-
item = db.query(ScoreCalibration).where(ScoreCalibration.urn == urn).one_or_none()
372+
item = (
373+
db.query(ScoreCalibration)
374+
.options(selectinload(ScoreCalibration.score_set).selectinload(ScoreSet.contributors))
375+
.where(ScoreCalibration.urn == urn)
376+
.one_or_none()
377+
)
322378
if not item:
323379
logger.debug("The requested score calibration does not exist", extra=logging_context())
324380
raise HTTPException(status_code=404, detail="The requested score calibration does not exist")
@@ -352,7 +408,12 @@ def publish_score_calibration_route(
352408
"""
353409
save_to_logging_context({"requested_resource": urn, "resource_property": "private"})
354410

355-
item = db.query(ScoreCalibration).where(ScoreCalibration.urn == urn).one_or_none()
411+
item = (
412+
db.query(ScoreCalibration)
413+
.options(selectinload(ScoreCalibration.score_set).selectinload(ScoreSet.contributors))
414+
.where(ScoreCalibration.urn == urn)
415+
.one_or_none()
416+
)
356417
if not item:
357418
logger.debug("The requested score calibration does not exist", extra=logging_context())
358419
raise HTTPException(status_code=404, detail="The requested score calibration does not exist")

0 commit comments

Comments
 (0)