Search now also includes Files and URLs
All checks were successful
Build containers when image tags change / build-if-image-changed (., web, containers, main container, git.baumann.gr/adebaumann/labhelper) (push) Successful in 2m53s
Build containers when image tags change / build-if-image-changed (data-loader, loader, initContainers, init-container, git.baumann.gr/adebaumann/labhelper-data-loader) (push) Successful in 5s

This commit is contained in:
2026-01-01 15:24:42 +01:00
parent b465e7365f
commit 7410f8c607
3 changed files with 111 additions and 3 deletions

View File

@@ -1610,3 +1610,93 @@ class ThingFileAndLinkCRUDTests(AuthTestCase):
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Upload File')
self.assertContains(response, 'Add Link')
def test_search_api_includes_files(self):
"""Search API results should include files."""
ThingFile.objects.create(
thing=self.thing,
title='Datasheet',
file='datasheets/test.pdf'
)
response = self.client.get('/search/api/?q=ard')
self.assertEqual(response.status_code, 200)
results = response.json()['results']
self.assertEqual(len(results), 1)
self.assertEqual(len(results[0]['files']), 1)
self.assertEqual(results[0]['files'][0]['title'], 'Datasheet')
self.assertIn('filename', results[0]['files'][0])
def test_search_api_includes_links(self):
"""Search API results should include links."""
ThingLink.objects.create(
thing=self.thing,
title='Documentation',
url='https://docs.example.com'
)
response = self.client.get('/search/api/?q=ard')
self.assertEqual(response.status_code, 200)
results = response.json()['results']
self.assertEqual(len(results), 1)
self.assertEqual(len(results[0]['links']), 1)
self.assertEqual(results[0]['links'][0]['title'], 'Documentation')
self.assertEqual(results[0]['links'][0]['url'], 'https://docs.example.com')
def test_search_api_shows_empty_files_and_links(self):
"""Search API should show empty arrays for things without files/links."""
response = self.client.get('/search/api/?q=ard')
self.assertEqual(response.status_code, 200)
results = response.json()['results']
self.assertEqual(len(results), 1)
self.assertEqual(results[0]['files'], [])
self.assertEqual(results[0]['links'], [])
def test_search_api_searches_by_file_title(self):
"""Search API should find things by file title."""
ThingFile.objects.create(
thing=self.thing,
title='Datasheet PDF',
file='datasheets/test.pdf'
)
response = self.client.get('/search/api/?q=Datasheet')
self.assertEqual(response.status_code, 200)
results = response.json()['results']
self.assertEqual(len(results), 1)
self.assertEqual(results[0]['name'], self.thing.name)
def test_search_api_searches_by_filename(self):
"""Search API should find things by filename."""
ThingFile.objects.create(
thing=self.thing,
title='Test File',
file='models/part123.stl'
)
response = self.client.get('/search/api/?q=stl')
self.assertEqual(response.status_code, 200)
results = response.json()['results']
self.assertEqual(len(results), 1)
self.assertEqual(results[0]['name'], self.thing.name)
def test_search_api_searches_by_link_title(self):
"""Search API should find things by link title."""
ThingLink.objects.create(
thing=self.thing,
title='Documentation Link',
url='https://docs.example.com/manual.pdf'
)
response = self.client.get('/search/api/?q=Documentation')
self.assertEqual(response.status_code, 200)
results = response.json()['results']
self.assertEqual(len(results), 1)
self.assertEqual(results[0]['name'], self.thing.name)
def test_search_api_searches_by_link_url(self):
"""Search API should find things by link URL."""
ThingLink.objects.create(
thing=self.thing,
title='Manual',
url='https://arduino.cc/products/uno'
)
response = self.client.get('/search/api/?q=arduino')
self.assertEqual(response.status_code, 200)
results = response.json()['results']
self.assertGreater(len(results), 0)

View File

@@ -143,8 +143,12 @@ def search_api(request):
things = Thing.objects.filter(
Q(name__icontains=query) |
Q(description__icontains=query) |
Q(thing_type__name__icontains=query)
).select_related('thing_type', 'box')[:50]
Q(thing_type__name__icontains=query) |
Q(files__title__icontains=query) |
Q(files__file__icontains=query) |
Q(links__title__icontains=query) |
Q(links__url__icontains=query)
).prefetch_related('files', 'links').select_related('thing_type', 'box').distinct()[:50]
results = [
{
@@ -153,6 +157,20 @@ def search_api(request):
'type': thing.thing_type.name,
'box': thing.box.id,
'description': thing.description[:100] if thing.description else '',
'files': [
{
'title': f.title,
'filename': f.filename(),
}
for f in thing.files.all()
],
'links': [
{
'title': l.title,
'url': l.url,
}
for l in thing.links.all()
],
}
for thing in things
]