Skip to content

Commit

Permalink
Merge pull request #117 from orangespaceman/lm/searchable-performaances
Browse files Browse the repository at this point in the history
Make content of Results from Events/Performances searchable (#113)
  • Loading branch information
lachiemurray authored Oct 2, 2024
2 parents 61916b2 + 1fe513f commit f0e0283
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 13 deletions.
4 changes: 2 additions & 2 deletions frontend/components/global/Result/Result.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ <h3 class="Result-title">
{% endif %}
{% for event in result.event_set.all %}
{% if result.event_set.all|length > 1 %}
<h4 class="Result-eventTitle">{{event.name}}</h4>
<h4 class="Result-eventTitle">{{event.name|highlight:search|safe}}</h4>
{% endif %}
<p class="Result-event">
<table>
Expand All @@ -43,7 +43,7 @@ <h4 class="Result-eventTitle">{{event.name}}</h4>
</tr>
{% for performance in event.performance_set.all %}
<tr>
<td>{{performance.athlete.first_name}} {{performance.athlete.last_name}}</td>
<td>{{performance.athlete.full_name|highlight:search|safe}}</td>
<td>{{performance.category}}</td>
<td>{{performance.distance}}</td>
<td>{{performance.overall_position}}</td>
Expand Down
4 changes: 4 additions & 0 deletions phx/athletes/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,9 @@ class Athlete(models.Model):
null=True,
)

@property
def full_name(self) -> str:
return f"{self.first_name} {self.last_name}"

def __str__(self) -> str:
return f"{self.first_name} {self.last_name} ({self.age_category})"
19 changes: 19 additions & 0 deletions phx/athletes/tests/factories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from datetime import datetime, timezone

from factory.fuzzy import FuzzyDateTime, FuzzyText
from factory_djoy import CleanModelFactory

from ..models import Athlete


class AthleteFactory(CleanModelFactory):
first_name = FuzzyText()
last_name = FuzzyText()
age_category = FuzzyText(length=3)
gender = FuzzyText(length=1)
power_of_10_id = FuzzyText()
last_checked = FuzzyDateTime(datetime.now(timezone.utc))

class Meta:
model = Athlete
skip_postgeneration_save = True
12 changes: 9 additions & 3 deletions phx/phx/templatetags/highlight.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import re

from django import template

register = template.Library()
Expand All @@ -8,6 +10,10 @@ def highlight(full_text, search_term):
"""Wraps all values of search_term"""
if full_text is None or len(search_term) == 0:
return full_text
replacement_text = '{}{}{}'.format('<span class="u-highlight">',
search_term, '</span>')
return full_text.replace(search_term, replacement_text)

# Use a replacer function in order to maintain the original case
def replacer(match):
return '<span class="u-highlight">{}</span>'.format(match.group(0))

pattern = re.compile(re.escape(search_term), re.IGNORECASE)
return pattern.sub(replacer, full_text)
13 changes: 13 additions & 0 deletions phx/phx/tests/templatetags/test_highlight.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,16 @@ def test_None_text_dont_replace_text(self):
results = highlight(None, 'foo bar')

self.assertEqual(results, None)

def test_case_insensitive(self):
"""
Case insensitive search
"""
full_text = 'Lorem ipsum dolor sit amet'
search_term = 'LOREM'
expected = ('<span class="u-highlight">Lorem</span> ipsum '
'dolor sit amet')

results = highlight(full_text, search_term)

self.assertEqual(results, expected)
38 changes: 35 additions & 3 deletions phx/results/tests/factories.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from datetime import datetime
from datetime import datetime, timezone

from factory import post_generation
from factory.fuzzy import FuzzyDate, FuzzyText
from factory.fuzzy import FuzzyDate, FuzzyDateTime, FuzzyInteger, FuzzyText
from factory_djoy import CleanModelFactory

from ..models import Result
from ..models import Event, Performance, Result


class ResultFactory(CleanModelFactory):
Expand All @@ -27,3 +27,35 @@ def categories(self, create, extracted, **kwargs):
class Meta:
model = Result
skip_postgeneration_save = True


class EventFactory(CleanModelFactory):
name = FuzzyText()
location = FuzzyText()
power_of_10_meeting_id = FuzzyText()

class Meta:
model = Event
skip_postgeneration_save = True


class FuzzyTime(FuzzyDateTime):

def fuzz(self):
return super().fuzz().time()


class PerformanceFactory(CleanModelFactory):
date = FuzzyDate(datetime.now().date())
distance = FuzzyText()
category = FuzzyText(length=4)
overall_position = FuzzyText(length=2)
time = FuzzyDateTime(datetime.now(
timezone.utc)).fuzz().strftime('%H:%M:%S')
round = FuzzyText(length=1)
gender_position = FuzzyInteger(1)
age_position = FuzzyInteger(1)

class Meta:
model = Performance
skip_postgeneration_save = True
38 changes: 37 additions & 1 deletion phx/results/tests/views/test_results_view.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from datetime import datetime, timedelta

from athletes.tests.factories import AthleteFactory
from django.test import TestCase
from django.urls import reverse
from django.utils import timezone
Expand All @@ -8,7 +9,7 @@
from pages.models import Page

from ...models import Result
from ..factories import ResultFactory
from ..factories import EventFactory, PerformanceFactory, ResultFactory


class TestResultsView(TestCase):
Expand Down Expand Up @@ -140,6 +141,41 @@ def test_result_category_search_empty(self):
response = self.client.get(url, {'search': 'cat 3'})
self.assertEqual(len(response.context['results']), 0)

def test_result_athlete_search(self):
"""
GET request retrieves results filtered by search
"""
Page.objects.create(title='results')
url = reverse('results-index')

result = ResultFactory(title='parkrun')
john = AthleteFactory(first_name='John', last_name='Doe')
jane = AthleteFactory(first_name='Jane', last_name='Doe')
event = EventFactory(result=result)
PerformanceFactory(athlete=john, event=event)
PerformanceFactory(athlete=jane, event=event)

response = self.client.get(url, {'search': 'john doe'})
self.assertEqual(len(response.context['results']), 1)

def test_result_event_name_search(self):
"""
GET request retrieves results filtered by search
"""
Page.objects.create(title='results')
url = reverse('results-index')

result = ResultFactory(title='parkrun')
john = AthleteFactory(first_name='John', last_name='Doe')
jane = AthleteFactory(first_name='Jane', last_name='Doe')
first_event = EventFactory(name='Preston Park', result=result)
second_event = EventFactory(name='Hove Prom', result=result)
PerformanceFactory(athlete=john, event=first_event)
PerformanceFactory(athlete=jane, event=second_event)

response = self.client.get(url, {'search': 'Preston'})
self.assertEqual(len(response.context['results']), 1)

def test_get_year(self):
""""
GET request uses year, tested against gallery dates
Expand Down
17 changes: 13 additions & 4 deletions phx/results/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from datetime import datetime

from components.models import COMPONENT_TYPES
from django.db.models import Q
from django.db.models import Q, Value
from django.db.models.functions import Concat
from django.shortcuts import get_object_or_404
from django.urls import reverse
from django.utils import timezone
Expand All @@ -12,7 +13,7 @@

from phx.helpers.subnav import generate_subnav

from .models import Result
from .models import Athlete, Result

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -53,11 +54,19 @@ def get_queryset(self):

search = self.request.GET.get('search')
if search:
athletes = Athlete.objects.annotate(full_name=Concat(
'first_name', Value(' '), 'last_name')).filter(
full_name__icontains=search)

query = query.filter(
Q(summary__icontains=search) | Q(results__icontains=search)
Q(summary__icontains=search)
| Q(results__icontains=search)
| Q(title__icontains=search)
| Q(categories__abbreviation__icontains=search)
| Q(categories__title__icontains=search))
| Q(categories__title__icontains=search)
| Q(event__location__icontains=search)
| Q(event__name__icontains=search)
| Q(event__performance__athlete__in=athletes))

category = self.request.GET.get('category')
if category:
Expand Down

0 comments on commit f0e0283

Please sign in to comment.