From dea70a8855cebe6d35eb8508ee150a79e87b8f45 Mon Sep 17 00:00:00 2001 From: Mike Crute Date: Fri, 28 Dec 2012 15:43:50 -0500 Subject: Users can submit talk proposals --- accounts/views.py | 5 ++- codemash/settings.py | 1 + codemash/urls.py | 1 + proposals/__init__.py | 0 proposals/admin.py | 12 ++++++ proposals/forms.py | 10 +++++ proposals/models.py | 75 ++++++++++++++++++++++++++++++++++ proposals/templatetags/icons.py | 14 +++++++ proposals/tests.py | 16 ++++++++ proposals/urls.py | 9 ++++ proposals/views.py | 30 ++++++++++++++ templates/accounts/profile.html | 26 ++++++++++-- templates/proposals/proposal_form.html | 31 ++++++++++++++ 13 files changed, 226 insertions(+), 4 deletions(-) create mode 100644 proposals/__init__.py create mode 100644 proposals/admin.py create mode 100644 proposals/forms.py create mode 100644 proposals/models.py create mode 100644 proposals/templatetags/icons.py create mode 100644 proposals/tests.py create mode 100644 proposals/urls.py create mode 100644 proposals/views.py create mode 100644 templates/proposals/proposal_form.html 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 from django.contrib.auth import authenticate, login from django.contrib.auth.decorators import login_required +from proposals.models import Proposal from accounts.forms import UserCreationForm @login_required def profile(request): - return render(request, "accounts/profile.html") + return render(request, "accounts/profile.html", { + 'proposals': Proposal.objects.for_user(request.user), + }) def 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 = ( 'contact', 'accounts', + 'proposals', ) # 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('', (r'^contact/', include('contact.urls', namespace='contact')), (r'^accounts/', include('django.contrib.auth.urls', namespace='auth')), (r'^accounts/', include('accounts.urls', namespace='account')), + (r'^proposals/', include('proposals.urls', namespace='proposals')), url(r'^admin/doc/', include('django.contrib.admindocs.urls')), url(r'^admin/', include(admin.site.urls)), diff --git a/proposals/__init__.py b/proposals/__init__.py new file mode 100644 index 0000000..e69de29 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 @@ +from django.contrib import admin + +from proposals.models import TimeSlot, Location, TalkType +from proposals.models import AudienceSkillLevel, Category, Proposal + + +admin.site.register(Category) +admin.site.register(TimeSlot) +admin.site.register(Location) +admin.site.register(Proposal) +admin.site.register(TalkType) +admin.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 @@ +from django import forms + +from proposals.models import Proposal + + +class UserProposalForm(forms.ModelForm): + + class Meta: + model = Proposal + 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 @@ +from django.db import models +from django.contrib.auth.models import User + + +class TimeSlot(models.Model): + + slot = models.DateTimeField() + + def __str__(self): + return self.slot.strftime("%A, %B %d, %Y @ %I:%M %p") + + +class Location(models.Model): + + name = models.CharField(max_length=255) + + def __str__(self): + return self.name + + +class TalkType(models.Model): + + name = models.CharField(max_length=255) + + def __str__(self): + return self.name + + +class AudienceSkillLevel(models.Model): + + name = models.CharField(max_length=255) + + def __str__(self): + return self.name + + +class Category(models.Model): + + name = models.CharField(max_length=255) + + def __str__(self): + return self.name + + class Meta: + verbose_name_plural = "Categories" + + +class ProposalManager(models.Manager): + + def for_user(self, user): + return self.get_query_set().filter(proposers=user) + + +class Proposal(models.Model): + + objects = ProposalManager() + + title = models.CharField(max_length=255) + + type = models.ForeignKey(TalkType) + category = models.ForeignKey(Category) + audience_skill_level = models.ForeignKey(AudienceSkillLevel) + location = models.ForeignKey(Location, blank=True, null=True) + time_slot = models.ForeignKey(TimeSlot, blank=True, null=True) + proposers = models.ManyToManyField(User) + + approved = models.BooleanField(default=False) + recording_release = models.BooleanField(default=False) + + outline = models.TextField(blank=True) + abstract = models.TextField(blank=True) + notes = models.TextField(blank=True) + + def __str__(self): + 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 @@ +from django import template +from django.utils.html import format_html +from django.contrib.admin.templatetags.admin_static import static + + +register = template.Library() + + +@register.filter +def boolean_icon(value): + icon_url = static('admin/img/icon-%s.gif' % + {True: 'yes', False: 'no', None: 'unknown'}[value]) + alt_text = {True: 'yes', False: 'no', None: 'pending' }[value] + return format_html('{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 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" + +from django.test import TestCase + + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + 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 @@ +from django.conf.urls import patterns, include, url + +from proposals.views import ProposalUpdateView, ProposalCreationForm + + +urlpatterns = patterns('proposals.views', + url(r'(?P[0-9]+)$', ProposalUpdateView.as_view(), name='update'), + url(r'create/$', ProposalCreationForm.as_view(), name='create'), +) 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 @@ +from django.shortcuts import resolve_url +from django.views.generic.edit import CreateView, UpdateView + +from proposals.models import Proposal +from proposals.forms import UserProposalForm + + +class ProposalCreationForm(CreateView): + + model = Proposal + form_class = UserProposalForm + + def get_success_url(self): + return resolve_url("account:profile") + + +class ProposalUpdateView(UpdateView): + + form_class = UserProposalForm + + def get_success_url(self): + return resolve_url("account:profile") + + def get_queryset(self): + return Proposal.objects.for_user(self.request.user) + + def get_context_data(self, **kwargs): + context = super(ProposalUpdateView, self).get_context_data(**kwargs) + context["edit_view"] = True + 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 @@ {% extends "base.html" %} +{% load icons %} {% block content %}

Your Account

Hello {{ user.email }}

- + +

Your Talk Proposals

+

Submit a Proposal

+ +{% if proposals %} + + + + + + + + {% for proposal in proposals %} + + + + + + + {% endfor %} +
TitleTypeCategoryApproved
{{ proposal.title }}{{ proposal.type }}{{ proposal.category }}{{ proposal.approved|boolean_icon }}
+{% endif %} {% 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 @@ +{% extends "base.html" %} + +{% block title %}CodeMash Sponsors{% endblock %} + +{% block content %} +

{% if edit_view %}Edit{% else %}Submit{% endif %} Proposal

+{% if object.approved %} +

Congratulations, your talk has been approved!

+ +
+ Scheduling Details +

+ + +

+

+ + +

+
+{% endif %} + +
+ {% csrf_token %} +
+ Talk Details + {{ form.as_p }} + +
+
+{% endblock %} -- cgit v1.2.3