Skip to content
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
22 changes: 18 additions & 4 deletions src/test/test_link_preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,27 @@ def _class_with_example():

# --- id validation -----------------------------------------------------------

@pytest.mark.parametrize("value", ["FBbt_00003748", "VFB_jrchjrch", "VFBexp_FBtp0000001", "GO_0001872"])
def test_is_term_id_accepts_vfb_shapes(value):
@pytest.mark.parametrize("value", [
# underscored ontology ids
"FBbt_00003748", "VFB_jrchjrch", "VFBexp_FBtp0000001", "GO_0001872",
"GENO_0000346", "FBdv_00007133", "FBbi_00000537",
# FlyBase ids -- no underscore at all
"FBgn0038978", "FBtp0106402", "FBti0004391", "FBrf0247641", "FBal0331598",
# dataset / publication names
"Court2017", "Chiang2010", "Robie2017",
])
def test_is_term_id_accepts_every_shape_get_term_info_resolves(value):
assert link_preview.is_term_id(value)


@pytest.mark.parametrize("value", ["", None, "medulla", "<script>", "../x", "VFB jrch", "_leading"])
def test_is_term_id_rejects_free_text(value):
@pytest.mark.parametrize("value", [
"", None, "<script>", "../x", "VFB jrch", "_leading", "x",
# FlyBase links VFB thumbnails by label rather than id; that must not be
# mistaken for a term.
"P{VT057232-GAL4} expression pattern in adult VNS on Virtual Fly Brain",
"VFB_00101384/thumbnail.png",
])
def test_is_term_id_rejects_junk(value):
assert not link_preview.is_term_id(value)


Expand Down
8 changes: 7 additions & 1 deletion src/vfbquery/ha_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4197,7 +4197,13 @@ async def _term_info_for_preview(request, short_form):
if response.status != 200:
return None
info = json.loads(response.body)
return info if info and info.get("Id") else None
# get_term_info answers 200 with an empty shell for an id it does not know
# (every field null), so presence is not enough: without a Name there is
# nothing to put on a card, and the caller should fall back to its own
# redirect rather than be handed a blank preview.
if not info or not info.get("Id") or not info.get("Name"):
return None
return info


async def handle_get_preview(request):
Expand Down
12 changes: 11 additions & 1 deletion src/vfbquery/link_preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,17 @@
MAX_DESCRIPTION = 300

_MARKDOWN_LINK = re.compile(r"\[([^\]]*)\]\([^)\s]*\)")
_ID_PATTERN = re.compile(r"^[A-Za-z][A-Za-z0-9]*_[A-Za-z0-9_]+$")
# Deliberately broad: VFB ids are not one shape. Underscored ontology ids
# (FBbt_00003748, VFB_jrchjrch, GO_0016811, VFBexp_FBtp0088219) sit alongside
# FlyBase ids with no underscore at all (FBgn0038978, FBtp0106402, FBrf0247641)
# and dataset/publication names (Court2017, Chiang2010) -- all of which
# get_term_info resolves. An earlier pattern required an underscore and so
# silently refused a preview for every FlyBase id and every dataset.
#
# Over-matching is cheap: an id with no term behind it comes back with a null
# Id and is refused as a 404, which is what lets a caller fall back to its
# ordinary redirect. Under-matching is the expensive mistake.
_ID_PATTERN = re.compile(r"^[A-Za-z][A-Za-z0-9_]+$")


def is_term_id(value):
Expand Down
Loading