Skip to content

Commit 385a956

Browse files
authored
Merge pull request #344 from VariantEffect/maintenance/bencap/74/update-permitted-licenses
Update Permitted Licenses
2 parents 72a36f4 + 7c864d0 commit 385a956

12 files changed

Lines changed: 192 additions & 3 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""Add active column to licenses
2+
3+
Revision ID: 68a0ec57694e
4+
Revises: 2b6f40ea2fb6
5+
Create Date: 2024-10-22 15:36:41.868909
6+
7+
"""
8+
9+
from alembic import op
10+
import sqlalchemy as sa
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision = "68a0ec57694e"
15+
down_revision = "2b6f40ea2fb6"
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
# ### commands auto generated by Alembic - please adjust! ###
22+
op.add_column("licenses", sa.Column("active", sa.Boolean(), nullable=False, server_default=sa.true()))
23+
# ### end Alembic commands ###
24+
25+
26+
def downgrade():
27+
# ### commands auto generated by Alembic - please adjust! ###
28+
op.drop_column("licenses", "active")
29+
# ### end Alembic commands ###

src/mavedb/models/license.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from datetime import date
22

3-
from sqlalchemy import Column, Date, Integer, String
3+
from sqlalchemy import Boolean, Column, Date, Integer, String
44

55
from mavedb.db.base import Base
66

@@ -16,3 +16,4 @@ class License(Base):
1616
version = Column(String, nullable=True, unique=False)
1717
creation_date = Column(Date, nullable=False, default=date.today)
1818
modification_date = Column(Date, nullable=False, default=date.today, onupdate=date.today)
19+
active = Column(Boolean, nullable=False)

src/mavedb/routers/licenses.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,19 @@ def list_licenses(
2323
return items
2424

2525

26+
@router.get("/active", status_code=200, response_model=List[license.ShortLicense], responses={404: {}})
27+
def list_active_licenses(
28+
*,
29+
db: Session = Depends(deps.get_db),
30+
) -> Any:
31+
"""
32+
List active licenses.
33+
"""
34+
35+
items = db.query(License).where(License.active.is_(True)).order_by(License.short_name).all()
36+
return items
37+
38+
2639
@router.get("/{item_id}", status_code=200, response_model=license.License, responses={404: {}})
2740
def fetch_license(
2841
*,

src/mavedb/routers/score_sets.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,11 @@ async def create_score_set(
348348
if not license_:
349349
logger.info(msg="Failed to create score set; The requested license does not exist.", extra=logging_context())
350350
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Unknown license")
351+
elif not license_.active:
352+
logger.info(
353+
msg="Failed to create score set; The requested license is no longer active.", extra=logging_context()
354+
)
355+
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid license")
351356

352357
save_to_logging_context({"requested_superseded_score_set": item_create.superseded_score_set_urn})
353358
if item_create.superseded_score_set_urn is not None:
@@ -698,6 +703,14 @@ async def update_score_set(
698703
)
699704
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Unknown license")
700705

706+
# Allow in-active licenses to be retained on update if they already exist on the item.
707+
elif not license_.active and item.licence_id != item_update.license_id:
708+
logger.info(
709+
msg="Failed to update score set license; The requested license is no longer active.",
710+
extra=logging_context(),
711+
)
712+
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid license")
713+
701714
item.license = license_
702715

703716
item.doi_identifiers = [

src/mavedb/view_models/license.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class LicenseBase(BaseModel):
1010

1111
long_name: str
1212
short_name: str
13+
active: bool
1314
link: Optional[str]
1415
version: Optional[str]
1516

tests/helpers/constants.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
VALID_GENE = "BRCA1"
1515

1616
SAVED_PUBMED_PUBLICATION = {
17+
"recordType": "PublicationIdentifier",
1718
"identifier": "20711194",
1819
"dbName": "PubMed",
1920
"title": "None",
@@ -28,6 +29,7 @@
2829
}
2930

3031
SAVED_DOI_IDENTIFIER = {
32+
"recordType": "DoiIdentifier",
3133
"identifier": TEST_CROSSREF_IDENTIFIER,
3234
"url": f"https://doi.org/{TEST_CROSSREF_IDENTIFIER}",
3335
"id": 1,
@@ -51,6 +53,7 @@
5153
}
5254

5355
SAVED_CONTRIBUTOR = {
56+
"recordType": "Contributor",
5457
"orcidId": TEST_USER["username"],
5558
"givenName": TEST_USER["first_name"],
5659
"familyName": TEST_USER["last_name"],
@@ -80,6 +83,7 @@
8083
}
8184

8285
SAVED_EXTRA_CONTRIBUTOR = {
86+
"recordType": "Contributor",
8387
"orcidId": EXTRA_USER["username"],
8488
"givenName": EXTRA_USER["first_name"],
8589
"familyName": EXTRA_USER["last_name"],
@@ -347,14 +351,17 @@
347351
"text": "Don't be evil.",
348352
"link": "localhost",
349353
"version": "1.0",
354+
"active": True,
350355
}
351356

352357
SAVED_SHORT_TEST_LICENSE = {
358+
"recordType": "ShortLicense",
353359
"id": TEST_LICENSE["id"],
354360
"shortName": TEST_LICENSE["short_name"],
355361
"longName": TEST_LICENSE["long_name"],
356362
"link": TEST_LICENSE["link"],
357363
"version": TEST_LICENSE["version"],
364+
"active": TEST_LICENSE["active"],
358365
}
359366

360367
EXTRA_LICENSE = {
@@ -364,14 +371,37 @@
364371
"text": "Don't be tooooo evil.",
365372
"link": "localhost",
366373
"version": "1.0",
374+
"active": True,
367375
}
368376

369377
SAVED_SHORT_EXTRA_LICENSE = {
378+
"recordType": "ShortLicense",
370379
"id": EXTRA_LICENSE["id"],
371380
"shortName": EXTRA_LICENSE["short_name"],
372381
"longName": EXTRA_LICENSE["long_name"],
373382
"link": EXTRA_LICENSE["link"],
374383
"version": EXTRA_LICENSE["version"],
384+
"active": EXTRA_LICENSE["active"],
385+
}
386+
387+
TEST_INACTIVE_LICENSE = {
388+
"id": 3,
389+
"short_name": "Long",
390+
"long_name": "Short",
391+
"text": "Be evil.",
392+
"link": "localhost",
393+
"version": "1.0",
394+
"active": False,
395+
}
396+
397+
SAVED_SHORT_INACTIVE_LICENSE = {
398+
"recordType": "ShortLicense",
399+
"id": TEST_INACTIVE_LICENSE["id"],
400+
"shortName": TEST_INACTIVE_LICENSE["short_name"],
401+
"longName": TEST_INACTIVE_LICENSE["long_name"],
402+
"link": TEST_INACTIVE_LICENSE["link"],
403+
"version": TEST_INACTIVE_LICENSE["version"],
404+
"active": TEST_INACTIVE_LICENSE["active"],
375405
}
376406

377407
TEST_SEQ_SCORESET = {

tests/helpers/util.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from mavedb.models.contributor import Contributor
1313
from mavedb.models.enums.processing_state import ProcessingState
1414
from mavedb.models.score_set import ScoreSet as ScoreSetDbModel
15+
from mavedb.models.license import License
1516
from mavedb.models.user import User
1617
from mavedb.view_models.experiment import Experiment, ExperimentCreate
1718
from mavedb.view_models.score_set import ScoreSet, ScoreSetCreate
@@ -52,6 +53,17 @@ def change_ownership(db, urn, model):
5253
db.commit()
5354

5455

56+
def change_to_inactive_license(db, urn):
57+
"""Change the license of the score set with given urn to an inactive license."""
58+
item = db.query(ScoreSetDbModel).filter(ScoreSetDbModel.urn == urn).one_or_none()
59+
assert item is not None
60+
license = db.query(License).filter(License.active.is_(False)).first()
61+
assert license is not None
62+
item.license_id = license.id
63+
db.add(item)
64+
db.commit()
65+
66+
5567
def create_experiment(client, update=None):
5668
experiment_payload = deepcopy(TEST_MINIMAL_EXPERIMENT)
5769
if update is not None:

tests/lib/conftest.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@
55
from mavedb.models.role import Role
66
from mavedb.models.taxonomy import Taxonomy
77
from mavedb.models.user import User
8-
from tests.helpers.constants import ADMIN_USER, EXTRA_USER, TEST_LICENSE, TEST_TAXONOMY, TEST_USER
8+
from tests.helpers.constants import (
9+
ADMIN_USER,
10+
EXTRA_USER,
11+
TEST_LICENSE,
12+
TEST_INACTIVE_LICENSE,
13+
TEST_TAXONOMY,
14+
TEST_USER,
15+
)
916

1017

1118
@pytest.fixture
@@ -20,4 +27,5 @@ def setup_lib_db(session):
2027
db.add(User(**ADMIN_USER, role_objs=[Role(name=UserRole.admin)]))
2128
db.add(Taxonomy(**TEST_TAXONOMY))
2229
db.add(License(**TEST_LICENSE))
30+
db.add(License(**TEST_INACTIVE_LICENSE))
2331
db.commit()

tests/routers/conftest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
TEST_CDOT_TRANSCRIPT,
2020
TEST_DB_KEYWORDS,
2121
TEST_LICENSE,
22+
TEST_INACTIVE_LICENSE,
2223
EXTRA_LICENSE,
2324
TEST_TAXONOMY,
2425
TEST_USER,
@@ -44,6 +45,7 @@ def setup_router_db(session):
4445
db.add(User(**ADMIN_USER, role_objs=[Role(name=UserRole.admin)]))
4546
db.add(Taxonomy(**TEST_TAXONOMY))
4647
db.add(License(**TEST_LICENSE))
48+
db.add(License(**TEST_INACTIVE_LICENSE))
4749
db.add(License(**EXTRA_LICENSE))
4850
db.add(Contributor(**EXTRA_CONTRIBUTOR))
4951
db.bulk_save_objects([ControlledKeyword(**keyword_obj) for keyword_obj in TEST_DB_KEYWORDS])

tests/routers/test_licenses.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import pytest
2+
3+
from tests.helpers.constants import TEST_LICENSE
4+
from tests.helpers.dependency_overrider import DependencyOverrider
5+
6+
7+
@pytest.mark.parametrize("user_overrides", [None, "anonymous_app_overrides", "admin_app_overrides"])
8+
def test_can_list_licenses_as_any_user_class(setup_router_db, client, user_overrides, request):
9+
if user_overrides is not None:
10+
dep_overrides = request.getfixturevalue(user_overrides)
11+
with DependencyOverrider(dep_overrides):
12+
response = client.get("/api/v1/licenses/")
13+
else:
14+
response = client.get("/api/v1/licenses/")
15+
16+
assert response.status_code == 200
17+
response_value = response.json()
18+
assert len(response_value) == 3
19+
20+
21+
@pytest.mark.parametrize("user_overrides", [None, "anonymous_app_overrides", "admin_app_overrides"])
22+
def test_can_list_active_licenses_as_any_user_class(setup_router_db, client, user_overrides, request):
23+
if user_overrides is not None:
24+
dep_overrides = request.getfixturevalue(user_overrides)
25+
with DependencyOverrider(dep_overrides):
26+
response = client.get("/api/v1/licenses/active")
27+
else:
28+
response = client.get("/api/v1/licenses/active")
29+
30+
assert response.status_code == 200
31+
response_value = response.json()
32+
assert len(response_value) == 2
33+
license_state = [_license["active"] for _license in response_value]
34+
assert all(license_state)
35+
36+
37+
def test_can_fetch_arbitrary_license(setup_router_db, client):
38+
response = client.get("/api/v1/licenses/1")
39+
40+
assert response.status_code == 200
41+
response_value = response.json()
42+
response_value["text"] == TEST_LICENSE["text"]
43+
44+
45+
def test_cannot_fetch_nonexistent_license(setup_router_db, client):
46+
response = client.get("/api/v1/licenses/100")
47+
assert response.status_code == 404

0 commit comments

Comments
 (0)