aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accounts/views.py5
-rw-r--r--codemash/settings.py1
-rw-r--r--codemash/urls.py1
-rw-r--r--proposals/__init__.py0
-rw-r--r--proposals/admin.py12
-rw-r--r--proposals/forms.py10
-rw-r--r--proposals/models.py75
-rw-r--r--proposals/templatetags/icons.py14
-rw-r--r--proposals/tests.py16
-rw-r--r--proposals/urls.py9
-rw-r--r--proposals/views.py30
-rw-r--r--templates/accounts/profile.html26
-rw-r--r--templates/proposals/proposal_form.html31
13 files changed, 226 insertions, 4 deletions
diff --git a/accounts/views.py b/accounts/views.py
index aafcfb6..c869085 100644
--- a/accounts/views.py
+++ b/accounts/views.py
@@ -2,12 +2,15 @@ from django.shortcuts import render, redirect
2from django.contrib.auth import authenticate, login 2from django.contrib.auth import authenticate, login
3from django.contrib.auth.decorators import login_required 3from django.contrib.auth.decorators import login_required
4 4
5from proposals.models import Proposal
5from accounts.forms import UserCreationForm 6from accounts.forms import UserCreationForm
6 7
7 8
8@login_required 9@login_required
9def profile(request): 10def profile(request):
10 return render(request, "accounts/profile.html") 11 return render(request, "accounts/profile.html", {
12 'proposals': Proposal.objects.for_user(request.user),
13 })
11 14
12 15
13def create_account(request): 16def create_account(request):
diff --git a/codemash/settings.py b/codemash/settings.py
index fbd61f8..efdfb99 100644
--- a/codemash/settings.py
+++ b/codemash/settings.py
@@ -129,6 +129,7 @@ INSTALLED_APPS = (
129 129
130 'contact', 130 'contact',
131 'accounts', 131 'accounts',
132 'proposals',
132) 133)
133 134
134# A sample logging configuration. The only tangible logging 135# A sample logging configuration. The only tangible logging
diff --git a/codemash/urls.py b/codemash/urls.py
index 762679a..da6f216 100644
--- a/codemash/urls.py
+++ b/codemash/urls.py
@@ -9,6 +9,7 @@ urlpatterns = patterns('',
9 (r'^contact/', include('contact.urls', namespace='contact')), 9 (r'^contact/', include('contact.urls', namespace='contact')),
10 (r'^accounts/', include('django.contrib.auth.urls', namespace='auth')), 10 (r'^accounts/', include('django.contrib.auth.urls', namespace='auth')),
11 (r'^accounts/', include('accounts.urls', namespace='account')), 11 (r'^accounts/', include('accounts.urls', namespace='account')),
12 (r'^proposals/', include('proposals.urls', namespace='proposals')),
12 13
13 url(r'^admin/doc/', include('django.contrib.admindocs.urls')), 14 url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
14 url(r'^admin/', include(admin.site.urls)), 15 url(r'^admin/', include(admin.site.urls)),
diff --git a/proposals/__init__.py b/proposals/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/proposals/__init__.py
diff --git a/proposals/admin.py b/proposals/admin.py
new file mode 100644
index 0000000..5b10ec3
--- /dev/null
+++ b/proposals/admin.py
@@ -0,0 +1,12 @@
1from django.contrib import admin
2
3from proposals.models import TimeSlot, Location, TalkType
4from proposals.models import AudienceSkillLevel, Category, Proposal
5
6
7admin.site.register(Category)
8admin.site.register(TimeSlot)
9admin.site.register(Location)
10admin.site.register(Proposal)
11admin.site.register(TalkType)
12admin.site.register(AudienceSkillLevel)
diff --git a/proposals/forms.py b/proposals/forms.py
new file mode 100644
index 0000000..7a32dec
--- /dev/null
+++ b/proposals/forms.py
@@ -0,0 +1,10 @@
1from django import forms
2
3from proposals.models import Proposal
4
5
6class UserProposalForm(forms.ModelForm):
7
8 class Meta:
9 model = Proposal
10 exclude = ("approved", "location", "time_slot")
diff --git a/proposals/models.py b/proposals/models.py
new file mode 100644
index 0000000..8551659
--- /dev/null
+++ b/proposals/models.py
@@ -0,0 +1,75 @@
1from django.db import models
2from django.contrib.auth.models import User
3
4
5class TimeSlot(models.Model):
6
7 slot = models.DateTimeField()
8
9 def __str__(self):
10 return self.slot.strftime("%A, %B %d, %Y @ %I:%M %p")
11
12
13class Location(models.Model):
14
15 name = models.CharField(max_length=255)
16
17 def __str__(self):
18 return self.name
19
20
21class TalkType(models.Model):
22
23 name = models.CharField(max_length=255)
24
25 def __str__(self):
26 return self.name
27
28
29class AudienceSkillLevel(models.Model):
30
31 name = models.CharField(max_length=255)
32
33 def __str__(self):
34 return self.name
35
36
37class Category(models.Model):
38
39 name = models.CharField(max_length=255)
40
41 def __str__(self):
42 return self.name
43
44 class Meta:
45 verbose_name_plural = "Categories"
46
47
48class ProposalManager(models.Manager):
49
50 def for_user(self, user):
51 return self.get_query_set().filter(proposers=user)
52
53
54class Proposal(models.Model):
55
56 objects = ProposalManager()
57
58 title = models.CharField(max_length=255)
59
60 type = models.ForeignKey(TalkType)
61 category = models.ForeignKey(Category)
62 audience_skill_level = models.ForeignKey(AudienceSkillLevel)
63 location = models.ForeignKey(Location, blank=True, null=True)
64 time_slot = models.ForeignKey(TimeSlot, blank=True, null=True)
65 proposers = models.ManyToManyField(User)
66
67 approved = models.BooleanField(default=False)
68 recording_release = models.BooleanField(default=False)
69
70 outline = models.TextField(blank=True)
71 abstract = models.TextField(blank=True)
72 notes = models.TextField(blank=True)
73
74 def __str__(self):
75 return self.title
diff --git a/proposals/templatetags/icons.py b/proposals/templatetags/icons.py
new file mode 100644
index 0000000..551ad49
--- /dev/null
+++ b/proposals/templatetags/icons.py
@@ -0,0 +1,14 @@
1from django import template
2from django.utils.html import format_html
3from django.contrib.admin.templatetags.admin_static import static
4
5
6register = template.Library()
7
8
9@register.filter
10def boolean_icon(value):
11 icon_url = static('admin/img/icon-%s.gif' %
12 {True: 'yes', False: 'no', None: 'unknown'}[value])
13 alt_text = {True: 'yes', False: 'no', None: 'pending' }[value]
14 return format_html('<img src="{0}" alt="{1}" />', icon_url, alt_text)
diff --git a/proposals/tests.py b/proposals/tests.py
new file mode 100644
index 0000000..501deb7
--- /dev/null
+++ b/proposals/tests.py
@@ -0,0 +1,16 @@
1"""
2This file demonstrates writing tests using the unittest module. These will pass
3when you run "manage.py test".
4
5Replace this with more appropriate tests for your application.
6"""
7
8from django.test import TestCase
9
10
11class SimpleTest(TestCase):
12 def test_basic_addition(self):
13 """
14 Tests that 1 + 1 always equals 2.
15 """
16 self.assertEqual(1 + 1, 2)
diff --git a/proposals/urls.py b/proposals/urls.py
new file mode 100644
index 0000000..5a33b6f
--- /dev/null
+++ b/proposals/urls.py
@@ -0,0 +1,9 @@
1from django.conf.urls import patterns, include, url
2
3from proposals.views import ProposalUpdateView, ProposalCreationForm
4
5
6urlpatterns = patterns('proposals.views',
7 url(r'(?P<pk>[0-9]+)$', ProposalUpdateView.as_view(), name='update'),
8 url(r'create/$', ProposalCreationForm.as_view(), name='create'),
9)
diff --git a/proposals/views.py b/proposals/views.py
new file mode 100644
index 0000000..aacba55
--- /dev/null
+++ b/proposals/views.py
@@ -0,0 +1,30 @@
1from django.shortcuts import resolve_url
2from django.views.generic.edit import CreateView, UpdateView
3
4from proposals.models import Proposal
5from proposals.forms import UserProposalForm
6
7
8class ProposalCreationForm(CreateView):
9
10 model = Proposal
11 form_class = UserProposalForm
12
13 def get_success_url(self):
14 return resolve_url("account:profile")
15
16
17class ProposalUpdateView(UpdateView):
18
19 form_class = UserProposalForm
20
21 def get_success_url(self):
22 return resolve_url("account:profile")
23
24 def get_queryset(self):
25 return Proposal.objects.for_user(self.request.user)
26
27 def get_context_data(self, **kwargs):
28 context = super(ProposalUpdateView, self).get_context_data(**kwargs)
29 context["edit_view"] = True
30 return context
diff --git a/templates/accounts/profile.html b/templates/accounts/profile.html
index aa6f3ad..fb9e8b1 100644
--- a/templates/accounts/profile.html
+++ b/templates/accounts/profile.html
@@ -1,9 +1,29 @@
1{% extends "base.html" %} 1{% extends "base.html" %}
2{% load icons %}
2 3
3{% block content %} 4{% block content %}
4<h1>Your Account</h1> 5<h1>Your Account</h1>
5<p>Hello <b>{{ user.email }}</b></p> 6<p>Hello <b>{{ user.email }}</b></p>
6<ul> 7
7 <li><a href="{% url 'auth:logout' %}">Logout</a></li> 8<h1>Your Talk Proposals</h1>
8</ul> 9<p><a href="{% url 'proposals:create' %}">Submit a Proposal</a></p>
10
11{% if proposals %}
12<table>
13 <tr>
14 <th>Title</th>
15 <th>Type</th>
16 <th>Category</th>
17 <th>Approved</th>
18 </tr>
19 {% for proposal in proposals %}
20 <tr>
21 <td><a href="{% url 'proposals:update' proposal.id %}">{{ proposal.title }}</a></td>
22 <td>{{ proposal.type }}</td>
23 <td>{{ proposal.category }}</td>
24 <td>{{ proposal.approved|boolean_icon }}</td>
25 </tr>
26 {% endfor %}
27</table>
28{% endif %}
9{% endblock %} 29{% endblock %}
diff --git a/templates/proposals/proposal_form.html b/templates/proposals/proposal_form.html
new file mode 100644
index 0000000..79f33bf
--- /dev/null
+++ b/templates/proposals/proposal_form.html
@@ -0,0 +1,31 @@
1{% extends "base.html" %}
2
3{% block title %}CodeMash Sponsors{% endblock %}
4
5{% block content %}
6<h1>{% if edit_view %}Edit{% else %}Submit{% endif %} Proposal</h1>
7{% if object.approved %}
8<p>Congratulations, your talk has been approved!</p>
9
10<fieldset>
11 <legend>Scheduling Details</legend>
12 <p>
13 <label for="id_time_slot">Time Slot:</label>
14 <input type="text" id="id_time_slot" value="{{ object.time_slot }}" disabled />
15 </p>
16 <p>
17 <label for="id_location">Location:</label>
18 <input type="text" id="id_location" value="{{ object.location }}" disabled />
19 </p>
20</fieldset>
21{% endif %}
22
23<form action="" method="post">
24 {% csrf_token %}
25 <fieldset>
26 <legend>Talk Details</legend>
27 {{ form.as_p }}
28 <input type="submit" value="Save Changes" />
29 </fieldset>
30</form>
31{% endblock %}