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

Implemented speaker detail page and enchanced model #108

Merged
merged 2 commits into from
Jun 21, 2017
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
1 change: 1 addition & 0 deletions pybay/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ def save_to_models(self):
meetup_talk=data['meetup_talk'],
speaker_and_talk_history=data['speaker_and_talk_history'],
talk_links=data['links_to_past_talks'],
speaker_website=data['website'],
)

# Email submitter
Expand Down
5 changes: 3 additions & 2 deletions pybay/proposals/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

from .models import TalkProposal, TutorialProposal


class TalkProposalAdmin(admin.ModelAdmin):
list_display = ('title', 'speaker')
pass
list_display = ('title', 'speaker', 'status')


admin.site.register(TalkProposal, TalkProposalAdmin)
admin.site.register(TutorialProposal)
25 changes: 25 additions & 0 deletions pybay/proposals/migrations/0005_auto_20170614_0036.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.2 on 2017-06-14 04:36
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('proposals', '0004_auto_20170516_2218'),
]

operations = [
migrations.AddField(
model_name='talkproposal',
name='speaker_website',
field=models.TextField(null=True),
),
migrations.AddField(
model_name='tutorialproposal',
name='speaker_website',
field=models.TextField(null=True),
),
]
1 change: 1 addition & 0 deletions pybay/proposals/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class Proposal(ProposalBase):
what_will_attendees_learn = models.TextField()
meetup_talk = models.CharField(choices=MEETUP_CHOICES, max_length=100, default="No")
speaker_and_talk_history = models.TextField()
speaker_website = models.TextField(null=True, blank=True)

class Meta:
abstract = True
Expand Down
52 changes: 52 additions & 0 deletions pybay/templates/frontend/speakers_detail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{% extends 'frontend/base.html' %}
{% load static %}
{% load thumbnail %}
{% block content %}
<section>
<div class="container" style="padding-top: 150px;">
<div class="row">
<div class="col-sm-6 col-md-4">
<a href="{{ speaker.photo.url }}">
<div>
<img class="img-responsive" alt="{{ speaker.name }}" src="{{ speaker.photo.url }}">
</div>
</a>
</div>
<div class="col-sm-6 col-md-7">
<h1><strong>{{ speaker.name }}</strong></h1>
<p class="lead">{{ speaker.biography_html | safe }}</p>
<a style="margin-top: 20px;" href="{{ speaker_website }}" class="btn">Speaker home page</a>
</div>
</div>
</div>
</section>

{% for talk in talks %}
<section class="inline-video">
<div class="container">
<div class="row">
<div class="col-sm-12">
<h2><strong>{{ talk.title }}</strong></h2>
{{ talk.category | capfirst }}, {{ talk.get_audience_level_display | capfirst }}
</div>
</div>

<div class="row">
<div class="col-md-11">
<p class="lead"></p>
<p class="lead">
<h3>Description</h3>
{{ talk.description }}
</p>
<p class="lead">
<h3>Abstract</h3>
{{ talk.abstract }}
</p>
<a href="#" class="btn">Conference Schedule</a>
</div>
</div>
</div>
</section>
{% endfor %}

{% endblock content %}
2 changes: 1 addition & 1 deletion pybay/templates/frontend/speakers_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ <h1>All Speakers</h1>
{% for speaker in speakers %}
<div class="col-md-6">
<img src="{% thumbnail speaker.photo '300x300' %}" alt="{{ speaker.name }}">
<h2>{{ speaker.name }}</h2>
<h2><a href="{% url 'pybay_speakers_detail' speaker.name_slug %}">{{ speaker.name }}</a></h2>
<span>{{ speaker.biography|truncatechars:"300" }}</span>
</div>
{% endfor %}
Expand Down
42 changes: 39 additions & 3 deletions pybay/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,56 @@
from django.test import TestCase
from django.core.urlresolvers import reverse
from pybay.proposals.models import Proposal
from pybay.proposals.models import TalkProposal
from pybay.utils import get_accepted_speaker_by_slug
from symposion.proposals.models import ProposalKind
from symposion.speakers.models import Speaker
from symposion.proposals.models import AdditionalSpeaker
from model_mommy import mommy
from model_mommy.random_gen import gen_image_field
from symposion.reviews.models import ProposalResult


class SpeakersModelTest(TestCase):

def test_get_slug(self):
self.speaker = mommy.make(Speaker, name="Lorem Ipsum",
photo=gen_image_field())
self.assertEquals(self.speaker.name_slug,
"lorem-ipsum")

def test_get_active_speaker_by_slug(self):
s1 = mommy.make(Speaker, name="Lorem Ipsum 1",
photo=gen_image_field())
s2 = mommy.make(Speaker, name="Lorem Ipsum 2",
photo=gen_image_field())
s3 = mommy.make(Speaker, name="Lorem Ipsum 3",
photo=gen_image_field())

kind = mommy.make(ProposalKind)
p2 = TalkProposal.objects.create(
title='test this title', kind=kind,
speaker=s2, audience_level=1,
)
mommy.make(ProposalResult, proposal=p2, status='accepted')
self.assertEquals(
get_accepted_speaker_by_slug(s2.name_slug),
s2,
)
with self.assertRaises(Speaker.DoesNotExist):
get_accepted_speaker_by_slug(s1.name_slug)



class SpeakersViewTest(TestCase):

def setUp(self):
kind = mommy.make(ProposalKind)
self.speaker = mommy.make(Speaker, photo=gen_image_field())
self.proposal = Proposal.objects.create(
title='test this title', kind=kind, speaker=self.speaker)
self.proposal = TalkProposal.objects.create(
title='test this title', kind=kind,
speaker=self.speaker,
audience_level=1,
)
proposal_result = mommy.make(ProposalResult,
proposal=self.proposal,
status='accepted')
Expand Down
8 changes: 5 additions & 3 deletions pybay/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
from pybay.views import (
pybay_cfp_create,
pybay_sponsors_list, pybay_speakers_list,
pybay_faq_index, FaqTemplateView,
undecided_proposals,
proposal_detail,
pybay_faq_index, FaqTemplateView,
undecided_proposals,
proposal_detail,
pybay_speakers_detail,
)


Expand Down Expand Up @@ -56,6 +57,7 @@
# url(r"^markitup/", include("markitup.urls")),
url(r"^our-sponsors/$", pybay_sponsors_list, name="pybay_sponsors_list"),
url(r"^our-speakers/$", pybay_speakers_list, name="pybay_speakers_list"),
url(r"^speaker/(?P<speaker_slug>[-\w]+)/$", pybay_speakers_detail, name="pybay_speakers_detail"),
url(r"^api/undecided_proposals$", undecided_proposals, name="pybay_undecided_proposals"),
url(r"^api/proposals/(?P<proposal_id>\d+)/$", proposal_detail, name="pybay_detail_proposal"),
url(r"^404$", TemplateView.as_view(template_name="404.html")), # Adding explicitly for template dev purposes
Expand Down
21 changes: 21 additions & 0 deletions pybay/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from django.template.defaultfilters import slugify

from pybay.proposals.models import TalkProposal
from symposion.speakers.models import Speaker


def get_accepted_speaker_by_slug(speaker_slug):
"""
This function is purposely done do avoid touching Symposion
source code. Given the amount of approved speakers is not
substantial, it's better to iterate over speakers, slugify name,
and check equality, than create a new field in Symposion.
"""
approved_talks = TalkProposal.objects.filter(
result__status='accepted'
).prefetch_related('speaker')
for approved_talk in approved_talks:
if approved_talk.speaker.name_slug == speaker_slug:
return approved_talk.speaker

raise Speaker.DoesNotExist()
35 changes: 30 additions & 5 deletions pybay/views.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import json

from django.shortcuts import render
from django.http import HttpResponse, HttpResponseForbidden
from django.http import (HttpResponse, HttpResponseForbidden,
HttpResponseNotFound)
from django.views.generic import TemplateView

from .forms import CallForProposalForm
from pybay.faqs.models import Faq, Category
from symposion.sponsorship.models import Sponsor
from pybay.proposals.models import Proposal, TalkProposal, TutorialProposal
from pybay.proposals.models import TalkProposal
from pybay.utils import get_accepted_speaker_by_slug
from symposion.speakers.models import Speaker

from collections import defaultdict
from django.conf import settings

from logging import getLogger

log = getLogger(__file__)

cfp_close_date = settings.PROJECT_DATA['cfp_close_date']


Expand Down Expand Up @@ -71,9 +78,27 @@ def pybay_cfp_create(request):
{'form': form, 'cfp_close_date': cfp_close_date})


def pybay_speakers_detail(request, speaker_slug):

# Fetch speaker
try:
speaker = get_accepted_speaker_by_slug(speaker_slug)
except Speaker.DoesNotExist:
log.error("Speaker %s does not have any approved talks or does not exist", speaker_slug)
return HttpResponseNotFound()

# NOTE: Cannot perform reverse lookup (speaker.talk_proposals) for some reason.
speaker_approved_talks = TalkProposal.objects.filter(
speaker=speaker
).filter(result__status='accepted')

return render(request, 'frontend/speakers_detail.html',
{'speaker': speaker, 'talks': speaker_approved_talks,
'speaker_website': speaker_approved_talks[0].speaker_website})


def pybay_speakers_list(request):
accepted_proposals = Proposal.objects.filter(
result__status='accepted')
accepted_proposals = TalkProposal.objects.filter(result__status='accepted')
speakers = []
for proposal in accepted_proposals:
speakers += list(proposal.speakers())
Expand All @@ -86,8 +111,8 @@ def pybay_speakers_list(request):
'speakers': speakers
})

def undecided_proposals(request):

def undecided_proposals(request):
api_token = request.GET.get('token')
if api_token != settings.PYBAY_API_TOKEN:
return HttpResponseForbidden()
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ django-user-accounts==2.0
Django==1.9.2
easy-thumbnails==2.3
eventlog==0.8.0
git+https://github.com/pybay/symposion.git#egg=symposion-1.0b2.dev3
git+https://github.com/pybay/symposion.git#egg=symposion
html5lib==0.9999999
Markdown==2.6.5
metron==1.3.5
Expand Down