nci-cidc-api-modules 1.2.1__tar.gz → 1.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nci_cidc_api_modules-1.2.1/nci_cidc_api_modules.egg-info → nci_cidc_api_modules-1.2.3}/PKG-INFO +3 -3
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/README.md +1 -1
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/config/db.py +5 -33
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/models/files/facets.py +5 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/models/models.py +48 -4
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3/nci_cidc_api_modules.egg-info}/PKG-INFO +3 -3
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/nci_cidc_api_modules.egg-info/requires.txt +1 -1
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/requirements.modules.txt +1 -1
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/tests/test_api.py +1 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/LICENSE +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/MANIFEST.in +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/config/__init__.py +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/config/logging.py +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/config/secrets.py +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/config/settings.py +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/models/__init__.py +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/models/files/__init__.py +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/models/files/details.py +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/models/migrations.py +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/models/schemas.py +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/shared/__init__.py +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/shared/auth.py +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/shared/emails.py +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/shared/file_handling.py +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/shared/gcloud_client.py +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/shared/jose.py +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/cidc_api/shared/rest_utils.py +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/nci_cidc_api_modules.egg-info/SOURCES.txt +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/nci_cidc_api_modules.egg-info/dependency_links.txt +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/nci_cidc_api_modules.egg-info/not-zip-safe +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/nci_cidc_api_modules.egg-info/top_level.txt +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/pyproject.toml +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/setup.cfg +0 -0
- {nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/setup.py +0 -0
{nci_cidc_api_modules-1.2.1/nci_cidc_api_modules.egg-info → nci_cidc_api_modules-1.2.3}/PKG-INFO
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: nci_cidc_api_modules
|
3
|
-
Version: 1.2.
|
3
|
+
Version: 1.2.3
|
4
4
|
Summary: SQLAlchemy data models and configuration tools used in the NCI CIDC API
|
5
5
|
Home-page: https://github.com/NCI-CIDC/cidc-api-gae
|
6
6
|
License: MIT license
|
@@ -29,7 +29,7 @@ Requires-Dist: requests>=2.32.5
|
|
29
29
|
Requires-Dist: jinja2>=3.1.6
|
30
30
|
Requires-Dist: certifi>=2025.8.3
|
31
31
|
Requires-Dist: cloud-sql-python-connector[pg8000]>=1.18.4
|
32
|
-
Requires-Dist: nci-cidc-schemas==0.28.
|
32
|
+
Requires-Dist: nci-cidc-schemas==0.28.3
|
33
33
|
Dynamic: description
|
34
34
|
Dynamic: description-content-type
|
35
35
|
Dynamic: home-page
|
@@ -395,7 +395,7 @@ API authentication relies on _identity tokens_ generated by Auth0 to verify that
|
|
395
395
|
|
396
396
|
- It is a well-formatted JWT.
|
397
397
|
- It has not yet expired.
|
398
|
-
- Its cryptographic signature is valid.
|
398
|
+
- Its cryptographic signature is valid.
|
399
399
|
|
400
400
|
JWTs are a lot like passports - they convey personal information, they’re issued by a trusted entity, and they expire after a certain time. Moreover, like passports, JWTs **can be stolen** and used to impersonate someone. As such, JWTs should be kept private and treated sort of like short-lived passwords.
|
401
401
|
|
@@ -354,7 +354,7 @@ API authentication relies on _identity tokens_ generated by Auth0 to verify that
|
|
354
354
|
|
355
355
|
- It is a well-formatted JWT.
|
356
356
|
- It has not yet expired.
|
357
|
-
- Its cryptographic signature is valid.
|
357
|
+
- Its cryptographic signature is valid.
|
358
358
|
|
359
359
|
JWTs are a lot like passports - they convey personal information, they’re issued by a trusted entity, and they expire after a certain time. Moreover, like passports, JWTs **can be stolen** and used to impersonate someone. As such, JWTs should be kept private and treated sort of like short-lived passwords.
|
360
360
|
|
@@ -45,33 +45,7 @@ def get_sqlalchemy_database_uri(testing: bool = False) -> str:
|
|
45
45
|
# Connect to the test database
|
46
46
|
db_uri = environ.get("TEST_POSTGRES_URI", "fake-conn-string")
|
47
47
|
elif not db_uri:
|
48
|
-
|
49
|
-
# db_uri = f"postgresql+pg8000://{environ.get('CLOUD_SQL_DB_USER')}:xxx@/{environ.get('CLOUD_SQL_DB_NAME')}"
|
50
|
-
|
51
|
-
secrets = get_secrets_manager(testing)
|
52
|
-
|
53
|
-
# If POSTGRES_URI env variable is not set,
|
54
|
-
# we're connecting to a Cloud SQL instance.
|
55
|
-
|
56
|
-
config: dict = {
|
57
|
-
"drivername": "postgresql",
|
58
|
-
"username": environ.get("CLOUD_SQL_DB_USER"),
|
59
|
-
"password": secrets.get(environ.get("CLOUD_SQL_DB_PASS_ID")),
|
60
|
-
"database": environ.get("CLOUD_SQL_DB_NAME"),
|
61
|
-
}
|
62
|
-
|
63
|
-
if environ.get("CLOUD_SQL_INSTANCE_NAME"):
|
64
|
-
socket_dir = environ.get("CLOUD_SQL_SOCKET_DIR", "/cloudsql/")
|
65
|
-
|
66
|
-
# If CLOUD_SQL_INSTANCE_NAME is defined, we're connecting
|
67
|
-
# via a unix socket from inside App Engine.
|
68
|
-
config["query"] = {"host": f'{socket_dir}{environ.get("CLOUD_SQL_INSTANCE_NAME")}'}
|
69
|
-
else:
|
70
|
-
raise RuntimeError(
|
71
|
-
"Either POSTGRES_URI or CLOUD_SQL_INSTANCE_NAME must be defined to connect " + "to a database."
|
72
|
-
)
|
73
|
-
|
74
|
-
db_uri = str(URL.create(**config).render_as_string(hide_password=False))
|
48
|
+
db_uri = f"postgresql+pg8000://{environ.get('CLOUD_SQL_DB_USER')}:xxx@/{environ.get('CLOUD_SQL_DB_NAME')}"
|
75
49
|
|
76
50
|
assert db_uri
|
77
51
|
|
@@ -80,9 +54,7 @@ def get_sqlalchemy_database_uri(testing: bool = False) -> str:
|
|
80
54
|
|
81
55
|
# Use SQLALCHEMY_ENGINE_OPTIONS to connect to the cloud but use uri for local db
|
82
56
|
def cloud_connector(testing: bool = False):
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
# else:
|
88
|
-
# return {}
|
57
|
+
if not testing and not environ.get("POSTGRES_URI"):
|
58
|
+
return {"creator": getconn}
|
59
|
+
else:
|
60
|
+
return {}
|
@@ -361,6 +361,11 @@ assay_facets: Facets = {
|
|
361
361
|
"colorized image": FacetConfig(["/visium/colorized.tiff"]),
|
362
362
|
"cytassist image": FacetConfig(["/visium/cytassist.tiff"]),
|
363
363
|
},
|
364
|
+
"NULISA": {
|
365
|
+
"Metadata": FacetConfig(["/nulisa/metadata.csv", "Metadata for NULISA run"]),
|
366
|
+
"NPQ File": FacetConfig(["/nulisa/npq_file.csv", "NPQ file for NULISA run"]),
|
367
|
+
"Raw Counts File": FacetConfig(["/nulisa/raw_counts_file.csv", "Raw counts file for NULISA run"]),
|
368
|
+
},
|
364
369
|
"mIHC": {
|
365
370
|
"Samples Report": FacetConfig(["/mihc/sample_report.csv"], "Samples report for mIHC run"),
|
366
371
|
"Multitiffs": FacetConfig(["/mihc/multitiffs.tar.gz"], "Multi Tiffs file from mIHC run"),
|
@@ -26,6 +26,7 @@ __all__ = [
|
|
26
26
|
"FileValidationErrors",
|
27
27
|
"IngestionJobs",
|
28
28
|
"JobFileCategories",
|
29
|
+
"ValidationConfigs",
|
29
30
|
"TRIAL_APPENDIX_A",
|
30
31
|
"REQUEST_LETTER",
|
31
32
|
"ADMIN_FILE_CATEGORIES",
|
@@ -531,6 +532,7 @@ class IAMException(Exception):
|
|
531
532
|
EXTRA_DATA_TYPES = [
|
532
533
|
"participants info",
|
533
534
|
"samples info",
|
535
|
+
"clinical_upload",
|
534
536
|
"file_group",
|
535
537
|
]
|
536
538
|
ALL_UPLOAD_TYPES = set(
|
@@ -3117,7 +3119,7 @@ class DownloadableFiles(CommonColumns):
|
|
3117
3119
|
cls.file_purpose.label(purp_col.key),
|
3118
3120
|
func.json_agg(cls.id).label(ids_col.key),
|
3119
3121
|
)
|
3120
|
-
.group_by(cls.trial_id,
|
3122
|
+
.group_by(cls.trial_id, type_col, purp_col)
|
3121
3123
|
.alias("id_bundles")
|
3122
3124
|
)
|
3123
3125
|
purpose_bundles = (
|
@@ -3429,7 +3431,7 @@ class IngestionJobs(CommonColumns):
|
|
3429
3431
|
trial_id = Column(String, nullable=False)
|
3430
3432
|
version = Column(Integer, nullable=False)
|
3431
3433
|
pending = Column(Boolean, nullable=False, default=False)
|
3432
|
-
start_date = Column(
|
3434
|
+
start_date = Column(DateTime, nullable=True)
|
3433
3435
|
|
3434
3436
|
@staticmethod
|
3435
3437
|
@with_default_session
|
@@ -3497,11 +3499,33 @@ class IngestionJobs(CommonColumns):
|
|
3497
3499
|
.first()
|
3498
3500
|
)
|
3499
3501
|
|
3500
|
-
# TODO: figure out which users have access to which jobs
|
3501
3502
|
@classmethod
|
3502
3503
|
@with_default_session
|
3503
3504
|
def get_open_jobs_for_user(cls, user: Users, session: Session = None) -> list["IngestionJobs"]:
|
3504
|
-
|
3505
|
+
if user.role not in [CIDCRole.ADMIN.value, CIDCRole.CLINICAL_TRIAL_USER.value]:
|
3506
|
+
return []
|
3507
|
+
job_query = session.query(cls).filter(cls.status.notin_(["DRAFT"]))
|
3508
|
+
if (
|
3509
|
+
user.role != CIDCRole.ADMIN.value
|
3510
|
+
and not session.query(Permissions)
|
3511
|
+
.filter(
|
3512
|
+
Permissions.granted_to_user == user.id,
|
3513
|
+
Permissions.upload_type == "clinical_upload",
|
3514
|
+
Permissions.trial_id == Permissions.EVERY,
|
3515
|
+
)
|
3516
|
+
.all()
|
3517
|
+
):
|
3518
|
+
authorized_trials = (
|
3519
|
+
session.query(Permissions)
|
3520
|
+
.filter(
|
3521
|
+
Permissions.granted_to_user == user.id,
|
3522
|
+
Permissions.upload_type == "clinical_upload",
|
3523
|
+
Permissions.trial_id != Permissions.EVERY,
|
3524
|
+
)
|
3525
|
+
.all()
|
3526
|
+
)
|
3527
|
+
job_query = job_query.filter(cls.trial_id.in_(map(lambda x: x.trial_id, authorized_trials)))
|
3528
|
+
return job_query.order_by(cls._created.desc()).all()
|
3505
3529
|
|
3506
3530
|
|
3507
3531
|
class JobFileCategories(CommonColumns):
|
@@ -3579,3 +3603,23 @@ class FileValidationErrors(CommonColumns):
|
|
3579
3603
|
if file_ids:
|
3580
3604
|
session.query(cls).filter(cls.file_id.in_(file_ids)).delete(synchronize_session=False)
|
3581
3605
|
session.commit()
|
3606
|
+
|
3607
|
+
@classmethod
|
3608
|
+
@with_default_session
|
3609
|
+
def get_errors_for_job_sorted_by_file_id(cls, job_id: int, session: Session = None) -> list["FileValidationErrors"]:
|
3610
|
+
return session.query(cls).filter(cls.job_id == job_id).order_by(cls.file_id.asc()).all()
|
3611
|
+
|
3612
|
+
|
3613
|
+
class ValidationConfigs(CommonColumns):
|
3614
|
+
__tablename__ = "validation_configs"
|
3615
|
+
|
3616
|
+
data_label = Column(String, nullable=True)
|
3617
|
+
validation = Column(String, nullable=True)
|
3618
|
+
scope = Column(String, nullable=True)
|
3619
|
+
active = Column(Boolean, nullable=False, default=True, server_default="true")
|
3620
|
+
|
3621
|
+
@classmethod
|
3622
|
+
@with_default_session
|
3623
|
+
def get_active_configs_by_scope(cls, scope: str, session=None) -> list["ValidationConfigs"]:
|
3624
|
+
"""Return all active ValidationConfigs rows for the given scope."""
|
3625
|
+
return session.query(cls).filter(cls.scope == scope, cls.active.is_(True)).all()
|
{nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3/nci_cidc_api_modules.egg-info}/PKG-INFO
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: nci_cidc_api_modules
|
3
|
-
Version: 1.2.
|
3
|
+
Version: 1.2.3
|
4
4
|
Summary: SQLAlchemy data models and configuration tools used in the NCI CIDC API
|
5
5
|
Home-page: https://github.com/NCI-CIDC/cidc-api-gae
|
6
6
|
License: MIT license
|
@@ -29,7 +29,7 @@ Requires-Dist: requests>=2.32.5
|
|
29
29
|
Requires-Dist: jinja2>=3.1.6
|
30
30
|
Requires-Dist: certifi>=2025.8.3
|
31
31
|
Requires-Dist: cloud-sql-python-connector[pg8000]>=1.18.4
|
32
|
-
Requires-Dist: nci-cidc-schemas==0.28.
|
32
|
+
Requires-Dist: nci-cidc-schemas==0.28.3
|
33
33
|
Dynamic: description
|
34
34
|
Dynamic: description-content-type
|
35
35
|
Dynamic: home-page
|
@@ -395,7 +395,7 @@ API authentication relies on _identity tokens_ generated by Auth0 to verify that
|
|
395
395
|
|
396
396
|
- It is a well-formatted JWT.
|
397
397
|
- It has not yet expired.
|
398
|
-
- Its cryptographic signature is valid.
|
398
|
+
- Its cryptographic signature is valid.
|
399
399
|
|
400
400
|
JWTs are a lot like passports - they convey personal information, they’re issued by a trusted entity, and they expire after a certain time. Moreover, like passports, JWTs **can be stolen** and used to impersonate someone. As such, JWTs should be kept private and treated sort of like short-lived passwords.
|
401
401
|
|
@@ -441,6 +441,7 @@ def test_endpoint_urls(cidc_api):
|
|
441
441
|
"/jobs/<int:job_id>",
|
442
442
|
"/jobs/<int:job_id>/files",
|
443
443
|
"/jobs/<int:job_id>/status",
|
444
|
+
"/jobs/<int:job_id>/error_report",
|
444
445
|
"/jobs/trials/<string:trial_id>/current",
|
445
446
|
"/permissions/",
|
446
447
|
"/permissions/<int:permission>",
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/nci_cidc_api_modules.egg-info/SOURCES.txt
RENAMED
File without changes
|
File without changes
|
{nci_cidc_api_modules-1.2.1 → nci_cidc_api_modules-1.2.3}/nci_cidc_api_modules.egg-info/not-zip-safe
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|