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

Display Ongoing Events on the Events Page #2167

Closed
wants to merge 4 commits into from
Closed
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
45 changes: 44 additions & 1 deletion events/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ def for_datetime(self, dt=None):
dt = convert_dt_to_aware(dt)
return self.filter(Q(occurring_rule__dt_start__gt=dt) | Q(recurring_rules__finish__gt=dt))

def ongoing_datetime(self, dt=None):
if dt is None:
dt = timezone.now()
else:
dt = convert_dt_to_aware(dt)
return self.filter(
(Q(occurring_rule__dt_start__lt=dt) & Q(occurring_rule__dt_end__gt=dt))
| (Q(recurring_rules__begin__lt=dt) & Q(recurring_rules__finish__gt=dt))
)
Comment on lines +96 to +104
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def ongoing_datetime(self, dt=None):
if dt is None:
dt = timezone.now()
else:
dt = convert_dt_to_aware(dt)
return self.filter(
(Q(occurring_rule__dt_start__lt=dt) & Q(occurring_rule__dt_end__gt=dt))
| (Q(recurring_rules__begin__lt=dt) & Q(recurring_rules__finish__gt=dt))
)
def ongoing_datetime(self, dt=None):
dt = timezone.now() if dt is None else convert_dt_to_aware(dt)
return self.filter(
(Q(occurring_rule__dt_start__lt=dt) & Q(occurring_rule__dt_end__gt=dt))
| (Q(recurring_rules__begin__lt=dt) & Q(recurring_rules__finish__gt=dt))
)


def until_datetime(self, dt=None):
if dt is None:
dt = timezone.now()
Expand Down Expand Up @@ -181,6 +191,39 @@ def next_time(self):
except IndexError:
return None

@property
def present_time(self):
"""
Return the OccurringRule or RecurringRule that are ongoing now.
"""
now = timezone.now()
recurring_start = occurring_start = None

try:
occurring_rule = self.occurring_rule
except OccurringRule.DoesNotExist:
pass
else:
if occurring_rule and occurring_rule.dt_start < now and occurring_rule.dt_end > now:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if occurring_rule and occurring_rule.dt_start < now and occurring_rule.dt_end > now:
if occurring_rule and occurring_rule.dt_start < now < occurring_rule.dt_end:

occurring_start = (occurring_rule.dt_start, occurring_rule)

rrules = self.recurring_rules.filter(begin__lt=now, finish__gt=now)
recurring_starts = [(rule.dt_start, rule) for rule in rrules if rule.dt_start is not None]
recurring_starts.sort(key=itemgetter(0))

try:
recurring_start = recurring_starts[0]
except IndexError:
pass
Comment on lines +214 to +217
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
try:
recurring_start = recurring_starts[0]
except IndexError:
pass
with contextlib.suppress(IndexError):
recurring_start = recurring_starts[0]


starts = [i for i in (recurring_start, occurring_start) if i is not None]
starts.sort(key=itemgetter(0))

try:
return starts[0][1]
except IndexError:
return None

@property
def previous_time(self):
now = timezone.now()
Expand Down Expand Up @@ -216,7 +259,7 @@ def next_or_previous_time(self):

@property
def is_past(self):
return self.next_time is None
return self.next_time is None and self.present_time is None


class RuleMixin:
Expand Down
78 changes: 78 additions & 0 deletions events/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,47 @@ def test_occurring_event(self):
self.assertEqual(self.event.next_time, None)
self.assertTrue(self.event.is_past)

def test_ongoing_occurring_event(self):
now = seconds_resolution(timezone.now())

# Starts before and ends after now
occurring_time_dtstart = now - datetime.timedelta(days=3)
occurring_time_dtend = occurring_time_dtstart + datetime.timedelta(days=5)

ot = OccurringRule.objects.create(
event=self.event,
dt_start=occurring_time_dtstart,
dt_end=occurring_time_dtend,
)

self.assertEqual(Event.objects.ongoing_datetime().count(), 1)
self.assertIsNone(self.event.next_time)
self.assertIsNone(self.event.previous_time)
self.assertIsNotNone(self.event.present_time)
self.assertEqual(self.event.present_time.dt_start, occurring_time_dtstart)
self.assertEqual(self.event.present_time.dt_end, occurring_time_dtend)
self.assertFalse(self.event.is_past)

# Starts before and ends before now
ot.dt_start = now - datetime.timedelta(days=5)
ot.dt_end = now - datetime.timedelta(days=3)
ot.save()

event = Event.objects.get(pk=self.event.pk)
self.assertEqual(Event.objects.ongoing_datetime().count(), 0)
self.assertIsNone(event.present_time)
self.assertTrue(event.is_past)

# Starts after and ends after now
ot.dt_start = now + datetime.timedelta(days=3)
ot.dt_end = now + datetime.timedelta(days=5)
ot.save()

event = Event.objects.get(pk=self.event.pk)
self.assertEqual(Event.objects.ongoing_datetime().count(), 0)
self.assertIsNone(event.present_time)
self.assertFalse(event.is_past)

def test_recurring_event(self):
now = seconds_resolution(timezone.now())

Expand All @@ -71,6 +112,43 @@ def test_recurring_event(self):
self.assertEqual(event.next_time, None)
self.assertEqual(Event.objects.for_datetime().count(), 0)

def test_ongoing_recurring_event(self):
now = seconds_resolution(timezone.now())

# Starts before and ends after now
recurring_time_dtstart = now - datetime.timedelta(days=3)
recurring_time_dtend = recurring_time_dtstart + datetime.timedelta(days=5)

rt = RecurringRule.objects.create(
event=self.event,
begin=recurring_time_dtstart,
finish=recurring_time_dtend,
)
self.assertEqual(Event.objects.ongoing_datetime().count(), 1)
self.assertGreater(self.event.present_time.dt_start, recurring_time_dtstart)
self.assertTrue(rt.valid_dt_end())
self.assertFalse(self.event.is_past)

# Starts before and ends before now
rt.begin = now - datetime.timedelta(days=5)
rt.finish = now - datetime.timedelta(days=3)
rt.save()

event = Event.objects.get(pk=self.event.pk)
self.assertEqual(Event.objects.ongoing_datetime().count(), 0)
self.assertIsNone(event.present_time)
self.assertTrue(event.is_past)

# Starts after and ends after now
rt.begin = now + datetime.timedelta(days=3)
rt.finish = now + datetime.timedelta(days=5)
rt.save()

event = Event.objects.get(pk=self.event.pk)
self.assertEqual(Event.objects.ongoing_datetime().count(), 0)
self.assertIsNone(event.present_time)
self.assertFalse(event.is_past)

def test_rrule(self):
now = seconds_resolution(timezone.now())

Expand Down
7 changes: 6 additions & 1 deletion events/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,12 @@ def get_queryset(self):

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['events_today'] = Event.objects.until_datetime(timezone.now()).filter(calendar__slug=self.kwargs['calendar_slug'])[:2]
context['events_today'] = Event.objects.until_datetime(timezone.now()).filter(
calendar__slug=self.kwargs['calendar_slug']
)[:2]
context['events_ongoing'] = Event.objects.ongoing_datetime(timezone.now()).filter(
calendar__slug=self.kwargs['calendar_slug']
)
context['calendar'] = get_object_or_404(Calendar, slug=self.kwargs['calendar_slug'])
return context

Expand Down
20 changes: 20 additions & 0 deletions templates/events/event_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,26 @@ <h3 class="event-title"><a href="{{ object.get_absolute_url }}">{{ object.title|
</ul>
</div>

{% if events_ongoing %}
<h3 class="widget-title">Ongoing Events</h3>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<h3 class="widget-title">Ongoing Events</h3>
<h3 class="widget-title">Happening Now<h3>

I feel like this is "cooler" but just a nit :)

<ul class="list-recent-events menu">
{% for object in events_ongoing %}
<li>
<h3 class="event-title"><a href="{{ object.get_absolute_url }}">{{ object.title|striptags }}</a></h3>
<p>
{% with object.current_time as next_time %}
{% include "events/includes/time_tag.html" %}
{% endwith %}

{% if object.venue %}
<span class="event-location">{% if object.venue.url %}<a href="{{ object.venue.url }}">{% endif %}{{ object.venue.name }}{% if object.venue.url %}</a>{% endif %}{% if object.venue.address %}, {{ object.venue.address }}{% endif %}</span>
{% endif %}
</p>
</li>
{% endfor %}
</ul>
{% endif %}

{% if events_today %}
<h3 class="widget-title just-missed">You just missed...</h3>
<ul class="list-recent-events menu">
Expand Down