Skip to content

Commit 4e80c6d

Browse files
committed
reated a couple of apps to clean up the view code better
* Added settings for who contact form emails go to/from * Created an app for the code specific to retrieving meetups * Created an app for the code to process contact form submissions and emails * Commented out admin/admindoc apps for now
1 parent e2d3dd5 commit 4e80c6d

File tree

9 files changed

+146
-53
lines changed

9 files changed

+146
-53
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
=====================================
2+
Contact App for the PythonKC.com Site
3+
=====================================
4+
5+
Contact Form
6+
------------
7+
``pythonkc_site.contact.forms`` provides the contact form class.
8+
9+
Sending Contact Email
10+
---------------------
11+
The ``pythonkc_site.contact.email`` module provides a function to send an email
12+
based on the data from a submitted contact form.
13+
14+
This app also provides templates that used to compose the email, so these can
15+
be used to customize the email that is sent on contact form submission.
16+
17+
Settings
18+
--------
19+
The following settings are expected to be provided by the Django site for the
20+
contact functionality to work.
21+
22+
``CONTACT_EMAIL_FROM``
23+
The email address to send contact form emails from.
24+
``CONTACT_EMAIL_TO``
25+
The email addresses to send contact form email to.

pythonkc_site/contact/email.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Provides a function for sending the email when the site's contact form is
4+
submitted by a visitor.
5+
6+
"""
7+
8+
9+
from django.conf import settings
10+
from django.core.mail import BadHeaderError
11+
from django.core.mail import EmailMultiAlternatives
12+
from django.template.loader import render_to_string
13+
import logging
14+
15+
16+
logger = logging.getLogger(__name__)
17+
_SUBJECT_TEMPLATE = 'pythonkc_site/contact/email_subject.txt'
18+
_TEXT_TEMPLATE = 'pythonkc_site/contact/email_contents.txt'
19+
_HTML_TEMPLATE = 'pythonkc_site/contact/email_contents.html'
20+
21+
22+
def send_contact_form_email(first_name, last_name, email, message):
23+
"""
24+
Send an email based on the submission of the site's contact form.
25+
26+
"""
27+
context = {
28+
'first_name': first_name,
29+
'last_name': last_name,
30+
'email': email,
31+
'message': message
32+
}
33+
34+
subject = render_to_string(_SUBJECT_TEMPLATE, context)
35+
text_content = render_to_string(_TEXT_TEMPLATE, context)
36+
html_content = render_to_string(_HTML_TEMPLATE, context)
37+
from_email = settings.CONTACT_EMAIL_FROM
38+
to_emails = settings.CONTACT_EMAIL_TO
39+
40+
message = EmailMultiAlternatives(subject, text_content, from_email,
41+
to_emails)
42+
message.attach_alternative(html_content, "text/html")
43+
44+
try:
45+
message.send()
46+
except BadHeaderError:
47+
logger.exception('Exception occurred while sending contact form email')
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<h1>From {{ first }} {{ last }} &lt;{{ email }}&gt;</h1>
2+
<p>{{ message }}</p>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
From {{ first }} {{ last }} <{{ email }}>
2+
3+
{{ message }}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
New message from a PythonKC.com visitor

pythonkc_site/meetups/__init__.py

Whitespace-only changes.

pythonkc_site/meetups/events.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Provides the Meetup.com events that will be used to populate the site homepage.
4+
5+
"""
6+
7+
8+
from django.conf import settings
9+
from django.core.cache import cache
10+
from django.core.exceptions import ImproperlyConfigured
11+
from functools import wraps
12+
from pythonkc_meetups import PythonKCMeetups
13+
import logging
14+
15+
16+
logger = logging.getLogger(__name__)
17+
18+
19+
try:
20+
api_key = settings.MEETUP_API_KEY
21+
except AttributeError:
22+
raise ImproperlyConfigured('MEETUP_API_KEY is required in settings')
23+
24+
25+
meetups = PythonKCMeetups(api_key, http_timeout=6)
26+
num_past_events = getattr(settings, 'MEETUP_SHOW_PAST_EVENTS', 3)
27+
28+
29+
def memoize_in_cache(cache_key, cache_timeout_seconds=None):
30+
"""Cache the result of a no-args function."""
31+
def decorator(func):
32+
@wraps(func)
33+
def decorated():
34+
value = cache.get(cache_key)
35+
if not value:
36+
value = func()
37+
cache.set(cache_key, value, cache_timeout_seconds)
38+
return value
39+
return decorated
40+
return decorator
41+
42+
43+
@memoize_in_cache('next_event', 60 * 5)
44+
def get_next_event():
45+
logging.info('Retrieving next event from Meetup.com')
46+
upcoming_events = meetups.get_upcoming_events()
47+
return upcoming_events[0] if upcoming_events else None
48+
49+
50+
@memoize_in_cache('past_events', 60 * 60)
51+
def get_past_events():
52+
logging.info('Retrieving past events from Meetup.com')
53+
return meetups.get_past_events()[:num_past_events]

pythonkc_site/settings.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,11 @@
114114
'django.contrib.messages',
115115
'django.contrib.staticfiles',
116116
# Uncomment the next line to enable the admin:
117-
'django.contrib.admin',
117+
#'django.contrib.admin',
118118
# Uncomment the next line to enable admin documentation:
119-
'django.contrib.admindocs',
119+
#'django.contrib.admindocs',
120120
'south',
121+
'pythonkc_site.contact',
121122
)
122123

123124
# A sample logging configuration. The only tangible logging
@@ -144,6 +145,11 @@
144145
}
145146

146147

148+
CONTACT_EMAIL_FROM = 'noreply@pythonkc.com'
149+
# The following should become pythonkc@gmail.com, and eventually
150+
# contact@pythonkc.com
151+
CONTACT_EMAIL_TO = ['estebistec@gmail.com']
152+
147153
try:
148154
from local_settings import *
149155
except ImportError:

pythonkc_site/views.py

Lines changed: 7 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,32 @@
11
# -*- coding: utf-8 -*-
22

33

4-
from django.conf import settings
5-
from django.core.cache import cache
6-
from django.core.exceptions import ImproperlyConfigured
74
from django.core.urlresolvers import reverse
85
from django.views.generic import FormView
96
from django.views.generic.base import TemplateView
10-
from functools import wraps
11-
from pythonkc_meetups import PythonKCMeetups
12-
from pythonkc_site.forms import ContactForm
13-
import logging
14-
15-
16-
logger = logging.getLogger(__name__)
17-
18-
19-
try:
20-
api_key = settings.MEETUP_API_KEY
21-
except AttributeError:
22-
raise ImproperlyConfigured('MEETUP_API_KEY is required in settings')
23-
24-
25-
meetups = PythonKCMeetups(api_key, http_timeout=6)
26-
num_past_events = getattr(settings, 'MEETUP_SHOW_PAST_EVENTS', 3)
7+
from pythonkc_site.contact.email import send_contact_form_email
8+
from pythonkc_site.contact.forms import ContactForm
9+
from pythonkc_site.meetups import events
2710

2811

2912
class PythonKCHome(FormView):
3013
template_name = 'index.html'
3114
form_class = ContactForm
3215

3316
def get_success_url(self):
34-
return reverse('home')
17+
return '{0}?contact_sent=yes'.format(reverse('home'))
3518

3619
def form_valid(self, form):
37-
# TODO send email
38-
# TODO create success msg with msg framework
20+
send_contact_form_email(**form.cleaned_data)
3921
return super(PythonKCHome, self).form_valid(form)
4022

4123
def get_context_data(self, **kwargs):
42-
43-
@memoize_in_cache('next_event', 60 * 5)
44-
def get_next_event():
45-
logging.info('Retrieving next event from Meetup.com')
46-
upcoming_events = meetups.get_upcoming_events()
47-
return upcoming_events[0] if upcoming_events else None
48-
49-
@memoize_in_cache('past_events', 60 * 60)
50-
def get_past_events():
51-
logging.info('Retrieving past events from Meetup.com')
52-
return meetups.get_past_events()[:num_past_events]
53-
5424
return {
55-
'next_event': get_next_event(),
56-
'past_events': get_past_events(),
25+
'next_event': events.get_next_event(),
26+
'past_events': events.get_past_events(),
5727
'form': kwargs.get('form', None) or ContactForm()
5828
}
5929

6030

61-
def memoize_in_cache(cache_key, cache_timeout_seconds=None):
62-
"""Cache the result of a no-args function."""
63-
def decorator(func):
64-
@wraps(func)
65-
def decorated():
66-
value = cache.get(cache_key)
67-
if not value:
68-
value = func()
69-
cache.set(cache_key, value, cache_timeout_seconds)
70-
return value
71-
return decorated
72-
return decorator
73-
74-
7531
class PythonKCComingSoon(TemplateView):
7632
template_name = 'coming_soon.html'

0 commit comments

Comments
 (0)