Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Austenem/CAT-960 Fix EPIC redirects #3583

Merged
merged 10 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG-fix-epic-redirects.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Update support entity and processed/component dataset redirects to go only to the appropriate primary datasets.
46 changes: 16 additions & 30 deletions context/app/routes_browse.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

from .utils import (
get_default_flask_data, make_blueprint, get_client,
get_url_base_from_request, entity_types)
get_url_base_from_request, entity_types, find_raw_dataset_ancestor,
should_redirect_entity)


blueprint = make_blueprint(__name__)
Expand Down Expand Up @@ -48,39 +49,24 @@ def details(type, uuid):
entity = client.get_entity(uuid)
actual_type = entity['entity_type'].lower()

# Redirect to primary dataset if this is
# - a support entity (e.g. an image pyramid)
# - a processed or component dataset
is_support = actual_type == 'support'
is_processed = entity.get('processing') != 'raw' and actual_type == 'dataset'
is_component = entity.get('is_component', False) is True
if (is_support or is_processed or is_component):
supported_entity = client.get_entities(
'datasets',
query_override={
"bool": {
"must": {
"terms": {
"descendant_ids": [uuid]
}
}
}
},
non_metadata_fields=['hubmap_id', 'uuid']
)
if (should_redirect_entity(entity)):
raw_dataset = find_raw_dataset_ancestor(client, entity.get('ancestor_ids'))

pipeline_anchor = entity.get('pipeline', entity.get('hubmap_id')).replace(' ', '')
anchor = quote(f'section-{pipeline_anchor}-{entity.get("status")}').lower()

if len(supported_entity) > 0:
return redirect(
url_for('routes_browse.details',
type='dataset',
uuid=supported_entity[0]['uuid'],
_anchor=anchor,
redirected=True,
redirectedFromId=entity.get('hubmap_id'),
redirectedFromPipeline=entity.get('pipeline')))
if raw_dataset is None or len(raw_dataset) == 0:
abort(404)

# Redirect to the primary dataset
return redirect(
url_for('routes_browse.details',
type='dataset',
uuid=raw_dataset[0].get('uuid'),
_anchor=anchor,
redirected=True,
redirectedFromId=entity.get('hubmap_id'),
redirectedFromPipeline=entity.get('pipeline')))

if type != actual_type:
return redirect(url_for('routes_browse.details', type=actual_type, uuid=uuid))
Expand Down
54 changes: 54 additions & 0 deletions context/app/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,57 @@ def get_organs():
dir_path = Path(dirname(__file__) + '/organ')
organs = {p.stem: safe_load(p.read_text()) for p in dir_path.glob('*.yaml')}
return organs


# Redirect to primary dataset if this entity is
# - non-existent
# - a support entity (e.g. an image pyramid)
# - a processed or component dataset
def should_redirect_entity(entity):
if not entity:
return True

actual_type = entity.get('entity_type').lower()
is_support_type = actual_type == 'support'
is_component = entity.get('is_component', False) is True
is_not_raw_dataset = entity.get('processing') != 'raw' and actual_type == 'dataset'

if is_support_type or is_component or is_not_raw_dataset:
return True

return False


def find_raw_dataset_ancestor(client, ancestor_ids):
return client.get_entities(
'datasets',
query_override={
"bool": {
"must": [
{
"term": {
"processing": "raw"
}
},
{
"terms": {
"uuid": ancestor_ids
}
},
],
"must_not": [
{
"exists": {
"field": "ancestor_counts.entity_type.Dataset"
}
}
]
}
},
non_metadata_fields=[
'uuid',
'processing',
'entity_type',
'is_component'
]
)
111 changes: 111 additions & 0 deletions end-to-end/cypress/e2e/portal/flows/entity-redirects.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/******************************************************************************************
*
* Tests whether entities redirect to the appropriate detail page.
*
* Description:
* ----------------------------------------------------------------------------
* Checks that the title element of each page type is visible and that the URL contains
* the expected UUID.
*
******************************************************************************************/

describe("Entity does not redirect unnecessarily", () => {
const testCases = [
{
name: "Raw dataset",
entityType: "dataset",
uuid: "7b878dd4eceab573447ffd9b429afda8",
},
{
name: "Donor",
entityType: "donor",
uuid: "03b82562be364ef03017f7861e60d723",
},
{
name: "Sample",
entityType: "sample",
uuid: "c18dbe465fe2dfddd96b0382c6c4b38b",
},
{
name: "Collection",
entityType: "collection",
uuid: "3ae4ddfc175d768af5526a010bfe95aa",
},
];

context("macbook-size", () => {
beforeEach(() => {
cy.viewport("macbook-15");
});

testCases.forEach(({ name, entityType, uuid }) => {
it(`${name}`, () => {
cy.visit(`/browse/${entityType}/${uuid}`, { failOnStatusCode: false });
cy.url().should("include", `/browse/${entityType}/${uuid}`);
cy.findByTestId("entity-title").should("exist").and("be.visible");
});
});
});
});

describe("Entity redirects successfully", () => {
const testCases = [
{
name: "Centrally processed dataset",
entityType: "dataset",
uuid: "8fd6bb5cd1a69fc699342eb118565734",
expectedRedirectUuid: "1f3dd0d92f290e9a57db81ce5aea9284",
},
{
name: "Lab processed dataset",
entityType: "dataset",
uuid: "9f37a9b1f6073e6e588ff7e0dd9493b5",
expectedRedirectUuid: "c6a254b2dc2ed46b002500ade163a7cc",
},
{
name: "Support dataset",
entityType: "dataset",
uuid: "72fc3a9360628f251090d030b245e217",
expectedRedirectUuid: "bae7726744880f0d066980e617f1fff3",
},
// TODO: add EPICs when they are available
];

context("macbook-size", () => {
beforeEach(() => {
cy.viewport("macbook-15");
});

testCases.forEach(({ name, entityType, uuid, expectedRedirectUuid }) => {
it(`${name}`, () => {
cy.visit(`/browse/${entityType}/${uuid}`, { failOnStatusCode: false });
cy.url().should("include", `/browse/${entityType}/${expectedRedirectUuid}`);
cy.findByTestId("entity-title").should("exist").and("be.visible");
});
});
});
});

describe("Entity redirects to 404 when appropriate", () => {
const testCases = [
{
name: "Invalid UUID",
entityType: "dataset",
uuid: "not-valid"
},
];

context("macbook-size", () => {
beforeEach(() => {
cy.viewport("macbook-15");
});

testCases.forEach(({ name, entityType, uuid }) => {
it(`${name}`, () => {
cy.visit(`/browse/${entityType}/${uuid}`, { failOnStatusCode: false });
cy.contains("404").should("be.visible");
});
});
});
});

Loading