aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2023-04-21 05:24:21 +0300
committerFrederick Muriuki Muriithi2023-04-21 05:24:21 +0300
commit2f6f54e215d7618ab9efa4ed17e09c633db07eab (patch)
tree1bb1eda425e276b6c4cdf9550572dd948b8d5443
parent95f067a542424b76022595a74d660a7e84158f38 (diff)
downloadgenenetwork3-2f6f54e215d7618ab9efa4ed17e09c633db07eab.tar.gz
auth: Attach linked data to specific resources.
-rw-r--r--gn3/auth/authorisation/groups/views.py21
-rw-r--r--gn3/auth/authorisation/resources/models.py53
-rw-r--r--gn3/auth/authorisation/resources/views.py8
-rw-r--r--migrations/auth/20230322_02_Ll854-create-phenotype-resources-table.py6
-rw-r--r--migrations/auth/20230404_02_la33P-create-genotype-resources-table.py6
-rw-r--r--migrations/auth/20230410_02_WZqSf-create-mrna-resources-table.py4
6 files changed, 57 insertions, 41 deletions
diff --git a/gn3/auth/authorisation/groups/views.py b/gn3/auth/authorisation/groups/views.py
index 202df95..9e717a9 100644
--- a/gn3/auth/authorisation/groups/views.py
+++ b/gn3/auth/authorisation/groups/views.py
@@ -180,12 +180,16 @@ def unlinked_phenotype_data(
"ON lpd.data_link_id=pr.data_link_id "
"WHERE lpd.group_id=? AND pr.data_link_id IS NULL",
(str(group.group_id),))
- ids = tuple((
- row["SpeciesId"], row["InbredSetId"], row["PublishFreezeId"],
- row["PublishXRefId"]) for row in authcur.fetchall())
- if len(ids) < 1:
+ results = authcur.fetchall()
+ ids: dict[tuple[str, ...], str] = {
+ (
+ row["SpeciesId"], row["InbredSetId"], row["PublishFreezeId"],
+ row["PublishXRefId"]): row["data_link_id"]
+ for row in results
+ }
+ if len(ids.keys()) < 1:
return tuple()
- paramstr = ", ".join(["(%s, %s, %s, %s)"] * len(ids))
+ paramstr = ", ".join(["(%s, %s, %s, %s)"] * len(ids.keys()))
gn3cur.execute(
"SELECT spc.SpeciesId, spc.SpeciesName, iset.InbredSetId, "
"iset.InbredSetName, pf.Id AS PublishFreezeId, "
@@ -208,7 +212,7 @@ def unlinked_phenotype_data(
"ON pxr.PhenotypeId=phen.Id "
"WHERE (spc.SpeciesId, iset.InbredSetId, pf.Id, pxr.Id) "
f"IN ({paramstr})",
- tuple(item for sublist in ids for item in sublist))
+ tuple(item for sublist in ids.keys() for item in sublist))
return tuple({
**{key: value for key, value in row.items() if key not in
("Post_publication_description", "Pre_publication_description",
@@ -216,7 +220,10 @@ def unlinked_phenotype_data(
"description": (
row["Post_publication_description"] or
row["Pre_publication_description"] or
- row["Original_description"])
+ row["Original_description"]),
+ "data_link_id": ids[tuple(str(row[key]) for key in (
+ "SpeciesId", "InbredSetId", "PublishFreezeId",
+ "PublishXRefId"))]
} for row in gn3cur.fetchall())
@groups.route("/<string:resource_type>/unlinked-data")
diff --git a/gn3/auth/authorisation/resources/models.py b/gn3/auth/authorisation/resources/models.py
index 2e2ff53..bc88691 100644
--- a/gn3/auth/authorisation/resources/models.py
+++ b/gn3/auth/authorisation/resources/models.py
@@ -269,56 +269,53 @@ def resource_by_id(
raise NotFoundError(f"Could not find a resource with id '{resource_id}'")
def __link_mrna_data_to_resource__(
- conn: db.DbConnection, resource: Resource, dataset_id: str) -> dict:
+ conn: db.DbConnection, resource: Resource, data_link_id: UUID) -> dict:
"""Link mRNA Assay data with a resource."""
with db.cursor(conn) as cursor:
params = {
"group_id": str(resource.group.group_id),
"resource_id": str(resource.resource_id),
- "dataset_type": "mRNA",
- "dataset_id": dataset_id
+ "data_link_id": str(data_link_id)
}
cursor.execute(
"INSERT INTO mrna_resources VALUES"
- "(:group_id, :resource_id, :dataset_type, :dataset_id)",
+ "(:group_id, :resource_id, :data_link_id)",
params)
return params
def __link_geno_data_to_resource__(
- conn: db.DbConnection, resource: Resource, dataset_id: str) -> dict:
+ conn: db.DbConnection, resource: Resource, data_link_id: UUID) -> dict:
"""Link Genotype data with a resource."""
with db.cursor(conn) as cursor:
params = {
"group_id": str(resource.group.group_id),
"resource_id": str(resource.resource_id),
- "dataset_type": "Genotype",
- "trait_id": dataset_id
+ "data_link_id": str(data_link_id)
}
cursor.execute(
"INSERT INTO genotype_resources VALUES"
- "(:group_id, :resource_id, :dataset_type, :trait_id)",
+ "(:group_id, :resource_id, :data_link_id)",
params)
return params
def __link_pheno_data_to_resource__(
- conn: db.DbConnection, resource: Resource, dataset_id: str) -> dict:
+ conn: db.DbConnection, resource: Resource, data_link_id: UUID) -> dict:
"""Link Phenotype data with a resource."""
with db.cursor(conn) as cursor:
params = {
"group_id": str(resource.group.group_id),
"resource_id": str(resource.resource_id),
- "dataset_type": "Phenotype",
- "trait_id": dataset_id
+ "data_link_id": str(data_link_id)
}
cursor.execute(
"INSERT INTO phenotype_resources VALUES"
- "(:group_id, :resource_id, :dataset_type, :trait_id)",
+ "(:group_id, :resource_id, :data_link_id)",
params)
return params
def link_data_to_resource(
conn: db.DbConnection, user: User, resource_id: UUID, dataset_type: str,
- dataset_id: str):
+ data_link_id: UUID) -> dict:
"""Link data to resource."""
if not authorised_for(
conn, user, ("group:resource:edit-resource",),
@@ -333,49 +330,49 @@ def link_data_to_resource(
"mrna": __link_mrna_data_to_resource__,
"genotype": __link_geno_data_to_resource__,
"phenotype": __link_pheno_data_to_resource__,
- }[dataset_type.lower()](conn, resource, dataset_id)
+ }[dataset_type.lower()](conn, resource, data_link_id)
def __unlink_mrna_data_to_resource__(
- conn: db.DbConnection, resource: Resource, dataset_id: str) -> dict:
+ conn: db.DbConnection, resource: Resource, data_link_id: UUID) -> dict:
"""Unlink data from mRNA Assay resources"""
with db.cursor(conn) as cursor:
cursor.execute("DELETE FROM mrna_resources "
- "WHERE resource_id=? AND dataset_id=?",
- (str(resource.resource_id), dataset_id))
+ "WHERE resource_id=? AND data_link_id=?",
+ (str(resource.resource_id), str(data_link_id)))
return {
"resource_id": str(resource.resource_id),
"dataset_type": resource.resource_category.resource_category_key,
- "dataset_id": dataset_id
+ "data_link_id": data_link_id
}
def __unlink_geno_data_to_resource__(
- conn: db.DbConnection, resource: Resource, trait_id: str) -> dict:
+ conn: db.DbConnection, resource: Resource, data_link_id: UUID) -> dict:
"""Unlink data from Genotype resources"""
with db.cursor(conn) as cursor:
cursor.execute("DELETE FROM genotype_resources "
- "WHERE resource_id=? AND trait_id=?",
- (str(resource.resource_id), trait_id))
+ "WHERE resource_id=? AND data_link_id=?",
+ (str(resource.resource_id), str(data_link_id)))
return {
"resource_id": str(resource.resource_id),
"dataset_type": resource.resource_category.resource_category_key,
- "dataset_id": trait_id
+ "data_link_id": data_link_id
}
def __unlink_pheno_data_to_resource__(
- conn: db.DbConnection, resource: Resource, trait_id: str) -> dict:
+ conn: db.DbConnection, resource: Resource, data_link_id: UUID) -> dict:
"""Unlink data from Phenotype resources"""
with db.cursor(conn) as cursor:
cursor.execute("DELETE FROM phenotype_resources "
- "WHERE resource_id=? AND trait_id=?",
- (str(resource.resource_id), trait_id))
+ "WHERE resource_id=? AND data_link_id=?",
+ (str(resource.resource_id), str(data_link_id)))
return {
"resource_id": str(resource.resource_id),
"dataset_type": resource.resource_category.resource_category_key,
- "dataset_id": trait_id
+ "data_link_id": str(data_link_id)
}
def unlink_data_from_resource(
- conn: db.DbConnection, user: User, resource_id: UUID, dataset_id: str):
+ conn: db.DbConnection, user: User, resource_id: UUID, data_link_id: UUID):
"""Unlink data from resource."""
if not authorised_for(
conn, user, ("group:resource:edit-resource",),
@@ -391,7 +388,7 @@ def unlink_data_from_resource(
"mrna": __unlink_mrna_data_to_resource__,
"genotype": __unlink_geno_data_to_resource__,
"phenotype": __unlink_pheno_data_to_resource__,
- }[dataset_type.lower()](conn, resource, dataset_id)
+ }[dataset_type.lower()](conn, resource, data_link_id)
def organise_resources_by_category(resources: Sequence[Resource]) -> dict[
ResourceCategory, tuple[Resource]]:
diff --git a/gn3/auth/authorisation/resources/views.py b/gn3/auth/authorisation/resources/views.py
index 5615b11..7b647d3 100644
--- a/gn3/auth/authorisation/resources/views.py
+++ b/gn3/auth/authorisation/resources/views.py
@@ -77,7 +77,7 @@ def link_data():
try:
form = request.form
assert "resource_id" in form, "Resource ID not provided."
- assert "dataset_id" in form, "Dataset ID not provided."
+ assert "data_link_id" in form, "Data Link ID not provided."
assert "dataset_type" in form, "Dataset type not specified"
assert form["dataset_type"].lower() in (
"mrna", "genotype", "phenotype"), "Invalid dataset type provided."
@@ -86,7 +86,7 @@ def link_data():
def __link__(conn: db.DbConnection):
return link_data_to_resource(
conn, the_token.user, uuid.UUID(form["resource_id"]),
- form["dataset_type"], form["dataset_id"])
+ form["dataset_type"], uuid.UUID(form["data_link_id"]))
return jsonify(with_db_connection(__link__))
except AssertionError as aserr:
@@ -101,13 +101,13 @@ def unlink_data():
try:
form = request.form
assert "resource_id" in form, "Resource ID not provided."
- assert "dataset_id" in form, "Dataset ID not provided."
+ assert "data_link_id" in form, "Data Link ID not provided."
with require_oauth.acquire("profile group resource") as the_token:
def __unlink__(conn: db.DbConnection):
return unlink_data_from_resource(
conn, the_token.user, uuid.UUID(form["resource_id"]),
- form["dataset_id"])
+ uuid.UUID(form["data_link_id"]))
return jsonify(with_db_connection(__unlink__))
except AssertionError as aserr:
raise InvalidData(aserr.args[0]) from aserr
diff --git a/migrations/auth/20230322_02_Ll854-create-phenotype-resources-table.py b/migrations/auth/20230322_02_Ll854-create-phenotype-resources-table.py
index 19ee885..7c9e986 100644
--- a/migrations/auth/20230322_02_Ll854-create-phenotype-resources-table.py
+++ b/migrations/auth/20230322_02_Ll854-create-phenotype-resources-table.py
@@ -12,10 +12,14 @@ steps = [
CREATE TABLE IF NOT EXISTS phenotype_resources
-- Link phenotype data to specific resources
(
+ group_id TEXT NOT NULL,
resource_id TEXT NOT NULL, -- A resource can have multiple data items
data_link_id TEXT NOT NULL,
- PRIMARY KEY(resource_id, data_link_id),
+ PRIMARY KEY(group_id, resource_id, data_link_id),
UNIQUE (data_link_id), -- ensure data is linked to only one resource
+ FOREIGN KEY (group_id, resource_id)
+ REFERENCES resources(group_id, resource_id)
+ ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY (data_link_id)
REFERENCES linked_phenotype_data(data_link_id)
ON UPDATE CASCADE ON DELETE RESTRICT
diff --git a/migrations/auth/20230404_02_la33P-create-genotype-resources-table.py b/migrations/auth/20230404_02_la33P-create-genotype-resources-table.py
index e967ce6..1a865e0 100644
--- a/migrations/auth/20230404_02_la33P-create-genotype-resources-table.py
+++ b/migrations/auth/20230404_02_la33P-create-genotype-resources-table.py
@@ -12,10 +12,14 @@ steps = [
CREATE TABLE IF NOT EXISTS genotype_resources
-- Link genotype data to specific resource
(
+ group_id TEXT NOT NULL,
resource_id TEXT NOT NULL, -- A resource can have multiple items
data_link_id TEXT NOT NULL,
- PRIMARY KEY (resource_id, data_link_id),
+ PRIMARY KEY (group_id, resource_id, data_link_id),
UNIQUE (data_link_id) -- ensure data is linked to single resource
+ FOREIGN KEY (group_id, resource_id)
+ REFERENCES resources(group_id, resource_id)
+ ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY (data_link_id)
REFERENCES linked_genotype_data(data_link_id)
ON UPDATE CASCADE ON DELETE RESTRICT
diff --git a/migrations/auth/20230410_02_WZqSf-create-mrna-resources-table.py b/migrations/auth/20230410_02_WZqSf-create-mrna-resources-table.py
index de348c0..2ad1056 100644
--- a/migrations/auth/20230410_02_WZqSf-create-mrna-resources-table.py
+++ b/migrations/auth/20230410_02_WZqSf-create-mrna-resources-table.py
@@ -12,10 +12,14 @@ steps = [
CREATE TABLE IF NOT EXISTS mrna_resources
-- Link mRNA data to specific resource
(
+ group_id TEXT NOT NULL,
resource_id TEXT NOT NULL, -- A resource can have multiple items
data_link_id TEXT NOT NULL,
PRIMARY KEY (resource_id, data_link_id),
UNIQUE (data_link_id) -- ensure data is linked to single resource
+ FOREIGN KEY (group_id, resource_id)
+ REFERENCES resources(group_id, resource_id)
+ ON UPDATE CASCADE ON DELETE RESTRICT,
FOREIGN KEY (data_link_id) REFERENCES linked_mrna_data(data_link_id)
ON UPDATE CASCADE ON DELETE RESTRICT
) WITHOUT ROWID