Skip to content

Commit

Permalink
Merge pull request #567 from CTPUG/feature/group_speakers_by_talk_type
Browse files Browse the repository at this point in the history
Feature/group speakers by talk type
  • Loading branch information
drnlm committed Nov 10, 2020
2 parents 2cccc39 + a2191f4 commit 46814e1
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 28 deletions.
50 changes: 30 additions & 20 deletions wafer/talks/templates/wafer.talks/speakers.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,36 @@
{% block title %}{% trans "Speakers" %} - {{ WAFER_CONFERENCE_NAME }}{% endblock %}
{% block content %}
<section class="wafer wafer-speakers">
<h1>{% trans 'Speakers' %}</h1>
<div class="container">
{% for row in speaker_rows %}
<div class="row">
{% for user_profile in row %}
<div class="col-md-3">
<div class="wafer-speakers-logo">
<a href="{% url 'wafer_user_profile' username=user_profile.user.username %}">
<img class="thumbnail mx-auto" src="{{ user_profile.avatar_url }}">
</a>
{% for talk_type, type_rows in speaker_rows.items %}
{% if talk_type is None %}
<h1>{% trans 'Speakers' %}</h1>
{% else %}
<h1>{% blocktrans %}{{ talk_type }} Speakers{% endblocktrans %}</h1>
{% endif %}
{% if talk_type is None %}
<div class="container speakers-list">
{% else %}
<div class="container {{talk_type|slugify}}-speakers-list">
{% endif %}
{% for row in type_rows %}
<div class="row">
{% for user_profile in row %}
<div class="col-md-3">
<div class="wafer-speakers-logo">
<a href="{% url 'wafer_user_profile' username=user_profile.user.username %}">
<img class="thumbnail mx-auto" src="{{ user_profile.avatar_url }}">
</a>
</div>
<div class="wafer-speakers-name">
<a href="{% url 'wafer_user_profile' username=user_profile.user.username %}">
{{ user_profile.display_name }}
</a>
</div>
</div>
<div class="wafer-speakers-name">
<a href="{% url 'wafer_user_profile' username=user_profile.user.username %}">
{{ user_profile.display_name }}
</a>
</div>
</div>
{% endfor %}
</div>
{% endfor %}
</div>
{% endfor %}
</div>
{% endfor %}
</div>
{% endfor %}
</section>
{% endblock %}
121 changes: 116 additions & 5 deletions wafer/talks/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,27 @@
from wafer.tests.api_utils import SortedResultsClient
from wafer.tests.utils import create_user
from wafer.talks.models import (
Talk, TalkUrl, ACCEPTED, REJECTED, SUBMITTED, UNDER_CONSIDERATION,
CANCELLED, PROVISIONAL)
Talk, TalkUrl, TalkType, ACCEPTED, REJECTED, SUBMITTED,
UNDER_CONSIDERATION, CANCELLED, PROVISIONAL)


def create_talk(title, status, username):
def create_talk_type(name):
"""Create a talk type"""
return TalkType.objects.create(name=name)



def create_talk(title, status, username, talk_type=None):
user = create_user(username)
talk = Talk.objects.create(
title=title, status=status, corresponding_author_id=user.id)
talk.authors.add(user)
talk.notes = "Some notes for talk %s" % title
talk.private_notes = "Some private notes for talk %s" % title
talk.save()
if talk_type:
talk.talk_type = talk_type
talk.save()
return talk


Expand Down Expand Up @@ -360,6 +369,9 @@ def setUp(self):
self.talk_s = create_talk("Talk S", SUBMITTED, "author_s")
self.client = Client()

self.talk_type1 = create_talk_type('Talk')
self.talk_type2 = create_talk_type('Keynote')

@mock.patch('wafer.users.models.UserProfile.avatar_url', mock_avatar_url)
def test_view_one_speaker(self):
img = self.talk_a.corresponding_author.userprofile.avatar_url()
Expand All @@ -370,7 +382,7 @@ def test_view_one_speaker(self):
self.assertContains(response, "\n".join([
'<section class="wafer wafer-speakers">',
'<h1>Speakers</h1>'
'<div class="container">'
'<div class="container speakers-list">'
' <div class="row">',
' <div class="col-md-3">',
' <div class="wafer-speakers-logo">',
Expand Down Expand Up @@ -399,7 +411,7 @@ def check_n_speakers(self, n, expected_rows):
response = self.client.get(
reverse('wafer_talks_speakers'))
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["speaker_rows"], [
self.assertEqual(response.context["speaker_rows"][None], [
profiles[start:end] for start, end in expected_rows
])

Expand All @@ -419,6 +431,105 @@ def test_view_five_speakers(self):
def test_view_seven_speakers(self):
self.check_n_speakers(7, [(0, 4), (4, 7)])

@mock.patch('wafer.users.models.UserProfile.avatar_url', mock_avatar_url)
def test_multiple_types(self):
talk_d = create_talk('Talk D', ACCEPTED, 'author_d', self.talk_type1)
talk_e = create_talk('Talk E', ACCEPTED, 'author_e', self.talk_type1)
keynote_f = create_talk('Talk F', ACCEPTED, 'author_f', self.talk_type2)

user_d = talk_d.corresponding_author
user_e = talk_e.corresponding_author
user_f = keynote_f.corresponding_author

img_d = user_d.userprofile.avatar_url()
img_e = user_e.userprofile.avatar_url()
img_f = user_f.userprofile.avatar_url()

keynote_f.authors.add(user_e)
keynote_f.save()

response = self.client.get(
reverse('wafer_talks_speakers'))
self.assertEqual(response.status_code, 200)
# by_row means we're expecting a list of lists
self.assertEqual(response.context["speaker_rows"]['Talk'],
[[user_d.userprofile, user_e.userprofile]])
self.assertEqual(response.context["speaker_rows"]['Keynote'],
[[user_e.userprofile, user_f.userprofile]])

# Because of how assertHTMLEquals works, we can't combine these
# unless we include the surrounding <section>, which becomes
# unwieldy
self.assertContains(response, "\n".join([
'<h1>Talk Speakers</h1>',
]), html=True)

self.assertContains(response, "\n".join([
'<div class="container talk-speakers-list">',
' <div class="row">',
' <div class="col-md-3">',
' <div class="wafer-speakers-logo">',
' <a href="/users/%s/">' % user_d.username,
' <img class="thumbnail mx-auto" src="%s">' % img_d,
' </a>',
' </div>',
' <div class="wafer-speakers-name">',
' <a href="/users/%s/">' % user_d.username,
' author_d',
' </a>',
' </div>',
' </div>',
' <div class="col-md-3">',
' <div class="wafer-speakers-logo">',
' <a href="/users/%s/">' % user_e.username,
' <img class="thumbnail mx-auto" src="%s">' % img_e,
' </a>',
' </div>',
' <div class="wafer-speakers-name">',
' <a href="/users/%s/">' % user_e.username,
' author_e',
' </a>',
' </div>',
' </div>',
' </div>',
'</div>',
]), html=True)

self.assertContains(response, "\n".join([
'<h1>Keynote Speakers</h1>',
]), html=True)

self.assertContains(response, "\n".join([
'<div class="container keynote-speakers-list">',
' <div class="row">',
' <div class="col-md-3">',
' <div class="wafer-speakers-logo">',
' <a href="/users/%s/">' % user_e.username,
' <img class="thumbnail mx-auto" src="%s">' % img_e,
' </a>',
' </div>',
' <div class="wafer-speakers-name">',
' <a href="/users/%s/">' % user_e.username,
' author_e',
' </a>',
' </div>',
' </div>',
' <div class="col-md-3">',
' <div class="wafer-speakers-logo">',
' <a href="/users/%s/">' % user_f.username,
' <img class="thumbnail mx-auto" src="%s">' % img_f,
' </a>',
' </div>',
' <div class="wafer-speakers-name">',
' <a href="/users/%s/">' % user_f.username,
' author_f',
' </a>',
' </div>',
' </div>',
' </div>',
'</div>',
]), html=True)


class TalkSlugUrlTests(TestCase):
"""Check that we can lookup a talk via correct and incorrect slugs"""
Expand Down
15 changes: 12 additions & 3 deletions wafer/talks/views.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from itertools import groupby

from django.conf import settings
from django.contrib.auth.mixins import (
LoginRequiredMixin, PermissionRequiredMixin)
from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import PermissionDenied, ValidationError
from django.db.models import Q
from django.db.models import Q, F
from django.http import Http404
from django.http import HttpResponseRedirect
from django.urls import reverse_lazy
Expand Down Expand Up @@ -239,8 +241,15 @@ def get_context_data(self, **kwargs):
context = super(Speakers, self).get_context_data(**kwargs)
speakers = UserProfile.objects.filter(
user__talks__status='A').distinct().prefetch_related(
'user').order_by('user__first_name', 'user__last_name')
context["speaker_rows"] = self._by_row(speakers, 4)
'user').order_by('user__talks__talk_type',
'user__first_name',
'user__last_name',
'user__username').annotate(
talk_type=F('user__talks__talk_type__name'))
bytype = groupby(speakers, lambda x: x.talk_type)
context['speaker_rows'] = {}
for talk_type, type_speakers in bytype:
context["speaker_rows"][talk_type] = self._by_row(list(type_speakers), 4)
return context


Expand Down

0 comments on commit 46814e1

Please sign in to comment.