From 5e5de6c6ea66ba4666e01a732776d4a7f563647b Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Mon, 13 Jan 2014 16:49:40 -0500 Subject: [PATCH 01/46] Pyflakes clean across the entire project --- symposion/boxes/models.py | 11 +- symposion/boxes/templatetags/boxes_tags.py | 13 +- symposion/conf.py | 4 +- symposion/conference/urls.py | 2 +- symposion/markdown_parser.py | 5 +- symposion/proposals/urls.py | 4 +- symposion/reviews/context_processors.py | 2 - .../management/commands/assign_reviewers.py | 5 - .../management/commands/calculate_results.py | 4 +- symposion/reviews/templatetags/review_tags.py | 2 +- symposion/reviews/views.py | 142 +++++++++--------- symposion/schedule/models.py | 53 ++++--- symposion/schedule/timetable.py | 11 +- symposion/schedule/views.py | 45 +++--- .../commands/export_speaker_data.py | 6 +- symposion/speakers/urls.py | 2 +- .../commands/reset_sponsor_benefits.py | 16 +- symposion/teams/urls.py | 4 +- 18 files changed, 152 insertions(+), 179 deletions(-) diff --git a/symposion/boxes/models.py b/symposion/boxes/models.py index c83cadcb..4eb2a019 100644 --- a/symposion/boxes/models.py +++ b/symposion/boxes/models.py @@ -1,7 +1,4 @@ -import datetime - from django.db import models - from django.contrib.auth.models import User import reversion @@ -10,16 +7,16 @@ from markitup.fields import MarkupField class Box(models.Model): - + label = models.CharField(max_length=100, db_index=True) content = MarkupField(blank=True) - + created_by = models.ForeignKey(User, related_name="boxes") last_updated_by = models.ForeignKey(User, related_name="updated_boxes") - + def __unicode__(self): return self.label - + class Meta: verbose_name_plural = "boxes" diff --git a/symposion/boxes/templatetags/boxes_tags.py b/symposion/boxes/templatetags/boxes_tags.py index e300fd3b..53765e56 100644 --- a/symposion/boxes/templatetags/boxes_tags.py +++ b/symposion/boxes/templatetags/boxes_tags.py @@ -1,10 +1,5 @@ from django import template -from django.core.exceptions import ImproperlyConfigured from django.core.urlresolvers import reverse -from django.utils.safestring import mark_safe -from django.utils.encoding import smart_str -from django.utils.translation import ugettext_lazy as _ -from django.template.defaulttags import kwarg_re from symposion.boxes.models import Box from symposion.boxes.forms import BoxForm @@ -16,22 +11,22 @@ register = template.Library() @register.inclusion_tag("boxes/box.html", takes_context=True) def box(context, label, show_edit=True, *args, **kwargs): - + request = context["request"] can_edit = load_can_edit()(request, *args, **kwargs) - + try: box = Box.objects.get(label=label) except Box.DoesNotExist: box = None - + if can_edit and show_edit: form = BoxForm(instance=box, prefix=label) form_action = reverse("box_edit", args=[label]) else: form = None form_action = None - + return { "request": request, "label": label, diff --git a/symposion/conf.py b/symposion/conf.py index e2fb8072..dd2a6d50 100644 --- a/symposion/conf.py +++ b/symposion/conf.py @@ -1,8 +1,6 @@ -from django.conf import settings - from appconf import AppConf class SymposionAppConf(AppConf): - + VOTE_THRESHOLD = 3 diff --git a/symposion/conference/urls.py b/symposion/conference/urls.py index 6bd44c16..a25aa583 100644 --- a/symposion/conference/urls.py +++ b/symposion/conference/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import * +from django.conf.urls.defaults import patterns, url urlpatterns = patterns("symposion.conference.views", diff --git a/symposion/markdown_parser.py b/symposion/markdown_parser.py index 07216c2a..178708f6 100644 --- a/symposion/markdown_parser.py +++ b/symposion/markdown_parser.py @@ -1,14 +1,13 @@ -import html5lib from html5lib import html5parser, sanitizer import markdown def parse(text): - + # First run through the Markdown parser text = markdown.markdown(text, extensions=["extra"], safe_mode=False) - + # Sanitize using html5lib bits = [] parser = html5parser.HTMLParser(tokenizer=sanitizer.HTMLSanitizer) diff --git a/symposion/proposals/urls.py b/symposion/proposals/urls.py index 85e2bb1c..443540bb 100644 --- a/symposion/proposals/urls.py +++ b/symposion/proposals/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import * +from django.conf.urls.defaults import patterns, url urlpatterns = patterns("symposion.proposals.views", @@ -11,7 +11,7 @@ urlpatterns = patterns("symposion.proposals.views", url(r"^(\d+)/leave/$", "proposal_leave", name="proposal_leave"), url(r"^(\d+)/join/$", "proposal_pending_join", name="proposal_pending_join"), url(r"^(\d+)/decline/$", "proposal_pending_decline", name="proposal_pending_decline"), - + url(r"^(\d+)/document/create/$", "document_create", name="proposal_document_create"), url(r"^document/(\d+)/delete/$", "document_delete", name="proposal_document_delete"), url(r"^document/(\d+)/([^/]+)$", "document_download", name="proposal_document_download"), diff --git a/symposion/reviews/context_processors.py b/symposion/reviews/context_processors.py index 6e70715b..02850f15 100644 --- a/symposion/reviews/context_processors.py +++ b/symposion/reviews/context_processors.py @@ -1,5 +1,3 @@ -from django.contrib.contenttypes.models import ContentType - from symposion.proposals.models import ProposalSection diff --git a/symposion/reviews/management/commands/assign_reviewers.py b/symposion/reviews/management/commands/assign_reviewers.py index 334eab30..20594f4c 100644 --- a/symposion/reviews/management/commands/assign_reviewers.py +++ b/symposion/reviews/management/commands/assign_reviewers.py @@ -1,8 +1,3 @@ -import csv -import os -import random - -from django.contrib.auth import models from django.core.management.base import BaseCommand from symposion.reviews.models import ReviewAssignment diff --git a/symposion/reviews/management/commands/calculate_results.py b/symposion/reviews/management/commands/calculate_results.py index 45185a22..6a06ce8a 100644 --- a/symposion/reviews/management/commands/calculate_results.py +++ b/symposion/reviews/management/commands/calculate_results.py @@ -1,11 +1,9 @@ from django.core.management.base import BaseCommand -from django.contrib.auth.models import Group - from symposion.reviews.models import ProposalResult class Command(BaseCommand): - + def handle(self, *args, **options): ProposalResult.full_calculate() diff --git a/symposion/reviews/templatetags/review_tags.py b/symposion/reviews/templatetags/review_tags.py index cfb6437e..c646ca96 100644 --- a/symposion/reviews/templatetags/review_tags.py +++ b/symposion/reviews/templatetags/review_tags.py @@ -1,6 +1,6 @@ from django import template -from symposion.reviews.models import Review, ReviewAssignment +from symposion.reviews.models import ReviewAssignment register = template.Library() diff --git a/symposion/reviews/views.py b/symposion/reviews/views.py index 880e9e8b..8278778a 100644 --- a/symposion/reviews/views.py +++ b/symposion/reviews/views.py @@ -1,5 +1,3 @@ -import re - from django.core.mail import send_mass_mail from django.db.models import Q from django.http import HttpResponseBadRequest, HttpResponseNotAllowed @@ -27,18 +25,18 @@ def access_not_permitted(request): def proposals_generator(request, queryset, user_pk=None, check_speaker=True): - + for obj in queryset: # @@@ this sucks; we can do better if check_speaker: if request.user in [s.user for s in obj.speakers()]: continue - + try: obj.result except ProposalResult.DoesNotExist: ProposalResult.objects.get_or_create(proposal=obj) - + obj.comment_count = obj.result.comment_count obj.total_votes = obj.result.vote_count obj.plus_one = obj.result.plus_one @@ -46,19 +44,19 @@ def proposals_generator(request, queryset, user_pk=None, check_speaker=True): obj.minus_zero = obj.result.minus_zero obj.minus_one = obj.result.minus_one lookup_params = dict(proposal=obj) - + if user_pk: lookup_params["user__pk"] = user_pk else: lookup_params["user"] = request.user - + try: obj.user_vote = LatestVote.objects.get(**lookup_params).vote obj.user_vote_css = LatestVote.objects.get(**lookup_params).css_class() except LatestVote.DoesNotExist: obj.user_vote = None obj.user_vote_css = "no-vote" - + yield obj @@ -66,17 +64,17 @@ def proposals_generator(request, queryset, user_pk=None, check_speaker=True): # depending on the link user clicks in dashboard @login_required def review_section(request, section_slug, assigned=False, reviewed="all"): - + if not request.user.has_perm("reviews.can_review_%s" % section_slug): return access_not_permitted(request) - + section = get_object_or_404(ProposalSection, section__slug=section_slug) queryset = ProposalBase.objects.filter(kind__section=section) - + if assigned: assignments = ReviewAssignment.objects.filter(user=request.user).values_list("proposal__id") queryset = queryset.filter(id__in=assignments) - + # passing reviewed in from reviews.urls and out to review_list for # appropriate template header rendering if reviewed == "all": @@ -88,35 +86,35 @@ def review_section(request, section_slug, assigned=False, reviewed="all"): else: queryset = queryset.exclude(reviews__user=request.user).exclude(speaker=request.user) reviewed = "user_not_reviewed" - + proposals = proposals_generator(request, queryset) - + ctx = { "proposals": proposals, "section": section, "reviewed": reviewed, } - + return render(request, "reviews/review_list.html", ctx) @login_required def review_list(request, section_slug, user_pk): - + # if they're not a reviewer admin and they aren't the person whose # review list is being asked for, don't let them in if not request.user.has_perm("reviews.can_manage_%s" % section_slug): if not request.user.pk == user_pk: return access_not_permitted(request) - + queryset = ProposalBase.objects.select_related("speaker__user", "result") reviewed = LatestVote.objects.filter(user__pk=user_pk).values_list("proposal", flat=True) queryset = queryset.filter(pk__in=reviewed) proposals = queryset.order_by("submitted") - + admin = request.user.has_perm("reviews.can_manage_%s" % section_slug) - + proposals = proposals_generator(request, proposals, user_pk=user_pk, check_speaker=not admin) - + ctx = { "proposals": proposals, } @@ -125,20 +123,20 @@ def review_list(request, section_slug, user_pk): @login_required def review_admin(request, section_slug): - + if not request.user.has_perm("reviews.can_manage_%s" % section_slug): return access_not_permitted(request) - + def reviewers(): already_seen = set() - + for team in Team.objects.filter(permissions__codename="can_review_%s" % section_slug): for membership in team.memberships.filter(Q(state="member") | Q(state="manager")): user = membership.user if user.pk in already_seen: continue already_seen.add(user.pk) - + user.comment_count = Review.objects.filter(user=user).count() user.total_votes = LatestVote.objects.filter(user=user).count() user.plus_one = LatestVote.objects.filter( @@ -157,9 +155,9 @@ def review_admin(request, section_slug): user = user, vote = LatestVote.VOTES.MINUS_ONE ).count() - + yield user - + ctx = { "section_slug": section_slug, "reviewers": reviewers(), @@ -169,50 +167,50 @@ def review_admin(request, section_slug): @login_required def review_detail(request, pk): - + proposals = ProposalBase.objects.select_related("result").select_subclasses() proposal = get_object_or_404(proposals, pk=pk) - + if not request.user.has_perm("reviews.can_review_%s" % proposal.kind.section.slug): return access_not_permitted(request) - + speakers = [s.user for s in proposal.speakers()] - + if not request.user.is_superuser and request.user in speakers: return access_not_permitted(request) - + admin = request.user.is_staff - + try: latest_vote = LatestVote.objects.get(proposal=proposal, user=request.user) except LatestVote.DoesNotExist: latest_vote = None - + if request.method == "POST": if request.user in speakers: return access_not_permitted(request) - + if "vote_submit" in request.POST: review_form = ReviewForm(request.POST) if review_form.is_valid(): - + review = review_form.save(commit=False) review.user = request.user review.proposal = proposal review.save() - + return redirect(request.path) else: message_form = SpeakerCommentForm() elif "message_submit" in request.POST: message_form = SpeakerCommentForm(request.POST) if message_form.is_valid(): - + message = message_form.save(commit=False) message.user = request.user message.proposal = proposal message.save() - + for speaker in speakers: if speaker and speaker.email: ctx = { @@ -224,7 +222,7 @@ def review_detail(request, pk): [speaker.email], "proposal_new_message", context = ctx ) - + return redirect(request.path) else: initial = {} @@ -237,7 +235,7 @@ def review_detail(request, pk): elif "result_submit" in request.POST: if admin: result = request.POST["result_submit"] - + if result == "accept": proposal.result.status = "accepted" proposal.result.save() @@ -250,7 +248,7 @@ def review_detail(request, pk): elif result == "standby": proposal.result.status = "standby" proposal.result.save() - + return redirect(request.path) else: initial = {} @@ -261,17 +259,17 @@ def review_detail(request, pk): else: review_form = ReviewForm(initial=initial) message_form = SpeakerCommentForm() - + proposal.comment_count = proposal.result.comment_count proposal.total_votes = proposal.result.vote_count proposal.plus_one = proposal.result.plus_one proposal.plus_zero = proposal.result.plus_zero proposal.minus_zero = proposal.result.minus_zero proposal.minus_one = proposal.result.minus_one - + reviews = Review.objects.filter(proposal=proposal).order_by("-submitted_at") messages = proposal.messages.order_by("submitted_at") - + return render(request, "reviews/review_detail.html", { "proposal": proposal, "latest_vote": latest_vote, @@ -287,33 +285,33 @@ def review_detail(request, pk): def review_delete(request, pk): review = get_object_or_404(Review, pk=pk) section_slug = review.section.slug - + if not request.user.has_perm("reviews.can_manage_%s" % section_slug): return access_not_permitted(request) - + review = get_object_or_404(Review, pk=pk) review.delete() - + return redirect("review_detail", pk=review.proposal.pk) @login_required def review_status(request, section_slug=None, key=None): - + if not request.user.has_perm("reviews.can_review_%s" % section_slug): return access_not_permitted(request) - + VOTE_THRESHOLD = settings.SYMPOSION_VOTE_THRESHOLD - + ctx = { "section_slug": section_slug, "vote_threshold": VOTE_THRESHOLD, } - + queryset = ProposalBase.objects.select_related("speaker__user", "result").select_subclasses() if section_slug: queryset = queryset.filter(kind__section__slug=section_slug) - + proposals = { # proposals with at least VOTE_THRESHOLD reviews and at least one +1 and no -1s, sorted by the 'score' "positive": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD, result__plus_one__gt=0, result__minus_one=0).order_by("-result__score"), @@ -326,14 +324,14 @@ def review_status(request, section_slug=None, key=None): # proposals with fewer than VOTE_THRESHOLD reviews "too_few": queryset.filter(result__vote_count__lt=VOTE_THRESHOLD).order_by("result__vote_count"), } - + admin = request.user.has_perm("reviews.can_manage_%s" % section_slug) - + for status in proposals: if key and key != status: continue proposals[status] = list(proposals_generator(request, proposals[status], check_speaker=not admin)) - + if key: ctx.update({ "key": key, @@ -341,7 +339,7 @@ def review_status(request, section_slug=None, key=None): }) else: ctx["proposals"] = proposals - + return render(request, "reviews/review_stats.html", ctx) @@ -387,7 +385,7 @@ def review_bulk_accept(request, section_slug): return redirect("review_section", section_slug=section_slug) else: form = BulkPresentationForm() - + return render(request, "reviews/review_bulk_accept.html", { "form": form, }) @@ -397,10 +395,10 @@ def review_bulk_accept(request, section_slug): def result_notification(request, section_slug, status): if not request.user.has_perm("reviews.can_manage_%s" % section_slug): return access_not_permitted(request) - + proposals = ProposalBase.objects.filter(kind__section__slug=section_slug, result__status=status).select_related("speaker__user", "result").select_subclasses() notification_templates = NotificationTemplate.objects.all() - + ctx = { "section_slug": section_slug, "status": status, @@ -414,10 +412,10 @@ def result_notification(request, section_slug, status): def result_notification_prepare(request, section_slug, status): if request.method != "POST": return HttpResponseNotAllowed(["POST"]) - + if not request.user.has_perm("reviews.can_manage_%s" % section_slug): return access_not_permitted(request) - + proposal_pks = [] try: for pk in request.POST.getlist("_selected_action"): @@ -431,13 +429,13 @@ def result_notification_prepare(request, section_slug, status): proposals = proposals.filter(pk__in=proposal_pks) proposals = proposals.select_related("speaker__user", "result") proposals = proposals.select_subclasses() - + notification_template_pk = request.POST.get("notification_template", "") if notification_template_pk: notification_template = NotificationTemplate.objects.get(pk=notification_template_pk) else: notification_template = None - + ctx = { "section_slug": section_slug, "status": status, @@ -452,18 +450,18 @@ def result_notification_prepare(request, section_slug, status): def result_notification_send(request, section_slug, status): if request.method != "POST": return HttpResponseNotAllowed(["POST"]) - + if not request.user.has_perm("reviews.can_manage_%s" % section_slug): return access_not_permitted(request) - + if not all([k in request.POST for k in ["proposal_pks", "from_address", "subject", "body"]]): return HttpResponseBadRequest() - + try: proposal_pks = [int(pk) for pk in request.POST["proposal_pks"].split(",")] except ValueError: return HttpResponseBadRequest() - + proposals = ProposalBase.objects.filter( kind__section__slug=section_slug, result__status=status, @@ -471,15 +469,15 @@ def result_notification_send(request, section_slug, status): proposals = proposals.filter(pk__in=proposal_pks) proposals = proposals.select_related("speaker__user", "result") proposals = proposals.select_subclasses() - + notification_template_pk = request.POST.get("notification_template", "") if notification_template_pk: notification_template = NotificationTemplate.objects.get(pk=notification_template_pk) else: notification_template = None - + emails = [] - + for proposal in proposals: rn = ResultNotification() rn.proposal = proposal @@ -494,7 +492,7 @@ def result_notification_send(request, section_slug, status): ) rn.save() emails.append(rn.email_args) - + send_mass_mail(emails) - + return redirect("result_notification", section_slug=section_slug, status=status) diff --git a/symposion/schedule/models.py b/symposion/schedule/models.py index dc070917..c4614437 100644 --- a/symposion/schedule/models.py +++ b/symposion/schedule/models.py @@ -2,44 +2,43 @@ from django.core.exceptions import ObjectDoesNotExist from django.db import models from markitup.fields import MarkupField -from model_utils.managers import InheritanceManager from symposion.proposals.models import ProposalBase from symposion.conference.models import Section class Schedule(models.Model): - + section = models.OneToOneField(Section) published = models.BooleanField(default=True) hidden = models.BooleanField("Hide schedule from overall conference view", default=False) - + def __unicode__(self): return "%s Schedule" % self.section - + class Meta: ordering = ["section"] class Day(models.Model): - + schedule = models.ForeignKey(Schedule) date = models.DateField() - + def __unicode__(self): return "%s" % self.date - + class Meta: unique_together = [("schedule", "date")] ordering = ["date"] class Room(models.Model): - + schedule = models.ForeignKey(Schedule) name = models.CharField(max_length=65) order = models.PositiveIntegerField() - + def __unicode__(self): return self.name @@ -49,22 +48,22 @@ class SlotKind(models.Model): A slot kind represents what kind a slot is. For example, a slot can be a break, lunch, or X-minute talk. """ - + schedule = models.ForeignKey(Schedule) label = models.CharField(max_length=50) - + def __unicode__(self): return self.label class Slot(models.Model): - + day = models.ForeignKey(Day) kind = models.ForeignKey(SlotKind) start = models.TimeField() end = models.TimeField() content_override = MarkupField(blank=True) - + def assign(self, content): """ Assign the given content to this slot and if a previous slot content @@ -73,7 +72,7 @@ class Slot(models.Model): self.unassign() content.slot = self content.save() - + def unassign(self): """ Unassign the associated content with this slot. @@ -81,7 +80,7 @@ class Slot(models.Model): if self.content and self.content.slot_id: self.content.slot = None self.content.save() - + @property def content(self): """ @@ -92,14 +91,14 @@ class Slot(models.Model): return self.content_ptr except ObjectDoesNotExist: return None - + @property def rooms(self): return Room.objects.filter(pk__in=self.slotroom_set.values("room")) - + def __unicode__(self): return "%s %s (%s - %s)" % (self.day, self.kind, self.start, self.end) - + class Meta: ordering = ["day", "start", "end"] @@ -108,20 +107,20 @@ class SlotRoom(models.Model): """ Links a slot with a room. """ - + slot = models.ForeignKey(Slot) room = models.ForeignKey(Room) - + def __unicode__(self): return "%s %s" % (self.room, self.slot) - + class Meta: unique_together = [("slot", "room")] ordering = ["slot", "room__order"] class Presentation(models.Model): - + slot = models.OneToOneField(Slot, null=True, blank=True, related_name="content_ptr") title = models.CharField(max_length=100) description = MarkupField() @@ -131,25 +130,25 @@ class Presentation(models.Model): cancelled = models.BooleanField(default=False) proposal_base = models.OneToOneField(ProposalBase, related_name="presentation") section = models.ForeignKey(Section, related_name="presentations") - + @property def number(self): return self.proposal.number - + @property def proposal(self): if self.proposal_base_id is None: return None return ProposalBase.objects.get_subclass(pk=self.proposal_base_id) - + def speakers(self): yield self.speaker for speaker in self.additional_speakers.all(): if speaker.user: yield speaker - + def __unicode__(self): return "#%s %s (%s)" % (self.number, self.title, self.speaker) - + class Meta: ordering = ["slot"] diff --git a/symposion/schedule/timetable.py b/symposion/schedule/timetable.py index 2aba1de3..2564b0cd 100644 --- a/symposion/schedule/timetable.py +++ b/symposion/schedule/timetable.py @@ -1,5 +1,4 @@ import itertools -import operator from django.db.models import Count, Min @@ -7,22 +6,22 @@ from symposion.schedule.models import Room, Slot, SlotRoom class TimeTable(object): - + def __init__(self, day): self.day = day - + def slots_qs(self): qs = Slot.objects.all() qs = qs.filter(day=self.day) return qs - + def rooms(self): qs = Room.objects.all() qs = qs.filter(schedule=self.day.schedule) qs = qs.filter(pk__in=SlotRoom.objects.filter(slot__in=self.slots_qs().values("pk")).values("room")) qs = qs.order_by("order") return qs - + def __iter__(self): times = sorted(set(itertools.chain(*self.slots_qs().values_list("start", "end")))) slots = Slot.objects.filter(pk__in=self.slots_qs().values("pk")) @@ -38,7 +37,7 @@ class TimeTable(object): row["slots"].append(slot) if row["slots"] or next_time is None: yield row - + @staticmethod def rowspan(times, start, end): return times.index(end) - times.index(start) diff --git a/symposion/schedule/views.py b/symposion/schedule/views.py index 35f9e432..98771b59 100644 --- a/symposion/schedule/views.py +++ b/symposion/schedule/views.py @@ -1,4 +1,3 @@ -from django.core.exceptions import ObjectDoesNotExist from django.http import Http404, HttpResponse from django.shortcuts import render, get_object_or_404, redirect from django.template import loader, Context @@ -12,7 +11,7 @@ from symposion.schedule.timetable import TimeTable def fetch_schedule(slug): qs = Schedule.objects.all() - + if slug is None: if qs.count() > 1: raise Http404() @@ -21,14 +20,14 @@ def fetch_schedule(slug): raise Http404() else: schedule = get_object_or_404(qs, section__slug=slug) - + return schedule def schedule_conference(request): - + schedules = Schedule.objects.filter(published=True, hidden=False) - + sections = [] for schedule in schedules: days_qs = Day.objects.filter(schedule=schedule) @@ -37,7 +36,7 @@ def schedule_conference(request): "schedule": schedule, "days": days, }) - + ctx = { "sections": sections, } @@ -45,14 +44,14 @@ def schedule_conference(request): def schedule_detail(request, slug=None): - + schedule = fetch_schedule(slug) if not schedule.published and not request.user.is_staff: raise Http404() - + days_qs = Day.objects.filter(schedule=schedule) days = [TimeTable(day) for day in days_qs] - + ctx = { "schedule": schedule, "days": days, @@ -62,10 +61,10 @@ def schedule_detail(request, slug=None): def schedule_list(request, slug=None): schedule = fetch_schedule(slug) - + presentations = Presentation.objects.filter(section=schedule.section) presentations = presentations.exclude(cancelled=True) - + ctx = { "schedule": schedule, "presentations": presentations, @@ -75,32 +74,32 @@ def schedule_list(request, slug=None): def schedule_list_csv(request, slug=None): schedule = fetch_schedule(slug) - + presentations = Presentation.objects.filter(section=schedule.section) presentations = presentations.exclude(cancelled=True).order_by("id") - + response = HttpResponse(mimetype="text/csv") if slug: file_slug = slug else: file_slug = "presentations" response["Content-Disposition"] = 'attachment; filename="%s.csv"' % file_slug - + response.write(loader.get_template("schedule/schedule_list.csv").render(Context({ "presentations": presentations, - + }))) return response @login_required def schedule_edit(request, slug=None): - + if not request.user.is_staff: raise Http404() - + schedule = fetch_schedule(slug) - + days_qs = Day.objects.filter(schedule=schedule) days = [TimeTable(day) for day in days_qs] ctx = { @@ -112,12 +111,12 @@ def schedule_edit(request, slug=None): @login_required def schedule_slot_edit(request, slug, slot_pk): - + if not request.user.is_staff: raise Http404() - + slot = get_object_or_404(Slot, day__schedule__section__slug=slug, pk=slot_pk) - + if request.method == "POST": form = SlotEditForm(request.POST, slot=slot) if form.is_valid(): @@ -145,13 +144,13 @@ def schedule_slot_edit(request, slug, slot_pk): def schedule_presentation_detail(request, pk): - + presentation = get_object_or_404(Presentation, pk=pk) if presentation.slot: schedule = presentation.slot.day.schedule else: schedule = None - + ctx = { "presentation": presentation, "schedule": schedule, diff --git a/symposion/speakers/management/commands/export_speaker_data.py b/symposion/speakers/management/commands/export_speaker_data.py index 5f9f565d..00e82588 100644 --- a/symposion/speakers/management/commands/export_speaker_data.py +++ b/symposion/speakers/management/commands/export_speaker_data.py @@ -1,17 +1,17 @@ import csv import os -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand from symposion.speakers.models import Speaker class Command(BaseCommand): - + def handle(self, *args, **options): csv_file = csv.writer(open(os.path.join(os.getcwd(), "speakers.csv"), "wb")) csv_file.writerow(["Name", "Bio"]) - + for speaker in Speaker.objects.all(): csv_file.writerow([ speaker.name.encode("utf-8"), diff --git a/symposion/speakers/urls.py b/symposion/speakers/urls.py index fa7055cf..9a00ea3c 100644 --- a/symposion/speakers/urls.py +++ b/symposion/speakers/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import * +from django.conf.urls.defaults import patterns, url urlpatterns = patterns("symposion.speakers.views", diff --git a/symposion/sponsorship/management/commands/reset_sponsor_benefits.py b/symposion/sponsorship/management/commands/reset_sponsor_benefits.py index 2c515a2e..3c17efab 100644 --- a/symposion/sponsorship/management/commands/reset_sponsor_benefits.py +++ b/symposion/sponsorship/management/commands/reset_sponsor_benefits.py @@ -1,15 +1,13 @@ from django.core.management.base import BaseCommand -from django.contrib.auth.models import Group - -from symposion.sponsorship.models import Sponsor, SponsorBenefit +from symposion.sponsorship.models import Sponsor, SponsorBenefit, SponsorLevel class Command(BaseCommand): - + def handle(self, *args, **options): for sponsor in Sponsor.objects.all(): - level = None + level = None try: level = sponsor.level except SponsorLevel.DoesNotExist: @@ -19,17 +17,17 @@ class Command(BaseCommand): # Create all needed benefits if they don't exist already sponsor_benefit, created = SponsorBenefit.objects.get_or_create( sponsor=sponsor, benefit=benefit_level.benefit) - + if created: print "created", sponsor_benefit, "for", sponsor - + # and set to default limits for this level. sponsor_benefit.max_words = benefit_level.max_words sponsor_benefit.other_limits = benefit_level.other_limits - + # and set to active sponsor_benefit.active = True - + # @@@ We don't call sponsor_benefit.clean here. This means # that if the sponsorship level for a sponsor is adjusted # downwards, an existing too-long text entry can remain, diff --git a/symposion/teams/urls.py b/symposion/teams/urls.py index 01145f41..ed2f7645 100644 --- a/symposion/teams/urls.py +++ b/symposion/teams/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import * +from django.conf.urls.defaults import patterns, url urlpatterns = patterns("symposion.teams.views", @@ -7,7 +7,7 @@ urlpatterns = patterns("symposion.teams.views", url(r"^(?P[\w\-]+)/join/$", "team_join", name="team_join"), url(r"^(?P[\w\-]+)/leave/$", "team_leave", name="team_leave"), url(r"^(?P[\w\-]+)/apply/$", "team_apply", name="team_apply"), - + # membership specific url(r"^promote/(?P\d+)/$", "team_promote", name="team_promote"), url(r"^demote/(?P\d+)/$", "team_demote", name="team_demote"), From 70b0906bc5660e2e80a8fcc2fce1f0af0fb3c588 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Mon, 13 Jan 2014 16:50:01 -0500 Subject: [PATCH 02/46] Remove unused managers --- symposion/proposals/managers.py | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 symposion/proposals/managers.py diff --git a/symposion/proposals/managers.py b/symposion/proposals/managers.py deleted file mode 100644 index b908c7b6..00000000 --- a/symposion/proposals/managers.py +++ /dev/null @@ -1,27 +0,0 @@ -from django.db import models -from django.db.models.query import QuerySet - - -class CachingM2MQuerySet(QuerySet): - - def __init__(self, *args, **kwargs): - super(CachingM2MQuerySet, self).__init__(*args, **kwargs) - self.cached_m2m_field = kwargs["m2m_field"] - - def iterator(self): - parent_iter = super(CachingM2MQuerySet, self).iterator() - m2m_model = getattr(self.model, self.cached_m2m_field).through - - for obj in parent_iter: - if obj.id in cached_objects: - setattr(obj, "_cached_m2m_%s" % self.cached_m2m_field) - yield obj - - -class ProposalManager(models.Manager): - def cache_m2m(self, m2m_field): - return CachingM2MQuerySet(self.model, using=self._db, m2m_field=m2m_field) - AdditionalSpeaker = queryset.model.additional_speakers.through - additional_speakers = collections.defaultdict(set) - for additional_speaker in AdditionalSpeaker._default_manager.filter(proposal__in=queryset).select_related("speaker__user"): - additional_speakers[additional_speaker.proposal_id].add(additional_speaker.speaker) \ No newline at end of file From ef66c7ed125601e49f627b9a036537b7e4dc60d9 Mon Sep 17 00:00:00 2001 From: David Ray Date: Tue, 14 Jan 2014 09:47:49 -0500 Subject: [PATCH 03/46] Adding South Support; Work on #1 --- symposion/boxes/migrations/0001_initial.py | 76 +++++ symposion/boxes/migrations/__init__.py | 0 symposion/cms/migrations/0001_initial.py | 83 +++++ symposion/cms/migrations/__init__.py | 0 .../conference/migrations/0001_initial.py | 61 ++++ symposion/conference/migrations/__init__.py | 0 symposion/conference/models.py | 25 +- .../proposals/migrations/0001_initial.py | 254 ++++++++++++++ symposion/proposals/migrations/__init__.py | 0 symposion/reviews/migrations/0001_initial.py | 316 ++++++++++++++++++ symposion/reviews/migrations/__init__.py | 0 symposion/schedule/migrations/0001_initial.py | 284 ++++++++++++++++ symposion/schedule/migrations/__init__.py | 0 symposion/speakers/migrations/0001_initial.py | 84 +++++ symposion/speakers/migrations/__init__.py | 0 .../sponsorship/migrations/0001_initial.py | 184 ++++++++++ symposion/sponsorship/migrations/__init__.py | 0 symposion/teams/migrations/0001_initial.py | 123 +++++++ symposion/teams/migrations/__init__.py | 0 19 files changed, 1479 insertions(+), 11 deletions(-) create mode 100644 symposion/boxes/migrations/0001_initial.py create mode 100644 symposion/boxes/migrations/__init__.py create mode 100644 symposion/cms/migrations/0001_initial.py create mode 100644 symposion/cms/migrations/__init__.py create mode 100644 symposion/conference/migrations/0001_initial.py create mode 100644 symposion/conference/migrations/__init__.py create mode 100644 symposion/proposals/migrations/0001_initial.py create mode 100644 symposion/proposals/migrations/__init__.py create mode 100644 symposion/reviews/migrations/0001_initial.py create mode 100644 symposion/reviews/migrations/__init__.py create mode 100644 symposion/schedule/migrations/0001_initial.py create mode 100644 symposion/schedule/migrations/__init__.py create mode 100644 symposion/speakers/migrations/0001_initial.py create mode 100644 symposion/speakers/migrations/__init__.py create mode 100644 symposion/sponsorship/migrations/0001_initial.py create mode 100644 symposion/sponsorship/migrations/__init__.py create mode 100644 symposion/teams/migrations/0001_initial.py create mode 100644 symposion/teams/migrations/__init__.py diff --git a/symposion/boxes/migrations/0001_initial.py b/symposion/boxes/migrations/0001_initial.py new file mode 100644 index 00000000..7e0f7f75 --- /dev/null +++ b/symposion/boxes/migrations/0001_initial.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Box' + db.create_table('boxes_box', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('label', self.gf('django.db.models.fields.CharField')(max_length=100, db_index=True)), + ('content', self.gf('markitup.fields.MarkupField')(no_rendered_field=True, blank=True)), + ('created_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='boxes', to=orm['auth.User'])), + ('last_updated_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='updated_boxes', to=orm['auth.User'])), + ('_content_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('boxes', ['Box']) + + + def backwards(self, orm): + # Deleting model 'Box' + db.delete_table('boxes_box') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'boxes.box': { + 'Meta': {'object_name': 'Box'}, + '_content_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'content': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'boxes'", 'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '100', 'db_index': 'True'}), + 'last_updated_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'updated_boxes'", 'to': "orm['auth.User']"}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + } + } + + complete_apps = ['boxes'] \ No newline at end of file diff --git a/symposion/boxes/migrations/__init__.py b/symposion/boxes/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/cms/migrations/0001_initial.py b/symposion/cms/migrations/0001_initial.py new file mode 100644 index 00000000..beb391d2 --- /dev/null +++ b/symposion/cms/migrations/0001_initial.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Page' + db.create_table('cms_page', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('title', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('path', self.gf('django.db.models.fields.CharField')(unique=True, max_length=100)), + ('body', self.gf('markitup.fields.MarkupField')(no_rendered_field=True)), + ('status', self.gf('django.db.models.fields.IntegerField')(default=2)), + ('publish_date', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('updated', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('_body_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('cms', ['Page']) + + # Adding model 'File' + db.create_table('cms_file', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('file', self.gf('django.db.models.fields.files.FileField')(max_length=100)), + ('created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + )) + db.send_create_signal('cms', ['File']) + + + def backwards(self, orm): + # Deleting model 'Page' + db.delete_table('cms_page') + + # Deleting model 'File' + db.delete_table('cms_file') + + + models = { + 'cms.file': { + 'Meta': {'object_name': 'File'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'cms.page': { + 'Meta': {'object_name': 'Page'}, + '_body_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'body': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}), + 'publish_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'status': ('django.db.models.fields.IntegerField', [], {'default': '2'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['cms'] \ No newline at end of file diff --git a/symposion/cms/migrations/__init__.py b/symposion/cms/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/conference/migrations/0001_initial.py b/symposion/conference/migrations/0001_initial.py new file mode 100644 index 00000000..7546ca52 --- /dev/null +++ b/symposion/conference/migrations/0001_initial.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Conference' + db.create_table('conference_conference', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('title', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('start_date', self.gf('django.db.models.fields.DateField')(null=True, blank=True)), + ('end_date', self.gf('django.db.models.fields.DateField')(null=True, blank=True)), + ('timezone', self.gf('timezones.fields.TimeZoneField')(default='US/Eastern', max_length=100, blank=True)), + )) + db.send_create_signal('conference', ['Conference']) + + # Adding model 'Section' + db.create_table('conference_section', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('conference', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['conference.Conference'])), + ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('slug', self.gf('django.db.models.fields.SlugField')(max_length=50)), + ('start_date', self.gf('django.db.models.fields.DateField')(null=True, blank=True)), + ('end_date', self.gf('django.db.models.fields.DateField')(null=True, blank=True)), + )) + db.send_create_signal('conference', ['Section']) + + + def backwards(self, orm): + # Deleting model 'Conference' + db.delete_table('conference_conference') + + # Deleting model 'Section' + db.delete_table('conference_section') + + + models = { + 'conference.conference': { + 'Meta': {'object_name': 'Conference'}, + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'timezone': ('timezones.fields.TimeZoneField', [], {'default': "'US/Eastern'", 'max_length': '100', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'conference.section': { + 'Meta': {'ordering': "['start_date']", 'object_name': 'Section'}, + 'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Conference']"}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['conference'] \ No newline at end of file diff --git a/symposion/conference/migrations/__init__.py b/symposion/conference/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/conference/models.py b/symposion/conference/models.py index 4bb6b8ce..db09050f 100644 --- a/symposion/conference/models.py +++ b/symposion/conference/models.py @@ -3,6 +3,9 @@ from django.utils.translation import ugettext_lazy as _ from timezones.fields import TimeZoneField +from south.modelsinspector import add_introspection_rules +add_introspection_rules([], [r"^timezones\.fields\.TimeZoneField"]) + CONFERENCE_CACHE = {} @@ -11,24 +14,24 @@ class Conference(models.Model): """ the full conference for a specific year, e.g. US PyCon 2012. """ - + title = models.CharField(_("title"), max_length=100) - + # when the conference runs start_date = models.DateField(_("start date"), null=True, blank=True) end_date = models.DateField(_("end date"), null=True, blank=True) - + # timezone the conference is in timezone = TimeZoneField(_("timezone"), blank=True) - + def __unicode__(self): return self.title - + def save(self, *args, **kwargs): super(Conference, self).save(*args, **kwargs) if self.id in CONFERENCE_CACHE: del CONFERENCE_CACHE[self.id] - + def delete(self): pk = self.pk super(Conference, self).delete() @@ -36,7 +39,7 @@ class Conference(models.Model): del CONFERENCE_CACHE[pk] except KeyError: pass - + class Meta(object): verbose_name = _("conference") verbose_name_plural = _("conferences") @@ -48,19 +51,19 @@ class Section(models.Model): "Talks", "Expo", "Sprints", that may have its own review and scheduling process. """ - + conference = models.ForeignKey(Conference, verbose_name=_("conference")) - + name = models.CharField(_("name"), max_length=100) slug = models.SlugField() # when the section runs start_date = models.DateField(_("start date"), null=True, blank=True) end_date = models.DateField(_("end date"), null=True, blank=True) - + def __unicode__(self): return "%s %s" % (self.conference, self.name) - + class Meta(object): verbose_name = _("section") verbose_name_plural = _("sections") diff --git a/symposion/proposals/migrations/0001_initial.py b/symposion/proposals/migrations/0001_initial.py new file mode 100644 index 00000000..c1fb4940 --- /dev/null +++ b/symposion/proposals/migrations/0001_initial.py @@ -0,0 +1,254 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'ProposalSection' + db.create_table('proposals_proposalsection', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('section', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['conference.Section'], unique=True)), + ('start', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)), + ('end', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)), + ('closed', self.gf('django.db.models.fields.NullBooleanField')(null=True, blank=True)), + ('published', self.gf('django.db.models.fields.NullBooleanField')(null=True, blank=True)), + )) + db.send_create_signal('proposals', ['ProposalSection']) + + # Adding model 'ProposalKind' + db.create_table('proposals_proposalkind', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('section', self.gf('django.db.models.fields.related.ForeignKey')(related_name='proposal_kinds', to=orm['conference.Section'])), + ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('slug', self.gf('django.db.models.fields.SlugField')(max_length=50)), + )) + db.send_create_signal('proposals', ['ProposalKind']) + + # Adding model 'ProposalBase' + db.create_table('proposals_proposalbase', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('kind', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['proposals.ProposalKind'])), + ('title', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('description', self.gf('django.db.models.fields.TextField')(max_length=400)), + ('abstract', self.gf('markitup.fields.MarkupField')(no_rendered_field=True)), + ('additional_notes', self.gf('markitup.fields.MarkupField')(no_rendered_field=True, blank=True)), + ('submitted', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('speaker', self.gf('django.db.models.fields.related.ForeignKey')(related_name='proposals', to=orm['speakers.Speaker'])), + ('cancelled', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('_abstract_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + ('_additional_notes_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('proposals', ['ProposalBase']) + + # Adding model 'AdditionalSpeaker' + db.create_table('proposals_proposalbase_additional_speakers', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('speaker', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['speakers.Speaker'])), + ('proposalbase', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['proposals.ProposalBase'])), + ('status', self.gf('django.db.models.fields.IntegerField')(default=1)), + )) + db.send_create_signal('proposals', ['AdditionalSpeaker']) + + # Adding unique constraint on 'AdditionalSpeaker', fields ['speaker', 'proposalbase'] + db.create_unique('proposals_proposalbase_additional_speakers', ['speaker_id', 'proposalbase_id']) + + # Adding model 'SupportingDocument' + db.create_table('proposals_supportingdocument', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('proposal', self.gf('django.db.models.fields.related.ForeignKey')(related_name='supporting_documents', to=orm['proposals.ProposalBase'])), + ('uploaded_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('created_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('file', self.gf('django.db.models.fields.files.FileField')(max_length=100)), + ('description', self.gf('django.db.models.fields.CharField')(max_length=140)), + )) + db.send_create_signal('proposals', ['SupportingDocument']) + + # Adding model 'TalkProposal' + db.create_table('proposals_talkproposal', ( + ('proposalbase_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['proposals.ProposalBase'], unique=True, primary_key=True)), + ('audience_level', self.gf('django.db.models.fields.IntegerField')()), + ('recording_release', self.gf('django.db.models.fields.BooleanField')(default=True)), + )) + db.send_create_signal('proposals', ['TalkProposal']) + + # Adding model 'TutorialProposal' + db.create_table('proposals_tutorialproposal', ( + ('proposalbase_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['proposals.ProposalBase'], unique=True, primary_key=True)), + ('audience_level', self.gf('django.db.models.fields.IntegerField')()), + ('recording_release', self.gf('django.db.models.fields.BooleanField')(default=True)), + )) + db.send_create_signal('proposals', ['TutorialProposal']) + + # Adding model 'OpenSpaceProposal' + db.create_table('proposals_openspaceproposal', ( + ('proposalbase_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['proposals.ProposalBase'], unique=True, primary_key=True)), + )) + db.send_create_signal('proposals', ['OpenSpaceProposal']) + + + def backwards(self, orm): + # Removing unique constraint on 'AdditionalSpeaker', fields ['speaker', 'proposalbase'] + db.delete_unique('proposals_proposalbase_additional_speakers', ['speaker_id', 'proposalbase_id']) + + # Deleting model 'ProposalSection' + db.delete_table('proposals_proposalsection') + + # Deleting model 'ProposalKind' + db.delete_table('proposals_proposalkind') + + # Deleting model 'ProposalBase' + db.delete_table('proposals_proposalbase') + + # Deleting model 'AdditionalSpeaker' + db.delete_table('proposals_proposalbase_additional_speakers') + + # Deleting model 'SupportingDocument' + db.delete_table('proposals_supportingdocument') + + # Deleting model 'TalkProposal' + db.delete_table('proposals_talkproposal') + + # Deleting model 'TutorialProposal' + db.delete_table('proposals_tutorialproposal') + + # Deleting model 'OpenSpaceProposal' + db.delete_table('proposals_openspaceproposal') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'conference.conference': { + 'Meta': {'object_name': 'Conference'}, + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'timezone': ('timezones.fields.TimeZoneField', [], {'default': "'US/Eastern'", 'max_length': '100', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'conference.section': { + 'Meta': {'ordering': "['start_date']", 'object_name': 'Section'}, + 'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Conference']"}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'proposals.additionalspeaker': { + 'Meta': {'unique_together': "(('speaker', 'proposalbase'),)", 'object_name': 'AdditionalSpeaker', 'db_table': "'proposals_proposalbase_additional_speakers'"}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposalbase': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['proposals.ProposalBase']"}), + 'speaker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['speakers.Speaker']"}), + 'status': ('django.db.models.fields.IntegerField', [], {'default': '1'}) + }, + 'proposals.openspaceproposal': { + 'Meta': {'object_name': 'OpenSpaceProposal', '_ormbases': ['proposals.ProposalBase']}, + 'proposalbase_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['proposals.ProposalBase']", 'unique': 'True', 'primary_key': 'True'}) + }, + 'proposals.proposalbase': { + 'Meta': {'object_name': 'ProposalBase'}, + '_abstract_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + '_additional_notes_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'abstract': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}), + 'additional_notes': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'additional_speakers': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['speakers.Speaker']", 'symmetrical': 'False', 'through': "orm['proposals.AdditionalSpeaker']", 'blank': 'True'}), + 'cancelled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'description': ('django.db.models.fields.TextField', [], {'max_length': '400'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'kind': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['proposals.ProposalKind']"}), + 'speaker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'proposals'", 'to': "orm['speakers.Speaker']"}), + 'submitted': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'proposals.proposalkind': { + 'Meta': {'object_name': 'ProposalKind'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'proposal_kinds'", 'to': "orm['conference.Section']"}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}) + }, + 'proposals.proposalsection': { + 'Meta': {'object_name': 'ProposalSection'}, + 'closed': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'end': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'published': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'section': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['conference.Section']", 'unique': 'True'}), + 'start': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + 'proposals.supportingdocument': { + 'Meta': {'object_name': 'SupportingDocument'}, + 'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '140'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposal': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'supporting_documents'", 'to': "orm['proposals.ProposalBase']"}), + 'uploaded_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'proposals.talkproposal': { + 'Meta': {'object_name': 'TalkProposal'}, + 'audience_level': ('django.db.models.fields.IntegerField', [], {}), + 'proposalbase_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['proposals.ProposalBase']", 'unique': 'True', 'primary_key': 'True'}), + 'recording_release': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'proposals.tutorialproposal': { + 'Meta': {'object_name': 'TutorialProposal'}, + 'audience_level': ('django.db.models.fields.IntegerField', [], {}), + 'proposalbase_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['proposals.ProposalBase']", 'unique': 'True', 'primary_key': 'True'}), + 'recording_release': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) + }, + 'speakers.speaker': { + 'Meta': {'ordering': "['name']", 'object_name': 'Speaker'}, + '_biography_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'annotation': ('django.db.models.fields.TextField', [], {}), + 'biography': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invite_email': ('django.db.models.fields.CharField', [], {'max_length': '200', 'unique': 'True', 'null': 'True', 'db_index': 'True'}), + 'invite_token': ('django.db.models.fields.CharField', [], {'max_length': '40', 'db_index': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'photo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'speaker_profile'", 'unique': 'True', 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['proposals'] \ No newline at end of file diff --git a/symposion/proposals/migrations/__init__.py b/symposion/proposals/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/reviews/migrations/0001_initial.py b/symposion/reviews/migrations/0001_initial.py new file mode 100644 index 00000000..76df4e2f --- /dev/null +++ b/symposion/reviews/migrations/0001_initial.py @@ -0,0 +1,316 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'ReviewAssignment' + db.create_table('reviews_reviewassignment', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('proposal', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['proposals.ProposalBase'])), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('origin', self.gf('django.db.models.fields.IntegerField')()), + ('assigned_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('opted_out', self.gf('django.db.models.fields.BooleanField')(default=False)), + )) + db.send_create_signal('reviews', ['ReviewAssignment']) + + # Adding model 'ProposalMessage' + db.create_table('reviews_proposalmessage', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('proposal', self.gf('django.db.models.fields.related.ForeignKey')(related_name='messages', to=orm['proposals.ProposalBase'])), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('message', self.gf('markitup.fields.MarkupField')(no_rendered_field=True)), + ('submitted_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('_message_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('reviews', ['ProposalMessage']) + + # Adding model 'Review' + db.create_table('reviews_review', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('proposal', self.gf('django.db.models.fields.related.ForeignKey')(related_name='reviews', to=orm['proposals.ProposalBase'])), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('vote', self.gf('django.db.models.fields.CharField')(max_length=2, blank=True)), + ('comment', self.gf('markitup.fields.MarkupField')(no_rendered_field=True)), + ('submitted_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('_comment_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('reviews', ['Review']) + + # Adding model 'LatestVote' + db.create_table('reviews_latestvote', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('proposal', self.gf('django.db.models.fields.related.ForeignKey')(related_name='votes', to=orm['proposals.ProposalBase'])), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('vote', self.gf('django.db.models.fields.CharField')(max_length=2)), + ('submitted_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + )) + db.send_create_signal('reviews', ['LatestVote']) + + # Adding unique constraint on 'LatestVote', fields ['proposal', 'user'] + db.create_unique('reviews_latestvote', ['proposal_id', 'user_id']) + + # Adding model 'ProposalResult' + db.create_table('reviews_proposalresult', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('proposal', self.gf('django.db.models.fields.related.OneToOneField')(related_name='result', unique=True, to=orm['proposals.ProposalBase'])), + ('score', self.gf('django.db.models.fields.DecimalField')(default='0.00', max_digits=5, decimal_places=2)), + ('comment_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), + ('vote_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), + ('plus_one', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), + ('plus_zero', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), + ('minus_zero', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), + ('minus_one', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), + ('accepted', self.gf('django.db.models.fields.NullBooleanField')(default=None, null=True, blank=True)), + ('status', self.gf('django.db.models.fields.CharField')(default='undecided', max_length=20)), + )) + db.send_create_signal('reviews', ['ProposalResult']) + + # Adding model 'Comment' + db.create_table('reviews_comment', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('proposal', self.gf('django.db.models.fields.related.ForeignKey')(related_name='comments', to=orm['proposals.ProposalBase'])), + ('commenter', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('text', self.gf('markitup.fields.MarkupField')(no_rendered_field=True)), + ('public', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('commented_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('_text_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('reviews', ['Comment']) + + # Adding model 'NotificationTemplate' + db.create_table('reviews_notificationtemplate', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('label', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('from_address', self.gf('django.db.models.fields.EmailField')(max_length=75)), + ('subject', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('body', self.gf('django.db.models.fields.TextField')()), + )) + db.send_create_signal('reviews', ['NotificationTemplate']) + + # Adding model 'ResultNotification' + db.create_table('reviews_resultnotification', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('proposal', self.gf('django.db.models.fields.related.ForeignKey')(related_name='notifications', to=orm['proposals.ProposalBase'])), + ('template', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['reviews.NotificationTemplate'], null=True, on_delete=models.SET_NULL, blank=True)), + ('timestamp', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('to_address', self.gf('django.db.models.fields.EmailField')(max_length=75)), + ('from_address', self.gf('django.db.models.fields.EmailField')(max_length=75)), + ('subject', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('body', self.gf('django.db.models.fields.TextField')()), + )) + db.send_create_signal('reviews', ['ResultNotification']) + + + def backwards(self, orm): + # Removing unique constraint on 'LatestVote', fields ['proposal', 'user'] + db.delete_unique('reviews_latestvote', ['proposal_id', 'user_id']) + + # Deleting model 'ReviewAssignment' + db.delete_table('reviews_reviewassignment') + + # Deleting model 'ProposalMessage' + db.delete_table('reviews_proposalmessage') + + # Deleting model 'Review' + db.delete_table('reviews_review') + + # Deleting model 'LatestVote' + db.delete_table('reviews_latestvote') + + # Deleting model 'ProposalResult' + db.delete_table('reviews_proposalresult') + + # Deleting model 'Comment' + db.delete_table('reviews_comment') + + # Deleting model 'NotificationTemplate' + db.delete_table('reviews_notificationtemplate') + + # Deleting model 'ResultNotification' + db.delete_table('reviews_resultnotification') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'conference.conference': { + 'Meta': {'object_name': 'Conference'}, + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'timezone': ('timezones.fields.TimeZoneField', [], {'default': "'US/Eastern'", 'max_length': '100', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'conference.section': { + 'Meta': {'ordering': "['start_date']", 'object_name': 'Section'}, + 'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Conference']"}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'proposals.additionalspeaker': { + 'Meta': {'unique_together': "(('speaker', 'proposalbase'),)", 'object_name': 'AdditionalSpeaker', 'db_table': "'proposals_proposalbase_additional_speakers'"}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposalbase': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['proposals.ProposalBase']"}), + 'speaker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['speakers.Speaker']"}), + 'status': ('django.db.models.fields.IntegerField', [], {'default': '1'}) + }, + 'proposals.proposalbase': { + 'Meta': {'object_name': 'ProposalBase'}, + '_abstract_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + '_additional_notes_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'abstract': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}), + 'additional_notes': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'additional_speakers': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['speakers.Speaker']", 'symmetrical': 'False', 'through': "orm['proposals.AdditionalSpeaker']", 'blank': 'True'}), + 'cancelled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'description': ('django.db.models.fields.TextField', [], {'max_length': '400'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'kind': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['proposals.ProposalKind']"}), + 'speaker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'proposals'", 'to': "orm['speakers.Speaker']"}), + 'submitted': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'proposals.proposalkind': { + 'Meta': {'object_name': 'ProposalKind'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'proposal_kinds'", 'to': "orm['conference.Section']"}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}) + }, + 'reviews.comment': { + 'Meta': {'object_name': 'Comment'}, + '_text_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'commented_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'commenter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposal': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['proposals.ProposalBase']"}), + 'public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'text': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}) + }, + 'reviews.latestvote': { + 'Meta': {'unique_together': "[('proposal', 'user')]", 'object_name': 'LatestVote'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposal': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['proposals.ProposalBase']"}), + 'submitted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'vote': ('django.db.models.fields.CharField', [], {'max_length': '2'}) + }, + 'reviews.notificationtemplate': { + 'Meta': {'object_name': 'NotificationTemplate'}, + 'body': ('django.db.models.fields.TextField', [], {}), + 'from_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'subject': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'reviews.proposalmessage': { + 'Meta': {'ordering': "['submitted_at']", 'object_name': 'ProposalMessage'}, + '_message_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'message': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}), + 'proposal': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['proposals.ProposalBase']"}), + 'submitted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'reviews.proposalresult': { + 'Meta': {'object_name': 'ProposalResult'}, + 'accepted': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}), + 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'minus_one': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'minus_zero': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'plus_one': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'plus_zero': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'proposal': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'result'", 'unique': 'True', 'to': "orm['proposals.ProposalBase']"}), + 'score': ('django.db.models.fields.DecimalField', [], {'default': "'0.00'", 'max_digits': '5', 'decimal_places': '2'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'undecided'", 'max_length': '20'}), + 'vote_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + }, + 'reviews.resultnotification': { + 'Meta': {'object_name': 'ResultNotification'}, + 'body': ('django.db.models.fields.TextField', [], {}), + 'from_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposal': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notifications'", 'to': "orm['proposals.ProposalBase']"}), + 'subject': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'template': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['reviews.NotificationTemplate']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'to_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}) + }, + 'reviews.review': { + 'Meta': {'object_name': 'Review'}, + '_comment_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'comment': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposal': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reviews'", 'to': "orm['proposals.ProposalBase']"}), + 'submitted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'vote': ('django.db.models.fields.CharField', [], {'max_length': '2', 'blank': 'True'}) + }, + 'reviews.reviewassignment': { + 'Meta': {'object_name': 'ReviewAssignment'}, + 'assigned_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'opted_out': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'origin': ('django.db.models.fields.IntegerField', [], {}), + 'proposal': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['proposals.ProposalBase']"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'speakers.speaker': { + 'Meta': {'ordering': "['name']", 'object_name': 'Speaker'}, + '_biography_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'annotation': ('django.db.models.fields.TextField', [], {}), + 'biography': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invite_email': ('django.db.models.fields.CharField', [], {'max_length': '200', 'unique': 'True', 'null': 'True', 'db_index': 'True'}), + 'invite_token': ('django.db.models.fields.CharField', [], {'max_length': '40', 'db_index': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'photo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'speaker_profile'", 'unique': 'True', 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['reviews'] \ No newline at end of file diff --git a/symposion/reviews/migrations/__init__.py b/symposion/reviews/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/schedule/migrations/0001_initial.py b/symposion/schedule/migrations/0001_initial.py new file mode 100644 index 00000000..3798087d --- /dev/null +++ b/symposion/schedule/migrations/0001_initial.py @@ -0,0 +1,284 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Schedule' + db.create_table('schedule_schedule', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('section', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['conference.Section'], unique=True)), + ('published', self.gf('django.db.models.fields.BooleanField')(default=True)), + ('hidden', self.gf('django.db.models.fields.BooleanField')(default=False)), + )) + db.send_create_signal('schedule', ['Schedule']) + + # Adding model 'Day' + db.create_table('schedule_day', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('schedule', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['schedule.Schedule'])), + ('date', self.gf('django.db.models.fields.DateField')()), + )) + db.send_create_signal('schedule', ['Day']) + + # Adding unique constraint on 'Day', fields ['schedule', 'date'] + db.create_unique('schedule_day', ['schedule_id', 'date']) + + # Adding model 'Room' + db.create_table('schedule_room', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('schedule', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['schedule.Schedule'])), + ('name', self.gf('django.db.models.fields.CharField')(max_length=65)), + ('order', self.gf('django.db.models.fields.PositiveIntegerField')()), + )) + db.send_create_signal('schedule', ['Room']) + + # Adding model 'SlotKind' + db.create_table('schedule_slotkind', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('schedule', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['schedule.Schedule'])), + ('label', self.gf('django.db.models.fields.CharField')(max_length=50)), + )) + db.send_create_signal('schedule', ['SlotKind']) + + # Adding model 'Slot' + db.create_table('schedule_slot', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('day', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['schedule.Day'])), + ('kind', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['schedule.SlotKind'])), + ('start', self.gf('django.db.models.fields.TimeField')()), + ('end', self.gf('django.db.models.fields.TimeField')()), + ('content_override', self.gf('markitup.fields.MarkupField')(no_rendered_field=True, blank=True)), + ('_content_override_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('schedule', ['Slot']) + + # Adding model 'SlotRoom' + db.create_table('schedule_slotroom', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('slot', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['schedule.Slot'])), + ('room', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['schedule.Room'])), + )) + db.send_create_signal('schedule', ['SlotRoom']) + + # Adding unique constraint on 'SlotRoom', fields ['slot', 'room'] + db.create_unique('schedule_slotroom', ['slot_id', 'room_id']) + + # Adding model 'Presentation' + db.create_table('schedule_presentation', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('slot', self.gf('django.db.models.fields.related.OneToOneField')(blank=True, related_name='content_ptr', unique=True, null=True, to=orm['schedule.Slot'])), + ('title', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('description', self.gf('markitup.fields.MarkupField')(no_rendered_field=True)), + ('abstract', self.gf('markitup.fields.MarkupField')(no_rendered_field=True)), + ('speaker', self.gf('django.db.models.fields.related.ForeignKey')(related_name='presentations', to=orm['speakers.Speaker'])), + ('cancelled', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('proposal_base', self.gf('django.db.models.fields.related.OneToOneField')(related_name='presentation', unique=True, to=orm['proposals.ProposalBase'])), + ('section', self.gf('django.db.models.fields.related.ForeignKey')(related_name='presentations', to=orm['conference.Section'])), + ('_description_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + ('_abstract_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('schedule', ['Presentation']) + + # Adding M2M table for field additional_speakers on 'Presentation' + m2m_table_name = db.shorten_name('schedule_presentation_additional_speakers') + db.create_table(m2m_table_name, ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('presentation', models.ForeignKey(orm['schedule.presentation'], null=False)), + ('speaker', models.ForeignKey(orm['speakers.speaker'], null=False)) + )) + db.create_unique(m2m_table_name, ['presentation_id', 'speaker_id']) + + + def backwards(self, orm): + # Removing unique constraint on 'SlotRoom', fields ['slot', 'room'] + db.delete_unique('schedule_slotroom', ['slot_id', 'room_id']) + + # Removing unique constraint on 'Day', fields ['schedule', 'date'] + db.delete_unique('schedule_day', ['schedule_id', 'date']) + + # Deleting model 'Schedule' + db.delete_table('schedule_schedule') + + # Deleting model 'Day' + db.delete_table('schedule_day') + + # Deleting model 'Room' + db.delete_table('schedule_room') + + # Deleting model 'SlotKind' + db.delete_table('schedule_slotkind') + + # Deleting model 'Slot' + db.delete_table('schedule_slot') + + # Deleting model 'SlotRoom' + db.delete_table('schedule_slotroom') + + # Deleting model 'Presentation' + db.delete_table('schedule_presentation') + + # Removing M2M table for field additional_speakers on 'Presentation' + db.delete_table(db.shorten_name('schedule_presentation_additional_speakers')) + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'conference.conference': { + 'Meta': {'object_name': 'Conference'}, + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'timezone': ('timezones.fields.TimeZoneField', [], {'default': "'US/Eastern'", 'max_length': '100', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'conference.section': { + 'Meta': {'ordering': "['start_date']", 'object_name': 'Section'}, + 'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Conference']"}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'proposals.additionalspeaker': { + 'Meta': {'unique_together': "(('speaker', 'proposalbase'),)", 'object_name': 'AdditionalSpeaker', 'db_table': "'proposals_proposalbase_additional_speakers'"}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposalbase': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['proposals.ProposalBase']"}), + 'speaker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['speakers.Speaker']"}), + 'status': ('django.db.models.fields.IntegerField', [], {'default': '1'}) + }, + 'proposals.proposalbase': { + 'Meta': {'object_name': 'ProposalBase'}, + '_abstract_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + '_additional_notes_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'abstract': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}), + 'additional_notes': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'additional_speakers': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['speakers.Speaker']", 'symmetrical': 'False', 'through': "orm['proposals.AdditionalSpeaker']", 'blank': 'True'}), + 'cancelled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'description': ('django.db.models.fields.TextField', [], {'max_length': '400'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'kind': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['proposals.ProposalKind']"}), + 'speaker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'proposals'", 'to': "orm['speakers.Speaker']"}), + 'submitted': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'proposals.proposalkind': { + 'Meta': {'object_name': 'ProposalKind'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'proposal_kinds'", 'to': "orm['conference.Section']"}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}) + }, + 'schedule.day': { + 'Meta': {'ordering': "['date']", 'unique_together': "[('schedule', 'date')]", 'object_name': 'Day'}, + 'date': ('django.db.models.fields.DateField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'schedule': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Schedule']"}) + }, + 'schedule.presentation': { + 'Meta': {'ordering': "['slot']", 'object_name': 'Presentation'}, + '_abstract_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + '_description_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'abstract': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}), + 'additional_speakers': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'copresentations'", 'blank': 'True', 'to': "orm['speakers.Speaker']"}), + 'cancelled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'description': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposal_base': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'presentation'", 'unique': 'True', 'to': "orm['proposals.ProposalBase']"}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'presentations'", 'to': "orm['conference.Section']"}), + 'slot': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'content_ptr'", 'unique': 'True', 'null': 'True', 'to': "orm['schedule.Slot']"}), + 'speaker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'presentations'", 'to': "orm['speakers.Speaker']"}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'schedule.room': { + 'Meta': {'object_name': 'Room'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '65'}), + 'order': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'schedule': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Schedule']"}) + }, + 'schedule.schedule': { + 'Meta': {'ordering': "['section']", 'object_name': 'Schedule'}, + 'hidden': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'published': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'section': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['conference.Section']", 'unique': 'True'}) + }, + 'schedule.slot': { + 'Meta': {'ordering': "['day', 'start', 'end']", 'object_name': 'Slot'}, + '_content_override_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'content_override': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'day': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Day']"}), + 'end': ('django.db.models.fields.TimeField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'kind': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.SlotKind']"}), + 'start': ('django.db.models.fields.TimeField', [], {}) + }, + 'schedule.slotkind': { + 'Meta': {'object_name': 'SlotKind'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'schedule': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Schedule']"}) + }, + 'schedule.slotroom': { + 'Meta': {'ordering': "['slot', 'room__order']", 'unique_together': "[('slot', 'room')]", 'object_name': 'SlotRoom'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'room': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Room']"}), + 'slot': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Slot']"}) + }, + 'speakers.speaker': { + 'Meta': {'ordering': "['name']", 'object_name': 'Speaker'}, + '_biography_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'annotation': ('django.db.models.fields.TextField', [], {}), + 'biography': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invite_email': ('django.db.models.fields.CharField', [], {'max_length': '200', 'unique': 'True', 'null': 'True', 'db_index': 'True'}), + 'invite_token': ('django.db.models.fields.CharField', [], {'max_length': '40', 'db_index': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'photo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'speaker_profile'", 'unique': 'True', 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['schedule'] \ No newline at end of file diff --git a/symposion/schedule/migrations/__init__.py b/symposion/schedule/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/speakers/migrations/0001_initial.py b/symposion/speakers/migrations/0001_initial.py new file mode 100644 index 00000000..1db93f8c --- /dev/null +++ b/symposion/speakers/migrations/0001_initial.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Speaker' + db.create_table('speakers_speaker', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('user', self.gf('django.db.models.fields.related.OneToOneField')(related_name='speaker_profile', unique=True, null=True, to=orm['auth.User'])), + ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('biography', self.gf('markitup.fields.MarkupField')(no_rendered_field=True, blank=True)), + ('photo', self.gf('django.db.models.fields.files.ImageField')(max_length=100, blank=True)), + ('annotation', self.gf('django.db.models.fields.TextField')()), + ('invite_email', self.gf('django.db.models.fields.CharField')(max_length=200, unique=True, null=True, db_index=True)), + ('invite_token', self.gf('django.db.models.fields.CharField')(max_length=40, db_index=True)), + ('created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('_biography_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('speakers', ['Speaker']) + + + def backwards(self, orm): + # Deleting model 'Speaker' + db.delete_table('speakers_speaker') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'speakers.speaker': { + 'Meta': {'ordering': "['name']", 'object_name': 'Speaker'}, + '_biography_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'annotation': ('django.db.models.fields.TextField', [], {}), + 'biography': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invite_email': ('django.db.models.fields.CharField', [], {'max_length': '200', 'unique': 'True', 'null': 'True', 'db_index': 'True'}), + 'invite_token': ('django.db.models.fields.CharField', [], {'max_length': '40', 'db_index': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'photo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'speaker_profile'", 'unique': 'True', 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['speakers'] \ No newline at end of file diff --git a/symposion/speakers/migrations/__init__.py b/symposion/speakers/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/sponsorship/migrations/0001_initial.py b/symposion/sponsorship/migrations/0001_initial.py new file mode 100644 index 00000000..4bf423d9 --- /dev/null +++ b/symposion/sponsorship/migrations/0001_initial.py @@ -0,0 +1,184 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'SponsorLevel' + db.create_table('sponsorship_sponsorlevel', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('conference', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['conference.Conference'])), + ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('order', self.gf('django.db.models.fields.IntegerField')(default=0)), + ('cost', self.gf('django.db.models.fields.PositiveIntegerField')()), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('sponsorship', ['SponsorLevel']) + + # Adding model 'Sponsor' + db.create_table('sponsorship_sponsor', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('applicant', self.gf('django.db.models.fields.related.ForeignKey')(related_name='sponsorships', null=True, to=orm['auth.User'])), + ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('external_url', self.gf('django.db.models.fields.URLField')(max_length=200)), + ('annotation', self.gf('django.db.models.fields.TextField')(blank=True)), + ('contact_name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('contact_email', self.gf('django.db.models.fields.EmailField')(max_length=75)), + ('level', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['sponsorship.SponsorLevel'])), + ('added', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('active', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('sponsor_logo', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='+', null=True, to=orm['sponsorship.SponsorBenefit'])), + )) + db.send_create_signal('sponsorship', ['Sponsor']) + + # Adding model 'Benefit' + db.create_table('sponsorship_benefit', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + ('type', self.gf('django.db.models.fields.CharField')(default='simple', max_length=10)), + )) + db.send_create_signal('sponsorship', ['Benefit']) + + # Adding model 'BenefitLevel' + db.create_table('sponsorship_benefitlevel', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('benefit', self.gf('django.db.models.fields.related.ForeignKey')(related_name='benefit_levels', to=orm['sponsorship.Benefit'])), + ('level', self.gf('django.db.models.fields.related.ForeignKey')(related_name='benefit_levels', to=orm['sponsorship.SponsorLevel'])), + ('max_words', self.gf('django.db.models.fields.PositiveIntegerField')(null=True, blank=True)), + ('other_limits', self.gf('django.db.models.fields.CharField')(max_length=200, blank=True)), + )) + db.send_create_signal('sponsorship', ['BenefitLevel']) + + # Adding model 'SponsorBenefit' + db.create_table('sponsorship_sponsorbenefit', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('sponsor', self.gf('django.db.models.fields.related.ForeignKey')(related_name='sponsor_benefits', to=orm['sponsorship.Sponsor'])), + ('benefit', self.gf('django.db.models.fields.related.ForeignKey')(related_name='sponsor_benefits', to=orm['sponsorship.Benefit'])), + ('active', self.gf('django.db.models.fields.BooleanField')(default=True)), + ('max_words', self.gf('django.db.models.fields.PositiveIntegerField')(null=True, blank=True)), + ('other_limits', self.gf('django.db.models.fields.CharField')(max_length=200, blank=True)), + ('text', self.gf('django.db.models.fields.TextField')(blank=True)), + ('upload', self.gf('django.db.models.fields.files.FileField')(max_length=100, blank=True)), + )) + db.send_create_signal('sponsorship', ['SponsorBenefit']) + + + def backwards(self, orm): + # Deleting model 'SponsorLevel' + db.delete_table('sponsorship_sponsorlevel') + + # Deleting model 'Sponsor' + db.delete_table('sponsorship_sponsor') + + # Deleting model 'Benefit' + db.delete_table('sponsorship_benefit') + + # Deleting model 'BenefitLevel' + db.delete_table('sponsorship_benefitlevel') + + # Deleting model 'SponsorBenefit' + db.delete_table('sponsorship_sponsorbenefit') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'conference.conference': { + 'Meta': {'object_name': 'Conference'}, + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'timezone': ('timezones.fields.TimeZoneField', [], {'default': "'US/Eastern'", 'max_length': '100', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'sponsorship.benefit': { + 'Meta': {'object_name': 'Benefit'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'type': ('django.db.models.fields.CharField', [], {'default': "'simple'", 'max_length': '10'}) + }, + 'sponsorship.benefitlevel': { + 'Meta': {'ordering': "['level']", 'object_name': 'BenefitLevel'}, + 'benefit': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'benefit_levels'", 'to': "orm['sponsorship.Benefit']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'benefit_levels'", 'to': "orm['sponsorship.SponsorLevel']"}), + 'max_words': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'other_limits': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}) + }, + 'sponsorship.sponsor': { + 'Meta': {'object_name': 'Sponsor'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'added': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'annotation': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'applicant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sponsorships'", 'null': 'True', 'to': "orm['auth.User']"}), + 'contact_email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}), + 'contact_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sponsorship.SponsorLevel']"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'sponsor_logo': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['sponsorship.SponsorBenefit']"}) + }, + 'sponsorship.sponsorbenefit': { + 'Meta': {'ordering': "['-active']", 'object_name': 'SponsorBenefit'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'benefit': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sponsor_benefits'", 'to': "orm['sponsorship.Benefit']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'max_words': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'other_limits': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), + 'sponsor': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sponsor_benefits'", 'to': "orm['sponsorship.Sponsor']"}), + 'text': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'upload': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}) + }, + 'sponsorship.sponsorlevel': { + 'Meta': {'ordering': "['conference', 'order']", 'object_name': 'SponsorLevel'}, + 'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Conference']"}), + 'cost': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}) + } + } + + complete_apps = ['sponsorship'] \ No newline at end of file diff --git a/symposion/sponsorship/migrations/__init__.py b/symposion/sponsorship/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/teams/migrations/0001_initial.py b/symposion/teams/migrations/0001_initial.py new file mode 100644 index 00000000..d1ab1600 --- /dev/null +++ b/symposion/teams/migrations/0001_initial.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Team' + db.create_table('teams_team', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=50)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + ('access', self.gf('django.db.models.fields.CharField')(max_length=20)), + ('created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + )) + db.send_create_signal('teams', ['Team']) + + # Adding M2M table for field permissions on 'Team' + m2m_table_name = db.shorten_name('teams_team_permissions') + db.create_table(m2m_table_name, ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('team', models.ForeignKey(orm['teams.team'], null=False)), + ('permission', models.ForeignKey(orm['auth.permission'], null=False)) + )) + db.create_unique(m2m_table_name, ['team_id', 'permission_id']) + + # Adding M2M table for field manager_permissions on 'Team' + m2m_table_name = db.shorten_name('teams_team_manager_permissions') + db.create_table(m2m_table_name, ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('team', models.ForeignKey(orm['teams.team'], null=False)), + ('permission', models.ForeignKey(orm['auth.permission'], null=False)) + )) + db.create_unique(m2m_table_name, ['team_id', 'permission_id']) + + # Adding model 'Membership' + db.create_table('teams_membership', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='memberships', to=orm['auth.User'])), + ('team', self.gf('django.db.models.fields.related.ForeignKey')(related_name='memberships', to=orm['teams.Team'])), + ('state', self.gf('django.db.models.fields.CharField')(max_length=20)), + ('message', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('teams', ['Membership']) + + + def backwards(self, orm): + # Deleting model 'Team' + db.delete_table('teams_team') + + # Removing M2M table for field permissions on 'Team' + db.delete_table(db.shorten_name('teams_team_permissions')) + + # Removing M2M table for field manager_permissions on 'Team' + db.delete_table(db.shorten_name('teams_team_manager_permissions')) + + # Deleting model 'Membership' + db.delete_table('teams_membership') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'teams.membership': { + 'Meta': {'object_name': 'Membership'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'message': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'state': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'team': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'memberships'", 'to': "orm['teams.Team']"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'memberships'", 'to': "orm['auth.User']"}) + }, + 'teams.team': { + 'Meta': {'object_name': 'Team'}, + 'access': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'manager_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'manager_teams'", 'blank': 'True', 'to': "orm['auth.Permission']"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'member_teams'", 'blank': 'True', 'to': "orm['auth.Permission']"}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}) + } + } + + complete_apps = ['teams'] \ No newline at end of file diff --git a/symposion/teams/migrations/__init__.py b/symposion/teams/migrations/__init__.py new file mode 100644 index 00000000..e69de29b From 8e75bb77fb0d8d2f290dd699572fab5977a6559c Mon Sep 17 00:00:00 2001 From: David Ray Date: Tue, 14 Jan 2014 10:37:05 -0500 Subject: [PATCH 04/46] Remove project specific models --- .../proposals/migrations/0001_initial.py | 50 +------------------ 1 file changed, 1 insertion(+), 49 deletions(-) diff --git a/symposion/proposals/migrations/0001_initial.py b/symposion/proposals/migrations/0001_initial.py index c1fb4940..15878d53 100644 --- a/symposion/proposals/migrations/0001_initial.py +++ b/symposion/proposals/migrations/0001_initial.py @@ -67,28 +67,6 @@ class Migration(SchemaMigration): )) db.send_create_signal('proposals', ['SupportingDocument']) - # Adding model 'TalkProposal' - db.create_table('proposals_talkproposal', ( - ('proposalbase_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['proposals.ProposalBase'], unique=True, primary_key=True)), - ('audience_level', self.gf('django.db.models.fields.IntegerField')()), - ('recording_release', self.gf('django.db.models.fields.BooleanField')(default=True)), - )) - db.send_create_signal('proposals', ['TalkProposal']) - - # Adding model 'TutorialProposal' - db.create_table('proposals_tutorialproposal', ( - ('proposalbase_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['proposals.ProposalBase'], unique=True, primary_key=True)), - ('audience_level', self.gf('django.db.models.fields.IntegerField')()), - ('recording_release', self.gf('django.db.models.fields.BooleanField')(default=True)), - )) - db.send_create_signal('proposals', ['TutorialProposal']) - - # Adding model 'OpenSpaceProposal' - db.create_table('proposals_openspaceproposal', ( - ('proposalbase_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['proposals.ProposalBase'], unique=True, primary_key=True)), - )) - db.send_create_signal('proposals', ['OpenSpaceProposal']) - def backwards(self, orm): # Removing unique constraint on 'AdditionalSpeaker', fields ['speaker', 'proposalbase'] @@ -109,16 +87,6 @@ class Migration(SchemaMigration): # Deleting model 'SupportingDocument' db.delete_table('proposals_supportingdocument') - # Deleting model 'TalkProposal' - db.delete_table('proposals_talkproposal') - - # Deleting model 'TutorialProposal' - db.delete_table('proposals_tutorialproposal') - - # Deleting model 'OpenSpaceProposal' - db.delete_table('proposals_openspaceproposal') - - models = { 'auth.group': { 'Meta': {'object_name': 'Group'}, @@ -180,10 +148,6 @@ class Migration(SchemaMigration): 'speaker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['speakers.Speaker']"}), 'status': ('django.db.models.fields.IntegerField', [], {'default': '1'}) }, - 'proposals.openspaceproposal': { - 'Meta': {'object_name': 'OpenSpaceProposal', '_ormbases': ['proposals.ProposalBase']}, - 'proposalbase_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['proposals.ProposalBase']", 'unique': 'True', 'primary_key': 'True'}) - }, 'proposals.proposalbase': { 'Meta': {'object_name': 'ProposalBase'}, '_abstract_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), @@ -224,18 +188,6 @@ class Migration(SchemaMigration): 'proposal': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'supporting_documents'", 'to': "orm['proposals.ProposalBase']"}), 'uploaded_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) }, - 'proposals.talkproposal': { - 'Meta': {'object_name': 'TalkProposal'}, - 'audience_level': ('django.db.models.fields.IntegerField', [], {}), - 'proposalbase_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['proposals.ProposalBase']", 'unique': 'True', 'primary_key': 'True'}), - 'recording_release': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) - }, - 'proposals.tutorialproposal': { - 'Meta': {'object_name': 'TutorialProposal'}, - 'audience_level': ('django.db.models.fields.IntegerField', [], {}), - 'proposalbase_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['proposals.ProposalBase']", 'unique': 'True', 'primary_key': 'True'}), - 'recording_release': ('django.db.models.fields.BooleanField', [], {'default': 'True'}) - }, 'speakers.speaker': { 'Meta': {'ordering': "['name']", 'object_name': 'Speaker'}, '_biography_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), @@ -251,4 +203,4 @@ class Migration(SchemaMigration): } } - complete_apps = ['proposals'] \ No newline at end of file + complete_apps = ['proposals'] From cca9ad0793fa7ba5c6bacb364f7cc22efbb02525 Mon Sep 17 00:00:00 2001 From: David Ray Date: Tue, 14 Jan 2014 11:06:41 -0500 Subject: [PATCH 05/46] add dependencies for proper migration order --- symposion/proposals/migrations/0001_initial.py | 4 ++++ symposion/sponsorship/migrations/0001_initial.py | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/symposion/proposals/migrations/0001_initial.py b/symposion/proposals/migrations/0001_initial.py index 15878d53..dc013cbd 100644 --- a/symposion/proposals/migrations/0001_initial.py +++ b/symposion/proposals/migrations/0001_initial.py @@ -7,6 +7,10 @@ from django.db import models class Migration(SchemaMigration): + depends_on = ( + ("speakers", "0001_initial"), + ) + def forwards(self, orm): # Adding model 'ProposalSection' db.create_table('proposals_proposalsection', ( diff --git a/symposion/sponsorship/migrations/0001_initial.py b/symposion/sponsorship/migrations/0001_initial.py index 4bf423d9..356b8a8d 100644 --- a/symposion/sponsorship/migrations/0001_initial.py +++ b/symposion/sponsorship/migrations/0001_initial.py @@ -7,6 +7,10 @@ from django.db import models class Migration(SchemaMigration): + depends_on = ( + ("conference", "0001_initial"), + ) + def forwards(self, orm): # Adding model 'SponsorLevel' db.create_table('sponsorship_sponsorlevel', ( @@ -181,4 +185,4 @@ class Migration(SchemaMigration): } } - complete_apps = ['sponsorship'] \ No newline at end of file + complete_apps = ['sponsorship'] From 84bd8f8971d3712c5052e8b738042258dd377d27 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Mon, 13 Jan 2014 16:39:20 -0500 Subject: [PATCH 06/46] Update urls import format --- symposion/boxes/urls.py | 4 ++-- symposion/cms/urls.py | 4 +++- symposion/conference/urls.py | 2 +- symposion/proposals/urls.py | 2 +- symposion/reviews/urls.py | 6 +++--- symposion/schedule/urls.py | 2 +- symposion/speakers/urls.py | 2 +- symposion/sponsorship/urls.py | 2 +- symposion/teams/urls.py | 2 +- 9 files changed, 14 insertions(+), 12 deletions(-) diff --git a/symposion/boxes/urls.py b/symposion/boxes/urls.py index dc57fe6b..a3be13dc 100644 --- a/symposion/boxes/urls.py +++ b/symposion/boxes/urls.py @@ -1,6 +1,6 @@ -from django.conf.urls.defaults import url, patterns +from django.conf.urls import patterns, url urlpatterns = patterns("symposion.boxes.views", url(r"^([-\w]+)/edit/$", "box_edit", name="box_edit"), -) \ No newline at end of file +) diff --git a/symposion/cms/urls.py b/symposion/cms/urls.py index 3297ce53..1271f06e 100644 --- a/symposion/cms/urls.py +++ b/symposion/cms/urls.py @@ -1,7 +1,9 @@ -from django.conf.urls.defaults import url, patterns +from django.conf.urls import url, patterns + PAGE_RE = r"(([\w-]{1,})(/[\w-]{1,})*)/" + urlpatterns = patterns("symposion.cms.views", url(r"^files/$", "file_index", name="file_index"), url(r"^files/create/$", "file_create", name="file_create"), diff --git a/symposion/conference/urls.py b/symposion/conference/urls.py index a25aa583..90ae79f8 100644 --- a/symposion/conference/urls.py +++ b/symposion/conference/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns, url +from django.conf.urls import patterns, url urlpatterns = patterns("symposion.conference.views", diff --git a/symposion/proposals/urls.py b/symposion/proposals/urls.py index 443540bb..a69e6136 100644 --- a/symposion/proposals/urls.py +++ b/symposion/proposals/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns, url +from django.conf.urls import patterns, url urlpatterns = patterns("symposion.proposals.views", diff --git a/symposion/reviews/urls.py b/symposion/reviews/urls.py index 564bd35e..1719eb0e 100644 --- a/symposion/reviews/urls.py +++ b/symposion/reviews/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns, url +from django.conf.urls import patterns, url urlpatterns = patterns("symposion.reviews.views", @@ -14,9 +14,9 @@ urlpatterns = patterns("symposion.reviews.views", url(r"^section/(?P[\w\-]+)/notification/(?P\w+)/$", "result_notification", name="result_notification"), url(r"^section/(?P[\w\-]+)/notification/(?P\w+)/prepare/$", "result_notification_prepare", name="result_notification_prepare"), url(r"^section/(?P[\w\-]+)/notification/(?P\w+)/send/$", "result_notification_send", name="result_notification_send"), - + url(r"^review/(?P\d+)/$", "review_detail", name="review_detail"), - + url(r"^(?P\d+)/delete/$", "review_delete", name="review_delete"), url(r"^assignments/$", "review_assignments", name="review_assignments"), url(r"^assignment/(?P\d+)/opt-out/$", "review_assignment_opt_out", name="review_assignment_opt_out"), diff --git a/symposion/schedule/urls.py b/symposion/schedule/urls.py index 58890827..049aa7da 100644 --- a/symposion/schedule/urls.py +++ b/symposion/schedule/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import url, patterns +from django.conf.urls import url, patterns urlpatterns = patterns("symposion.schedule.views", diff --git a/symposion/speakers/urls.py b/symposion/speakers/urls.py index 9a00ea3c..fb30e787 100644 --- a/symposion/speakers/urls.py +++ b/symposion/speakers/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns, url +from django.conf.urls import patterns, url urlpatterns = patterns("symposion.speakers.views", diff --git a/symposion/sponsorship/urls.py b/symposion/sponsorship/urls.py index e5d32bb0..f7b946c6 100644 --- a/symposion/sponsorship/urls.py +++ b/symposion/sponsorship/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns, url +from django.conf.urls import patterns, url from django.views.generic.simple import direct_to_template diff --git a/symposion/teams/urls.py b/symposion/teams/urls.py index ed2f7645..785c4300 100644 --- a/symposion/teams/urls.py +++ b/symposion/teams/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns, url +from django.conf.urls import patterns, url urlpatterns = patterns("symposion.teams.views", From b495eddc61bad6ad27cdab58e8729ceca1634fa4 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Mon, 13 Jan 2014 16:40:27 -0500 Subject: [PATCH 07/46] direct_to_template -> TemplateView --- symposion/sponsorship/urls.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/symposion/sponsorship/urls.py b/symposion/sponsorship/urls.py index f7b946c6..c7dc581c 100644 --- a/symposion/sponsorship/urls.py +++ b/symposion/sponsorship/urls.py @@ -1,9 +1,9 @@ from django.conf.urls import patterns, url -from django.views.generic.simple import direct_to_template +from django.views.generic import TemplateView urlpatterns = patterns("symposion.sponsorship.views", - url(r"^$", direct_to_template, {"template": "sponsorship/list.html"}, name="sponsor_list"), + url(r"^$", TemplateView.as_view(template_name="sponsorship/list.html"), name="sponsor_list"), url(r"^apply/$", "sponsor_apply", name="sponsor_apply"), url(r"^add/$", "sponsor_add", name="sponsor_add"), url(r"^(?P\d+)/$", "sponsor_detail", name="sponsor_detail"), From 8857e7b7608c7fd3038126f7449c187b514fed34 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Wed, 15 Jan 2014 08:55:58 -0500 Subject: [PATCH 08/46] Use {% load url from future %} in cms templates Using https://github.com/django-future-url --- symposion/templates/cms/file_create.html | 5 ++++- symposion/templates/cms/file_index.html | 7 +++++-- symposion/templates/cms/page_detail.html | 5 ++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/symposion/templates/cms/file_create.html b/symposion/templates/cms/file_create.html index 547fc5d3..210a9e1d 100644 --- a/symposion/templates/cms/file_create.html +++ b/symposion/templates/cms/file_create.html @@ -1,5 +1,8 @@ {% extends "site_base.html" %} +{% load url from future %} + + {% load bootstrap_tags %} {% block head_title %}Upload File{% endblock %} @@ -8,7 +11,7 @@

Upload File

-
+ {% csrf_token %} {{ form|as_bootstrap }}
diff --git a/symposion/templates/cms/file_index.html b/symposion/templates/cms/file_index.html index bfe1337c..76e02354 100644 --- a/symposion/templates/cms/file_index.html +++ b/symposion/templates/cms/file_index.html @@ -1,5 +1,8 @@ {% extends "site_base.html" %} +{% load url from future %} + + {% block head_title %}Uploaded Files{% endblock %} {% block body_outer %} @@ -9,7 +12,7 @@ {% for file in files %}
- + {% csrf_token %} @@ -20,7 +23,7 @@

No uploaded files.

{% endfor %}
- + Add File diff --git a/symposion/templates/cms/page_detail.html b/symposion/templates/cms/page_detail.html index 770eae29..6f35395b 100644 --- a/symposion/templates/cms/page_detail.html +++ b/symposion/templates/cms/page_detail.html @@ -1,5 +1,8 @@ {% extends "site_base.html" %} +{% load url from future %} + + {% load sitetree %} {% load i18n %} @@ -12,7 +15,7 @@ {% block body %} {% if editable %} {% endif %}

{{ page.title }}

From 55d37c13bdf48e91c0bbcbdab93ad3394f75360a Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Wed, 15 Jan 2014 08:56:30 -0500 Subject: [PATCH 09/46] Use {% load url from future %} in conference templates Using https://github.com/futurecolors/django-future-url --- symposion/templates/conference/user_list.html | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/symposion/templates/conference/user_list.html b/symposion/templates/conference/user_list.html index 22caaede..04b6a5ca 100644 --- a/symposion/templates/conference/user_list.html +++ b/symposion/templates/conference/user_list.html @@ -1,5 +1,8 @@ {% extends "site_base.html" %} +{% load url from future %} + + {% load i18n %} {% load sitetree %} @@ -68,9 +71,9 @@ {{ user.get_full_name }} {% if user.speaker_profile %} - {{ user.speaker_profile }} + {{ user.speaker_profile }} {% else %} - create + create {% endif %} From 935ec48032d1e2228ce647f151255ce2db3ac34f Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Wed, 15 Jan 2014 08:57:03 -0500 Subject: [PATCH 10/46] Use {% load url from future %} in emails templates Using https://github.com/futurecolors/django-future-url --- symposion/templates/emails/proposal_new_message/message.html | 3 ++- symposion/templates/emails/proposal_updated/message.html | 3 ++- symposion/templates/emails/speaker_addition/message.html | 3 ++- symposion/templates/emails/speaker_invite/message.html | 3 ++- symposion/templates/emails/speaker_no_profile/message.html | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/symposion/templates/emails/proposal_new_message/message.html b/symposion/templates/emails/proposal_new_message/message.html index 90bbd8c8..3a9addf5 100644 --- a/symposion/templates/emails/proposal_new_message/message.html +++ b/symposion/templates/emails/proposal_new_message/message.html @@ -1,3 +1,4 @@ +{% load url from future %} {% load account_tags %}

{% user_display message.user %} has added a message on {{ proposal.title }}. @@ -6,6 +7,6 @@ {{ message.message|safe }}

- {% if reviewer %}{% url review_detail proposal.pk as detail_url %}{% else %}{% url proposal_detail proposal.pk as detail_url %}{% endif %} + {% if reviewer %}{% url 'review_detail' proposal.pk as detail_url %}{% else %}{% url 'proposal_detail' proposal.pk as detail_url %}{% endif %} Respond online at http://{{ current_site }}{{ detail_url }}#proposal-feedback

\ No newline at end of file diff --git a/symposion/templates/emails/proposal_updated/message.html b/symposion/templates/emails/proposal_updated/message.html index d5ed74ec..eef8af8d 100644 --- a/symposion/templates/emails/proposal_updated/message.html +++ b/symposion/templates/emails/proposal_updated/message.html @@ -1,8 +1,9 @@ +{% load url from future %} {% load account_tags %}

{% user_display user %} has made changes to {{ proposal.title }} which you have previously reviewed or commented on.

- {% url review_detail proposal.pk as detail_url %} + {% url 'review_detail' proposal.pk as detail_url %} View the latest version of the proposal online at http://{{ current_site }}{{ detail_url }}

diff --git a/symposion/templates/emails/speaker_addition/message.html b/symposion/templates/emails/speaker_addition/message.html index dff0c7ba..dec1ac76 100644 --- a/symposion/templates/emails/speaker_addition/message.html +++ b/symposion/templates/emails/speaker_addition/message.html @@ -1,6 +1,7 @@ +{% load url from future %}

{{ proposal.speaker.name }} attached you as an additional speaker to a talk proposal for {{ current_site.name }} entitled "{{ proposal.title }}".

For more details, visit the {{ current_site.name }} speaker dashboard: - http://{{ current_site }}{% url dashboard %} + http://{{ current_site }}{% url 'dashboard' %}

diff --git a/symposion/templates/emails/speaker_invite/message.html b/symposion/templates/emails/speaker_invite/message.html index 5ab2c2e8..5e32bd4a 100644 --- a/symposion/templates/emails/speaker_invite/message.html +++ b/symposion/templates/emails/speaker_invite/message.html @@ -1,9 +1,10 @@ +{% load url from future %}

{{ proposal.speaker.name }} attached you as an additional speaker to a talk proposal for {{ current_site.name }} entitled "{{ proposal.title }}".

Go to

-

http://{{ current_site }}{% url speaker_create_token token %}

+

http://{{ current_site }}{% url 'speaker_create_token' token %}

to confirm.

diff --git a/symposion/templates/emails/speaker_no_profile/message.html b/symposion/templates/emails/speaker_no_profile/message.html index 14007092..d77693c1 100644 --- a/symposion/templates/emails/speaker_no_profile/message.html +++ b/symposion/templates/emails/speaker_no_profile/message.html @@ -1,8 +1,9 @@ +{% load url from future %}

{{ proposal.speaker.name }} attached you as an additional speaker to a talk proposal for {{ current_site.name }} entitled "{{ proposal.title }}".

Go to

-

http://{{ current_site }}{% url speaker_create_token token %}

+

http://{{ current_site }}{% url 'speaker_create_token' token %}

to confirm and fill out your speaker profile.

From ed7278e9260ad986d1d30a625025213351081e4d Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Wed, 15 Jan 2014 08:57:33 -0500 Subject: [PATCH 11/46] Use {% load url from future %} in proposals templates Using https://github.com/futurecolors/django-future-url --- .../templates/proposals/_pending_proposal_row.html | 7 ++++--- symposion/templates/proposals/_proposal_fields.html | 3 ++- symposion/templates/proposals/_proposal_row.html | 7 ++++--- symposion/templates/proposals/proposal_cancel.html | 5 ++++- symposion/templates/proposals/proposal_detail.html | 13 ++++++++----- symposion/templates/proposals/proposal_edit.html | 7 +++++-- .../proposals/proposal_speaker_manage.html | 5 ++++- symposion/templates/proposals/proposal_submit.html | 5 ++++- 8 files changed, 35 insertions(+), 17 deletions(-) diff --git a/symposion/templates/proposals/_pending_proposal_row.html b/symposion/templates/proposals/_pending_proposal_row.html index fafd0ea0..ed147b0c 100644 --- a/symposion/templates/proposals/_pending_proposal_row.html +++ b/symposion/templates/proposals/_pending_proposal_row.html @@ -1,8 +1,9 @@ +{% load url from future %} {% load i18n %} - {{ proposal.title }} + {{ proposal.title }} {{ proposal.kind.name }} @@ -31,9 +32,9 @@
diff --git a/symposion/templates/proposals/_proposal_fields.html b/symposion/templates/proposals/_proposal_fields.html index a1040625..d75bdf3f 100644 --- a/symposion/templates/proposals/_proposal_fields.html +++ b/symposion/templates/proposals/_proposal_fields.html @@ -1,3 +1,4 @@ +{% load url from future %} {% load i18n %}
@@ -45,7 +46,7 @@ {{ document.description }} -
+ {% csrf_token %}
diff --git a/symposion/templates/proposals/_proposal_row.html b/symposion/templates/proposals/_proposal_row.html index 6ed15607..8dcb6261 100644 --- a/symposion/templates/proposals/_proposal_row.html +++ b/symposion/templates/proposals/_proposal_row.html @@ -1,6 +1,7 @@ +{% load url from future %} - {{ proposal.title }} + {{ proposal.title }} {{ proposal.kind.name }} @@ -24,8 +25,8 @@ {% if not proposal.cancelled %} {% if request.user == proposal.speaker.user and proposal.can_edit %} - Edit - Manage Additional Speakers + Edit + Manage Additional Speakers {% endif %} {% endif %} diff --git a/symposion/templates/proposals/proposal_cancel.html b/symposion/templates/proposals/proposal_cancel.html index 93a1204a..03bbd40d 100644 --- a/symposion/templates/proposals/proposal_cancel.html +++ b/symposion/templates/proposals/proposal_cancel.html @@ -1,5 +1,8 @@ {% extends "proposals/base.html" %} +{% load url from future %} + + {% load i18n %} {% load bootstrap_tags %} @@ -13,6 +16,6 @@ {% csrf_token %}

Are you sure you want to cancel {{ proposal.title }}?

- {% trans 'No, keep it for now' %} + {% trans 'No, keep it for now' %} {% endblock %} diff --git a/symposion/templates/proposals/proposal_detail.html b/symposion/templates/proposals/proposal_detail.html index a9b881e7..240e1c02 100644 --- a/symposion/templates/proposals/proposal_detail.html +++ b/symposion/templates/proposals/proposal_detail.html @@ -1,5 +1,8 @@ {% extends "proposals/base.html" %} +{% load url from future %} + + {% load i18n %} {% load account_tags %} {% load bootstrap_tags %} @@ -10,14 +13,14 @@
{% if not proposal.cancelled %} {% if request.user == proposal.speaker.user %} - + {% trans "Edit this proposal" %} - + {% trans "Cancel this proposal" %} {% else %} - + {% trans "Remove me from this proposal" %} {% endif %} @@ -52,7 +55,7 @@ {{ document.description }} -
+ {% csrf_token %}
@@ -63,7 +66,7 @@ {% else %}

{% trans 'No supporting documents attached to this proposal.' %}

{% endif %} - {% trans 'Add Document' %} + {% trans 'Add Document' %}
{% endif %} diff --git a/symposion/templates/proposals/proposal_edit.html b/symposion/templates/proposals/proposal_edit.html index 67c847a2..d968a7a3 100644 --- a/symposion/templates/proposals/proposal_edit.html +++ b/symposion/templates/proposals/proposal_edit.html @@ -1,5 +1,8 @@ {% extends "proposals/base.html" %} +{% load url from future %} + + {% load bootstrap_tags %} {% load markitup_tags %} @@ -8,7 +11,7 @@ {% block body %}

Edit: {{ proposal.title }}

-

Manage speakers

+

Manage speakers

{% csrf_token %} @@ -17,7 +20,7 @@
{% endblock %} diff --git a/symposion/templates/proposals/proposal_speaker_manage.html b/symposion/templates/proposals/proposal_speaker_manage.html index b1e9990d..2faa7085 100644 --- a/symposion/templates/proposals/proposal_speaker_manage.html +++ b/symposion/templates/proposals/proposal_speaker_manage.html @@ -1,4 +1,7 @@ {% extends "proposals/base.html" %} + +{% load url from future %} + {% load i18n %} {% load bootstrap_tags %} @@ -7,7 +10,7 @@

{% trans 'Proposal:' %} {{ proposal.title }}

- {% trans 'Edit proposal' %} + {% trans 'Edit proposal' %}

diff --git a/symposion/templates/proposals/proposal_submit.html b/symposion/templates/proposals/proposal_submit.html index 0a1b34e5..23175054 100644 --- a/symposion/templates/proposals/proposal_submit.html +++ b/symposion/templates/proposals/proposal_submit.html @@ -1,5 +1,8 @@ {% extends "proposals/base.html" %} +{% load url from future %} + + {% load boxes_tags %} {% load i18n %} @@ -13,7 +16,7 @@ {% else %} From 4c912da4aca6c953ac35a3cb5b40aeff0588ba77 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Wed, 15 Jan 2014 08:57:57 -0500 Subject: [PATCH 12/46] Use {% load url from future %} in reviews templates Using https://github.com/futurecolors/django-future-url --- .../templates/reviews/_review_table.html | 3 ++- symposion/templates/reviews/base.html | 11 +++++---- .../reviews/result_notification.html | 13 +++++++---- .../reviews/result_notification_prepare.html | 7 ++++-- symposion/templates/reviews/review_admin.html | 5 +++- .../templates/reviews/review_assignment.html | 7 ++++-- .../templates/reviews/review_detail.html | 5 +++- .../templates/reviews/review_review.html | 7 ++++-- symposion/templates/reviews/review_stats.html | 23 +++++++++++-------- 9 files changed, 53 insertions(+), 28 deletions(-) diff --git a/symposion/templates/reviews/_review_table.html b/symposion/templates/reviews/_review_table.html index 9c1804b7..9e94cf83 100644 --- a/symposion/templates/reviews/_review_table.html +++ b/symposion/templates/reviews/_review_table.html @@ -1,3 +1,4 @@ +{% load url from future %} {% load i18n %} @@ -18,7 +19,7 @@
{{ proposal.number }} - + {{ proposal.speaker }}
{{ proposal.title }} diff --git a/symposion/templates/reviews/base.html b/symposion/templates/reviews/base.html index 695d9c8c..a09bde0e 100644 --- a/symposion/templates/reviews/base.html +++ b/symposion/templates/reviews/base.html @@ -1,5 +1,8 @@ {% extends "site_base.html" %} +{% load url from future %} + + {% load i18n %} {% load sitetree %} @@ -60,25 +63,25 @@ {{ section }}
  • - + {% trans "All Reviews" %}
  • {% comment %}
  • - + {% trans "Your Assignments" %}
  • {% endcomment %}
  • - + {% trans "Voting Status" %}
  • {% if request.user.is_staff %}
  • - Result Notification + Result Notification
  • {% endif %} {% endfor %} diff --git a/symposion/templates/reviews/result_notification.html b/symposion/templates/reviews/result_notification.html index cbd5c4c2..af250baa 100644 --- a/symposion/templates/reviews/result_notification.html +++ b/symposion/templates/reviews/result_notification.html @@ -1,5 +1,8 @@ {% extends "reviews/base.html" %} +{% load url from future %} + + {% load i18n %} {% block extra_style %} @@ -13,14 +16,14 @@ {% block body %}

    Result Notification

    -
    + {% csrf_token %} @@ -54,7 +57,7 @@
    {{ proposal.number }} - + {{ proposal.speaker }}
    {{ proposal.title }} diff --git a/symposion/templates/reviews/result_notification_prepare.html b/symposion/templates/reviews/result_notification_prepare.html index 2248c204..bfe2e433 100644 --- a/symposion/templates/reviews/result_notification_prepare.html +++ b/symposion/templates/reviews/result_notification_prepare.html @@ -1,5 +1,8 @@ {% extends "reviews/base.html" %} +{% load url from future %} + + {% load i18n %} {% block body %} @@ -23,7 +26,7 @@
    diff --git a/symposion/templates/reviews/review_admin.html b/symposion/templates/reviews/review_admin.html index 1e762416..24ac217f 100644 --- a/symposion/templates/reviews/review_admin.html +++ b/symposion/templates/reviews/review_admin.html @@ -1,5 +1,8 @@ {% extends "reviews/base.html" %} +{% load url from future %} + + {% block body %}

    Reviewers

    @@ -30,7 +33,7 @@ {% for reviewer in reviewers %}
    - {{ reviewer.get_full_name }} + {{ reviewer.get_full_name }} {{ reviewer.total_votes }} diff --git a/symposion/templates/reviews/review_assignment.html b/symposion/templates/reviews/review_assignment.html index 8bcc1fef..448b85c0 100644 --- a/symposion/templates/reviews/review_assignment.html +++ b/symposion/templates/reviews/review_assignment.html @@ -1,5 +1,8 @@ {% extends "reviews/base.html" %} +{% load url from future %} + + {% block body %}

    Review Assignments

    @@ -13,12 +16,12 @@ {% for assignment in assignments %}
    - + {{ assignment.proposal.title }} -
    + {% csrf_token %}
    diff --git a/symposion/templates/reviews/review_detail.html b/symposion/templates/reviews/review_detail.html index 9a2de066..98b4043a 100644 --- a/symposion/templates/reviews/review_detail.html +++ b/symposion/templates/reviews/review_detail.html @@ -1,5 +1,8 @@ {% extends "reviews/base.html" %} +{% load url from future %} + + {% load i18n %} {% load markitup_tags %} {% load bootstrap_tags %} @@ -126,7 +129,7 @@ {% if is_manager %}
    -
    + {% csrf_token %}
    diff --git a/symposion/templates/reviews/review_review.html b/symposion/templates/reviews/review_review.html index 2168e899..7f753ddc 100644 --- a/symposion/templates/reviews/review_review.html +++ b/symposion/templates/reviews/review_review.html @@ -1,5 +1,8 @@ {% extends "site_base.html" %} +{% load url from future %} + + {% load markitup_tags %} {% load uni_form_tags %} @@ -55,7 +58,7 @@

    Review

    -
    + {% csrf_token %}
    {{ review_form|as_uni_form }} @@ -67,7 +70,7 @@

    Comment

    - + {% csrf_token %}
    {{ comment_form|as_uni_form }} diff --git a/symposion/templates/reviews/review_stats.html b/symposion/templates/reviews/review_stats.html index 8f4a09cb..40936af5 100644 --- a/symposion/templates/reviews/review_stats.html +++ b/symposion/templates/reviews/review_stats.html @@ -1,15 +1,18 @@ {% extends "reviews/base.html" %} +{% load url from future %} + + {% block body %}

    Voting Status ({{ section_slug }})

    {% if key %}
    @@ -42,35 +45,35 @@
    - Positive + Positive {{ proposals.positive|length }}
    proposals with at least {{ vote_threshold }} vote{{ vote_threshold|pluralize }} and at least one +1 and no −1s
    - Negative + Negative {{ proposals.negative|length }}
    proposals with at least {{ vote_threshold }} vote{{ vote_threshold|pluralize }} and at least one −1 and no +1s
    - Indifferent + Indifferent {{ proposals.indifferent|length }}
    proposals with at least {{ vote_threshold }} vote{{ vote_threshold|pluralize }} and neither a +1 or a −1
    - Controversial + Controversial {{ proposals.controversial|length }}
    proposals with at least {{ vote_threshold }} vote{{ vote_threshold|pluralize }} and both a +1 and −1
    - Too Few Reviews + Too Few Reviews {{ proposals.too_few|length }}
    From 76a5e08e2fe5a5e4052b700efbf48f50ebc91150 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Wed, 15 Jan 2014 08:58:21 -0500 Subject: [PATCH 13/46] Use {% load url from future %} in schedule templates Using https://github.com/futurecolors/django-future-url --- symposion/templates/schedule/_edit_grid.html | 7 ++++--- symposion/templates/schedule/_grid.html | 3 ++- symposion/templates/schedule/_slot_edit.html | 3 ++- symposion/templates/schedule/presentation_detail.html | 5 ++++- symposion/templates/schedule/schedule_list.html | 5 ++++- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/symposion/templates/schedule/_edit_grid.html b/symposion/templates/schedule/_edit_grid.html index ff9afe78..870391b5 100644 --- a/symposion/templates/schedule/_edit_grid.html +++ b/symposion/templates/schedule/_edit_grid.html @@ -1,3 +1,4 @@ +{% load url from future %} @@ -15,9 +16,9 @@ {% endfor %} diff --git a/symposion/templates/schedule/_grid.html b/symposion/templates/schedule/_grid.html index be62d912..71f98448 100644 --- a/symposion/templates/schedule/_grid.html +++ b/symposion/templates/schedule/_grid.html @@ -1,3 +1,4 @@ +{% load url from future %}
    {% if slot.kind.label == "talk" or slot.kind.label == "tutorial" %} {% if not slot.content %} - + + + {% else %} - {{ slot.content.title }} + {{ slot.content.title }} {{ slot.content.speaker }} {% endif %} {% else %} @@ -26,7 +27,7 @@ {% else %} {{ slot.kind.label }} {% endif %} - — edit + — edit {% endif %}
    @@ -17,7 +18,7 @@ {% if not slot.content %} {% else %} - {{ slot.content.title }} + {{ slot.content.title }} {{ slot.content.speakers|join:", " }} diff --git a/symposion/templates/schedule/_slot_edit.html b/symposion/templates/schedule/_slot_edit.html index d8b5ae9e..385ff89f 100644 --- a/symposion/templates/schedule/_slot_edit.html +++ b/symposion/templates/schedule/_slot_edit.html @@ -1,5 +1,6 @@ +{% load url from future %} {% load i18n bootstrap_tags %} - + {% endfor %} @@ -57,7 +60,7 @@ {% endfor %} @@ -70,8 +73,8 @@ {% endfor %} From 280a2c2d2098329ebabdf86c66351946134f31d1 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Wed, 15 Jan 2014 09:00:15 -0500 Subject: [PATCH 17/46] Use {% load url from future %} in dashboard template Using https://github.com/futurecolors/django-future-url --- symposion/templates/dashboard.html | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/symposion/templates/dashboard.html b/symposion/templates/dashboard.html index a88b4a3f..d47c2729 100644 --- a/symposion/templates/dashboard.html +++ b/symposion/templates/dashboard.html @@ -1,5 +1,8 @@ {% extends "site_base.html" %} +{% load url from future %} + + {% load i18n %} {% load proposal_tags %} {% load review_tags %} @@ -16,14 +19,14 @@

    {% trans "Speaking" %}

    {% if not user.speaker_profile %} - + Create a speaker profile {% else %} - + Edit your speaker profile - + Submit a new proposal {% endif %} @@ -32,7 +35,7 @@
    {% if not user.speaker_profile %} -

    To submit a proposal, you must first create a speaker profile.

    +

    To submit a proposal, you must first create a speaker profile.

    {% else %}

    Your Proposals

    {% if user.speaker_profile.proposals.exists %} @@ -92,7 +95,7 @@

    {% trans "Sponsorship" %}

    {% if not user.sponsorships.exists %} - + Apply to be a sponsor {% endif %} @@ -101,13 +104,13 @@
    {% if not user.sponsorships.exists %} -

    If you or your organization would be interested in sponsorship opportunities, use our online form to apply to be a sponsor. +

    If you or your organization would be interested in sponsorship opportunities, use our online form to apply to be a sponsor. {% else %}

    Your Sponsorship

    {{ membership.user.email }}{% if user == membership.user %} you{% endif %} -
    {% csrf_token %}
    +
    {% csrf_token %}
    {{ membership.user.email }}{% if user == membership.user %} you{% endif %} -
    {% csrf_token %}
    +
    {% csrf_token %}
    {{ membership.user.email }} -
    {% csrf_token %}
    -
    {% csrf_token %}
    +
    {% csrf_token %}
    +
    {% csrf_token %}
    - {{ membership.team.name }} + {{ membership.team.name }} {% if membership.team.description %}
    {{ membership.team.description }}{% endif %}
    @@ -204,7 +207,7 @@ {% for team in available_teams %}
    - {{ team }} + {{ team }} {% if team.description %}
    {{ team.description }}{% endif %}
    From e9c97a9586f2215bfe7a4714d5467e33201881bb Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Wed, 15 Jan 2014 09:05:08 -0500 Subject: [PATCH 18/46] mimetype -> content_type mimetype is deprecated and to be removed in Django 1.7. --- symposion/proposals/actions.py | 2 +- symposion/schedule/views.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/symposion/proposals/actions.py b/symposion/proposals/actions.py index e46e2524..c502c0fe 100644 --- a/symposion/proposals/actions.py +++ b/symposion/proposals/actions.py @@ -23,7 +23,7 @@ def export_as_csv_action( elif exclude: excludeset = set(exclude) field_names = field_names - excludeset - response = HttpResponse(mimetype="text/csv") + response = HttpResponse(content_type="text/csv") response["Content-Disposition"] = "attachment; filename=%s.csv" % unicode(opts).replace(".", "_") writer = csv.writer(response) if header: diff --git a/symposion/schedule/views.py b/symposion/schedule/views.py index 98771b59..1367808b 100644 --- a/symposion/schedule/views.py +++ b/symposion/schedule/views.py @@ -78,7 +78,7 @@ def schedule_list_csv(request, slug=None): presentations = Presentation.objects.filter(section=schedule.section) presentations = presentations.exclude(cancelled=True).order_by("id") - response = HttpResponse(mimetype="text/csv") + response = HttpResponse(content_type="text/csv") if slug: file_slug = slug else: From dff5c4b1bb043cf02e1f504eb1e8fba151a73733 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Wed, 15 Jan 2014 09:22:16 -0500 Subject: [PATCH 19/46] Use hashlib rather than django.utils.hashcompat --- symposion/proposals/views.py | 62 ++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/symposion/proposals/views.py b/symposion/proposals/views.py index cf532c2b..f8dde53c 100644 --- a/symposion/proposals/views.py +++ b/symposion/proposals/views.py @@ -1,3 +1,4 @@ +import hashlib import random import sys @@ -6,7 +7,6 @@ from django.core.exceptions import ObjectDoesNotExist from django.db.models import Q from django.http import Http404, HttpResponse, HttpResponseForbidden from django.shortcuts import render, redirect, get_object_or_404 -from django.utils.hashcompat import sha_constructor from django.views import static from django.contrib import messages @@ -37,21 +37,21 @@ def proposal_submit(request): request.user.speaker_profile except ObjectDoesNotExist: return redirect("dashboard") - + kinds = [] for proposal_section in ProposalSection.available(): for kind in proposal_section.section.proposal_kinds.all(): kinds.append(kind) - + return render(request, "proposals/proposal_submit.html", { "kinds": kinds, }) def proposal_submit_kind(request, kind_slug): - + kind = get_object_or_404(ProposalKind, slug=kind_slug) - + if not request.user.is_authenticated(): return redirect("home") # @@@ unauth'd speaker info page? else: @@ -59,12 +59,12 @@ def proposal_submit_kind(request, kind_slug): speaker_profile = request.user.speaker_profile except ObjectDoesNotExist: return redirect("dashboard") - + if not kind.section.proposalsection.is_available(): return redirect("proposal_submit") - + form_class = get_form(settings.PROPOSAL_FORMS[kind_slug]) - + if request.method == "POST": form = form_class(request.POST) if form.is_valid(): @@ -79,7 +79,7 @@ def proposal_submit_kind(request, kind_slug): return redirect("dashboard") else: form = form_class() - + return render(request, "proposals/proposal_submit_kind.html", { "kind": kind, "form": form, @@ -91,17 +91,17 @@ def proposal_speaker_manage(request, pk): queryset = ProposalBase.objects.select_related("speaker") proposal = get_object_or_404(queryset, pk=pk) proposal = ProposalBase.objects.get_subclass(pk=proposal.pk) - + if proposal.speaker != request.user.speaker_profile: raise Http404() - + if request.method == "POST": add_speaker_form = AddSpeakerForm(request.POST, proposal=proposal) if add_speaker_form.is_valid(): message_ctx = { "proposal": proposal, } - + def create_speaker_token(email_address): # create token and look for an existing speaker to prevent # duplicate tokens and confusing the pending speaker @@ -110,8 +110,8 @@ def proposal_speaker_manage(request, pk): Q(user=None, invite_email=email_address) ) except Speaker.DoesNotExist: - salt = sha_constructor(str(random.random())).hexdigest()[:5] - token = sha_constructor(salt + email_address).hexdigest() + salt = hashlib.sha1(str(random.random())).hexdigest()[:5] + token = hashlib.sha1(salt + email_address).hexdigest() pending = Speaker.objects.create( invite_email=email_address, invite_token=token, @@ -173,14 +173,14 @@ def proposal_edit(request, pk): if request.user != proposal.speaker.user: raise Http404() - + if not proposal.can_edit(): ctx = { "title": "Proposal editing closed", "body": "Proposal editing is closed for this session type." } return render(request, "proposals/proposal_error.html", ctx) - + form_class = get_form(settings.PROPOSAL_FORMS[proposal.kind.slug]) if request.method == "POST": @@ -206,7 +206,7 @@ def proposal_edit(request, pk): return redirect("proposal_detail", proposal.pk) else: form = form_class(instance=proposal) - + return render(request, "proposals/proposal_edit.html", { "proposal": proposal, "form": form, @@ -218,22 +218,22 @@ def proposal_detail(request, pk): queryset = ProposalBase.objects.select_related("speaker", "speaker__user") proposal = get_object_or_404(queryset, pk=pk) proposal = ProposalBase.objects.get_subclass(pk=proposal.pk) - + if request.user not in [p.user for p in proposal.speakers()]: raise Http404() - + if "symposion.reviews" in settings.INSTALLED_APPS: from symposion.reviews.forms import SpeakerCommentForm message_form = SpeakerCommentForm() if request.method == "POST": message_form = SpeakerCommentForm(request.POST) if message_form.is_valid(): - + message = message_form.save(commit=False) message.user = request.user message.proposal = proposal message.save() - + ProposalMessage = SpeakerCommentForm.Meta.model reviewers = User.objects.filter( id__in=ProposalMessage.objects.filter( @@ -242,7 +242,7 @@ def proposal_detail(request, pk): user=request.user ).distinct().values_list("user", flat=True) ) - + for reviewer in reviewers: ctx = { "proposal": proposal, @@ -253,13 +253,13 @@ def proposal_detail(request, pk): [reviewer.email], "proposal_new_message", context=ctx ) - + return redirect(request.path) else: message_form = SpeakerCommentForm() else: message_form = None - + return render(request, "proposals/proposal_detail.html", { "proposal": proposal, "message_form": message_form @@ -271,7 +271,7 @@ def proposal_cancel(request, pk): queryset = ProposalBase.objects.select_related("speaker") proposal = get_object_or_404(queryset, pk=pk) proposal = ProposalBase.objects.get_subclass(pk=proposal.pk) - + if proposal.speaker.user != request.user: return HttpResponseForbidden() @@ -281,7 +281,7 @@ def proposal_cancel(request, pk): # @@@ fire off email to submitter and other speakers messages.success(request, "%s has been cancelled" % proposal.title) return redirect("dashboard") - + return render(request, "proposals/proposal_cancel.html", { "proposal": proposal, }) @@ -339,10 +339,10 @@ def document_create(request, proposal_pk): queryset = ProposalBase.objects.select_related("speaker") proposal = get_object_or_404(queryset, pk=proposal_pk) proposal = ProposalBase.objects.get_subclass(pk=proposal.pk) - + if proposal.cancelled: return HttpResponseForbidden() - + if request.method == "POST": form = SupportingDocumentCreateForm(request.POST, request.FILES) if form.is_valid(): @@ -353,7 +353,7 @@ def document_create(request, proposal_pk): return redirect("proposal_detail", proposal.pk) else: form = SupportingDocumentCreateForm() - + return render(request, "proposals/document_create.html", { "proposal": proposal, "form": form, @@ -378,8 +378,8 @@ def document_download(request, pk, *args): def document_delete(request, pk): document = get_object_or_404(SupportingDocument, pk=pk, uploaded_by=request.user) proposal_pk = document.proposal.pk - + if request.method == "POST": document.delete() - + return redirect("proposal_detail", proposal_pk) From b78f7ebb91092221ca4a1948d0870f8e20ab88d9 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Mon, 13 Jan 2014 16:36:22 -0500 Subject: [PATCH 20/46] Create a requirements file --- requirements/base.txt | 13 +++++++++++++ requirements-docs.txt => requirements/docs.txt | 0 2 files changed, 13 insertions(+) create mode 100644 requirements/base.txt rename requirements-docs.txt => requirements/docs.txt (100%) diff --git a/requirements/base.txt b/requirements/base.txt new file mode 100644 index 00000000..2ee30364 --- /dev/null +++ b/requirements/base.txt @@ -0,0 +1,13 @@ +Django==1.4.5 +django-appconf==0.5 +django-forms-bootstrap==2.0.3.post2 +django-markitup==1.0.0 +django-model-utils==1.1.0 +django-reversion==1.7 +django-sitetree==0.9.4 +django-taggit==0.9.3 +django-timezones==0.2 +django-user-accounts==1.0b13 +easy-thumbnails==1.2 +html5lib==0.95 +markdown==2.3.1 diff --git a/requirements-docs.txt b/requirements/docs.txt similarity index 100% rename from requirements-docs.txt rename to requirements/docs.txt From e799ead0947b24d2a8cc9acf04d9be4e0ea7cff1 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Mon, 13 Jan 2014 16:41:10 -0500 Subject: [PATCH 21/46] Remove outdated fixture_gen files http://github.com/alex/fixture_generator has not been updated since Django 1.2. --- symposion/reviews/fixture_gen.py | 9 --------- symposion/speakers/fixture_gen.py | 29 ----------------------------- 2 files changed, 38 deletions(-) delete mode 100644 symposion/reviews/fixture_gen.py delete mode 100644 symposion/speakers/fixture_gen.py diff --git a/symposion/reviews/fixture_gen.py b/symposion/reviews/fixture_gen.py deleted file mode 100644 index 3a6aaa40..00000000 --- a/symposion/reviews/fixture_gen.py +++ /dev/null @@ -1,9 +0,0 @@ -from django.contrib.auth.models import Group - -from fixture_generator import fixture_generator - - -@fixture_generator(Group) -def initial_data(): - Group.objects.create(name="reviewers") - Group.objects.create(name="reviewers-admins") diff --git a/symposion/speakers/fixture_gen.py b/symposion/speakers/fixture_gen.py deleted file mode 100644 index fc38463f..00000000 --- a/symposion/speakers/fixture_gen.py +++ /dev/null @@ -1,29 +0,0 @@ -from django.contrib.auth.models import User - -from fixture_generator import fixture_generator - -from symposion.speakers.models import Speaker - - -@fixture_generator(Speaker, User) -def speakers(): - guido = User.objects.create_user("guido", "guido@python.org", "pythonisawesome") - matz = User.objects.create_user("matz", "matz@ruby.org", "pythonsucks") - larry = User.objects.create_user("larryw", "larry@perl.org", "linenoisehere") - - Speaker.objects.create( - user=guido, - name="Guido van Rossum", - biography="I wrote Python, and named it after Monty Python", - ) - Speaker.objects.create( - user=matz, - name="Yukihiro Matsumoto", - biography="I wrote Ruby, and named it after the rare gem Ruby, a pun " - "on Perl/pearl.", - ) - Speaker.objects.create( - user=larry, - name="Larry Wall", - biography="I wrote Perl, and named it after the Parable of the Pearl", - ) From 2413421324d3ba9f79523ba7506c0df70f61f0e6 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Mon, 13 Jan 2014 16:42:31 -0500 Subject: [PATCH 22/46] Remove old tests file --- symposion/reviews/tests.py | 143 ------------------------------------- 1 file changed, 143 deletions(-) delete mode 100644 symposion/reviews/tests.py diff --git a/symposion/reviews/tests.py b/symposion/reviews/tests.py deleted file mode 100644 index e5fe7caf..00000000 --- a/symposion/reviews/tests.py +++ /dev/null @@ -1,143 +0,0 @@ -from django.core.urlresolvers import reverse -from django.test import TestCase - -from django.contrib.auth.models import User, Group - -from symposion.proposals.models import Proposal -from symposion.reviews.models import Review, ReviewAssignment - - -class login(object): - def __init__(self, testcase, user, password): - self.testcase = testcase - success = testcase.client.login(username=user, password=password) - self.testcase.assertTrue( - success, - "login with username=%r, password=%r failed" % (user, password) - ) - - def __enter__(self): - pass - - def __exit__(self, *args): - self.testcase.client.logout() - - -class ReviewTests(TestCase): - fixtures = ["proposals"] - - def get(self, url_name, *args, **kwargs): - return self.client.get(reverse(url_name, args=args, kwargs=kwargs)) - - def post(self, url_name, *args, **kwargs): - data = kwargs.pop("data") - return self.client.post(reverse(url_name, args=args, kwargs=kwargs), data) - - def login(self, user, password): - return login(self, user, password) - - def test_detail_perms(self): - guidos_proposal = Proposal.objects.all()[0] - response = self.get("review_detail", pk=guidos_proposal.pk) - - # Not logged in - self.assertEqual(response.status_code, 302) - - with self.login("guido", "pythonisawesome"): - response = self.get("review_detail", pk=guidos_proposal.pk) - # Guido can see his own proposal. - self.assertEqual(response.status_code, 200) - - with self.login("matz", "pythonsucks"): - response = self.get("review_detail", pk=guidos_proposal.pk) - # Matz can't see guido's proposal - self.assertEqual(response.status_code, 302) - - larry = User.objects.get(username="larryw") - # Larry is a trustworthy guy, he's a reviewer. - larry.groups.add(Group.objects.get(name="reviewers")) - with self.login("larryw", "linenoisehere"): - response = self.get("review_detail", pk=guidos_proposal.pk) - # Reviewers can see a review detail page. - self.assertEqual(response.status_code, 200) - - def test_reviewing(self): - guidos_proposal = Proposal.objects.all()[0] - - with self.login("guido", "pythonisawesome"): - response = self.post("review_review", pk=guidos_proposal.pk, data={ - "vote": "+1", - }) - # It redirects, but... - self.assertEqual(response.status_code, 302) - # ... no vote recorded - self.assertEqual(guidos_proposal.reviews.count(), 0) - - larry = User.objects.get(username="larryw") - # Larry is a trustworthy guy, he's a reviewer. - larry.groups.add(Group.objects.get(name="reviewers")) - with self.login("larryw", "linenoisehere"): - response = self.post("review_review", pk=guidos_proposal.pk, data={ - "vote": "+0", - "text": "Looks like a decent proposal, and Guido is a smart guy", - }) - self.assertEqual(response.status_code, 302) - self.assertEqual(guidos_proposal.reviews.count(), 1) - self.assertEqual(ReviewAssignment.objects.count(), 1) - assignment = ReviewAssignment.objects.get() - self.assertEqual(assignment.proposal, guidos_proposal) - self.assertEqual(assignment.origin, ReviewAssignment.OPT_IN) - self.assertEqual(guidos_proposal.comments.count(), 1) - comment = guidos_proposal.comments.get() - self.assertFalse(comment.public) - - response = self.post("review_review", pk=guidos_proposal.pk, data={ - "vote": "+1", - "text": "Actually Perl is dead, we really need a talk on the future", - }) - self.assertEqual(guidos_proposal.reviews.count(), 2) - self.assertEqual(ReviewAssignment.objects.count(), 1) - assignment = ReviewAssignment.objects.get() - self.assertEqual(assignment.review, Review.objects.order_by("-id")[0]) - self.assertEqual(guidos_proposal.comments.count(), 2) - - # Larry's a big fan... - response = self.post("review_review", pk=guidos_proposal.pk, data={ - "vote": "+20", - }) - self.assertEqual(guidos_proposal.reviews.count(), 2) - - def test_speaker_commenting(self): - guidos_proposal = Proposal.objects.all()[0] - - with self.login("guido", "pythonisawesome"): - response = self.get("review_comment", pk=guidos_proposal.pk) - # Guido can comment on his proposal. - self.assertEqual(response.status_code, 200) - - response = self.post("review_comment", pk=guidos_proposal.pk, data={ - "text": "FYI I can do this as a 30-minute or 45-minute talk.", - }) - self.assertEqual(response.status_code, 302) - self.assertEqual(guidos_proposal.comments.count(), 1) - comment = guidos_proposal.comments.get() - self.assertTrue(comment.public) - - larry = User.objects.get(username="larryw") - # Larry is a trustworthy guy, he's a reviewer. - larry.groups.add(Group.objects.get(name="reviewers")) - with self.login("larryw", "linenoisehere"): - response = self.get("review_comment", pk=guidos_proposal.pk) - # Larry can comment, since he's a reviewer - self.assertEqual(response.status_code, 200) - - response = self.post("review_comment", pk=guidos_proposal.pk, data={ - "text": "Thanks for the heads-up Guido." - }) - self.assertEqual(response.status_code, 302) - self.assertEqual(guidos_proposal.comments.count(), 2) - - with self.login("matz", "pythonsucks"): - response = self.get("review_comment", pk=guidos_proposal.pk) - # Matz can't comment. - self.assertEqual(response.status_code, 302) From f2c3cbb3365b351abb97082969d40c9edd26d1c8 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Wed, 15 Jan 2014 10:07:04 -0500 Subject: [PATCH 23/46] Add install requirements to setup.py --- setup.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 74eebbc5..2018f9a9 100644 --- a/setup.py +++ b/setup.py @@ -1,10 +1,20 @@ #!/usr/bin/env python - +import os from setuptools import setup, find_packages import symposion +def read_file(filename): + """Read a file into a string.""" + path = os.path.abspath(os.path.dirname(__file__)) + filepath = os.path.ojoin(path, filename) + try: + return open(filepath).read() + except IOError: + return '' + + setup( name="symposion", author="James Tauber", @@ -12,7 +22,7 @@ setup( version=symposion.__version__, description="A collection of Django apps for conference websites.", url="http://eldarion.com/symposion/", - packages=find_packages(exclude=["symposion_project"]), + packages=find_packages(), include_package_data=True, classifiers=( "Development Status :: 4 - Beta", @@ -22,4 +32,5 @@ setup( "Natural Language :: English", "License :: OSI Approved :: MIT License", ), + install_requires=read_file("requirements/base.txt").splitlines(), ) From c8087ec23346bad31ba4a4b002e3f933a7bd8fb0 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Wed, 15 Jan 2014 10:19:40 -0500 Subject: [PATCH 24/46] Update quickstart instructions in README --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cad1f6fa..f0f04932 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,17 @@ A conference management solution from Eldarion. Built with the generous support of the Python Software Foundation. -See http://eldarion.com/symposion/ for commercial support, customization and hosting +See http://eldarion.com/symposion/ for commercial support, customization and +hosting. ## Quickstart -If you're interested in running symposion locally, we have built a [basic +To install Symposion, run: + + pip install symposion + +Symposion is a Django app. You will need to create a Django project to +customize and manage your Symposion installation. We have built a [basic Django startproject template that includes Symposion][1]. [1]: https://github.com/pinax/pinax-project-symposion From 18896aa6da36825769e27a4b5bfc3f9c5d71c1ae Mon Sep 17 00:00:00 2001 From: David Ray Date: Thu, 16 Jan 2014 08:27:29 -0500 Subject: [PATCH 25/46] fix typo --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2018f9a9..bdf75e6f 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ import symposion def read_file(filename): """Read a file into a string.""" path = os.path.abspath(os.path.dirname(__file__)) - filepath = os.path.ojoin(path, filename) + filepath = os.path.join(path, filename) try: return open(filepath).read() except IOError: From 0163ded85b5cb7a260f923a5e800cdb672450739 Mon Sep 17 00:00:00 2001 From: David Ray Date: Thu, 16 Jan 2014 08:28:45 -0500 Subject: [PATCH 26/46] fix typo --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2018f9a9..bdf75e6f 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ import symposion def read_file(filename): """Read a file into a string.""" path = os.path.abspath(os.path.dirname(__file__)) - filepath = os.path.ojoin(path, filename) + filepath = os.path.join(path, filename) try: return open(filepath).read() except IOError: From c654c5aabbf1db1d1aab690619e05d45bb730d92 Mon Sep 17 00:00:00 2001 From: David Ray Date: Thu, 16 Jan 2014 10:48:39 -0500 Subject: [PATCH 27/46] restore settings import as django-appconf relies on it being there --- symposion/conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/symposion/conf.py b/symposion/conf.py index dd2a6d50..ad9a1324 100644 --- a/symposion/conf.py +++ b/symposion/conf.py @@ -1,3 +1,5 @@ +from django.conf import settings + from appconf import AppConf From 6ab7e498ece973bacfe12726a713e5693e52171e Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Fri, 31 Jan 2014 17:27:58 -0500 Subject: [PATCH 28/46] Upgrade django-markitup from 1.0.0 -> 2.1 For Django 1.6 compatibility. --- requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index 2ee30364..5c625849 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,7 +1,7 @@ Django==1.4.5 django-appconf==0.5 django-forms-bootstrap==2.0.3.post2 -django-markitup==1.0.0 +django-markitup==2.1 django-model-utils==1.1.0 django-reversion==1.7 django-sitetree==0.9.4 From 8b7b09731484f5bf8fd2d50d54beaf85a188d6b5 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Fri, 31 Jan 2014 17:28:54 -0500 Subject: [PATCH 29/46] Update django-reversion from 1.7 -> 1.8 For Django 1.6 compatibility. --- requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index 5c625849..47519e56 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -3,7 +3,7 @@ django-appconf==0.5 django-forms-bootstrap==2.0.3.post2 django-markitup==2.1 django-model-utils==1.1.0 -django-reversion==1.7 +django-reversion==1.8 django-sitetree==0.9.4 django-taggit==0.9.3 django-timezones==0.2 From 6d4e7b1eb1660cab6095ca5ba50eb49c276abaf8 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Fri, 31 Jan 2014 17:29:36 -0500 Subject: [PATCH 30/46] Update django-sitetree from 0.9.4 -> 1.0.0 For Django 1.6 compatibility. --- requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index 47519e56..03bdf391 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -4,7 +4,7 @@ django-forms-bootstrap==2.0.3.post2 django-markitup==2.1 django-model-utils==1.1.0 django-reversion==1.8 -django-sitetree==0.9.4 +django-sitetree==1.0.0 django-taggit==0.9.3 django-timezones==0.2 django-user-accounts==1.0b13 From 8e852901071a320a0796701ef0ae8bf331877e94 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Fri, 31 Jan 2014 17:30:05 -0500 Subject: [PATCH 31/46] Update django-taggit from 0.9.3 -> 0.11.2 For Django 1.6 compatibility. --- requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index 03bdf391..31452f50 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -5,7 +5,7 @@ django-markitup==2.1 django-model-utils==1.1.0 django-reversion==1.8 django-sitetree==1.0.0 -django-taggit==0.9.3 +django-taggit==0.11.2 django-timezones==0.2 django-user-accounts==1.0b13 easy-thumbnails==1.2 From e92dee1e0e33c87dce88387364996b460a9c3d36 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Fri, 31 Jan 2014 17:30:32 -0500 Subject: [PATCH 32/46] Update easy-thumbnails from 1.2 -> 1.4 For Django 1.6 compatibility. --- requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index 31452f50..bffba110 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -8,6 +8,6 @@ django-sitetree==1.0.0 django-taggit==0.11.2 django-timezones==0.2 django-user-accounts==1.0b13 -easy-thumbnails==1.2 +easy-thumbnails==1.4 html5lib==0.95 markdown==2.3.1 From 8d5461d05de53197cb3d90ed9098877418917392 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Fri, 31 Jan 2014 17:31:32 -0500 Subject: [PATCH 33/46] Loosen Django requirement So that each project may control which version of Django to use. Not all of the latest requirements are compatible with Django 1.4 anymore. --- requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index bffba110..11be4891 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,4 +1,4 @@ -Django==1.4.5 +Django>=1.5,<=1.6 django-appconf==0.5 django-forms-bootstrap==2.0.3.post2 django-markitup==2.1 From 9833a6a27cb7107b4b8d5f55c3c74f69229fe2d0 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Tue, 11 Feb 2014 09:24:03 -0500 Subject: [PATCH 34/46] Loosen django-forms-bootstrap requirement --- requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index 11be4891..05a5a605 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,6 +1,6 @@ Django>=1.5,<=1.6 django-appconf==0.5 -django-forms-bootstrap==2.0.3.post2 +django-forms-bootstrap>=2.0.3.post2 django-markitup==2.1 django-model-utils==1.1.0 django-reversion==1.8 From bc3dfd6c4c2585520377307e1299c37e3500019c Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Tue, 11 Feb 2014 11:26:56 -0500 Subject: [PATCH 35/46] Redirect to dashboard if there are no benefits to edit. The sponsor object has been created, and we only need to collect details about the potential-sponsor's benefits. If there are no benefits, the user should be redirected to the dashboard rather than forced to submit what appears to be the same form twice. --- symposion/sponsorship/views.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/symposion/sponsorship/views.py b/symposion/sponsorship/views.py index 22b4f243..4c39f812 100644 --- a/symposion/sponsorship/views.py +++ b/symposion/sponsorship/views.py @@ -15,7 +15,16 @@ def sponsor_apply(request): form = SponsorApplicationForm(request.POST, user=request.user) if form.is_valid(): sponsor = form.save() - return redirect("sponsor_detail", pk=sponsor.pk) + if sponsor.sponsor_benefits.all(): + # Redirect user to sponsor_detail to give extra information. + messages.success(request, "Thank you for your sponsorship " + "application. Please update your " + "benefit details below.") + return redirect("sponsor_detail", pk=sponsor.pk) + else: + messages.success(request, "Thank you for your sponsorship " + "application.") + return redirect("dashboard") else: form = SponsorApplicationForm(user=request.user) From 6de322216d9585670c53caf3c159ced8e1256737 Mon Sep 17 00:00:00 2001 From: Rebecca Lovewell Date: Tue, 25 Feb 2014 21:36:32 -0500 Subject: [PATCH 36/46] Show message when user does not have permission to access proposal submission page --- symposion/proposals/views.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/symposion/proposals/views.py b/symposion/proposals/views.py index f8dde53c..c23fc803 100644 --- a/symposion/proposals/views.py +++ b/symposion/proposals/views.py @@ -4,6 +4,7 @@ import sys from django.conf import settings from django.core.exceptions import ObjectDoesNotExist +from django.core.urlresolvers import reverse from django.db.models import Q from django.http import Http404, HttpResponse, HttpResponseForbidden from django.shortcuts import render, redirect, get_object_or_404 @@ -31,11 +32,18 @@ def get_form(name): def proposal_submit(request): if not request.user.is_authenticated(): + messages.info(request, "To submit a proposal, please " + "log in and create a speaker profile " + "via the dashboard.".format(settings.LOGIN_URL)) return redirect("home") # @@@ unauth'd speaker info page? else: try: request.user.speaker_profile except ObjectDoesNotExist: + url = reverse("speaker_create") + messages.info(request, "To submit a proposal, first " + "create a speaker " + "profile.".format(url)) return redirect("dashboard") kinds = [] From 2f75033dc5c8369b150fcd964e0e99de8b3f08de Mon Sep 17 00:00:00 2001 From: David Ray Date: Wed, 26 Feb 2014 13:56:19 -0500 Subject: [PATCH 37/46] update dep --- requirements/base.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/base.txt b/requirements/base.txt index 05a5a605..b503a4ba 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -2,7 +2,7 @@ Django>=1.5,<=1.6 django-appconf==0.5 django-forms-bootstrap>=2.0.3.post2 django-markitup==2.1 -django-model-utils==1.1.0 +django-model-utils==2.0.2 django-reversion==1.8 django-sitetree==1.0.0 django-taggit==0.11.2 From 4d1e9cf78e3108fab2d2b8c206ae3c87d29d93a0 Mon Sep 17 00:00:00 2001 From: David Ray Date: Fri, 28 Feb 2014 10:55:54 -0500 Subject: [PATCH 38/46] work on #6, needs tests --- symposion/schedule/forms.py | 119 +++++++++++++++++- symposion/schedule/views.py | 16 ++- .../templates/schedule/schedule_edit.html | 24 +++- 3 files changed, 152 insertions(+), 7 deletions(-) diff --git a/symposion/schedule/forms.py b/symposion/schedule/forms.py index 63316743..3e4c9ff4 100644 --- a/symposion/schedule/forms.py +++ b/symposion/schedule/forms.py @@ -1,13 +1,21 @@ +import csv +import time + +from datetime import datetime + from django import forms +from django.contrib import messages +from django.db import IntegrityError, transaction from django.db.models import Q from markitup.widgets import MarkItUpWidget -from symposion.schedule.models import Presentation +from symposion.schedule.models import (Day, Presentation, Room, SlotKind, Slot, + SlotRoom) class SlotEditForm(forms.Form): - + def __init__(self, *args, **kwargs): self.slot = kwargs.pop("slot") super(SlotEditForm, self).__init__(*args, **kwargs) @@ -16,7 +24,7 @@ class SlotEditForm(forms.Form): self.fields["presentation"] = self.build_presentation_field() else: self.fields["content_override"] = self.build_content_override_field() - + def build_presentation_field(self): kwargs = {} queryset = Presentation.objects.all() @@ -31,7 +39,7 @@ class SlotEditForm(forms.Form): kwargs["required"] = True kwargs["queryset"] = queryset return forms.ModelChoiceField(**kwargs) - + def build_content_override_field(self): kwargs = { "label": "Content", @@ -40,3 +48,106 @@ class SlotEditForm(forms.Form): "initial": self.slot.content_override, } return forms.CharField(**kwargs) + + +class ScheduleSectionForm(forms.Form): + ROOM_KEY = 'room' + DATE_KEY = 'date' + START_KEY = 'time_start' + END_KEY = 'time_end' + KIND = 'kind' + + filename = forms.FileField( + label='Select a CSV file to import:', + required=False + ) + + def __init__(self, *args, **kwargs): + self.schedule = kwargs.pop("schedule") + super(ScheduleSectionForm, self).__init__(*args, **kwargs) + + def clean_filename(self): + if 'submit' in self.data: + fname = self.cleaned_data.get('filename') + if not fname or not fname.name.endswith('.csv'): + raise forms.ValidationError(u'Please upload a .csv file') + return fname + + def _get_start_end_times(self, data): + "Return start and end time objects" + start_time = time.strptime(data[self.START_KEY], '%I:%M %p') + start = datetime(100, 1, 1, start_time.tm_hour, start_time.tm_min, 00) + end_time = time.strptime(data[self.END_KEY], '%I:%M %p') + end = datetime(100, 1, 1, end_time.tm_hour, end_time.tm_min, 00) + return start.time(), end.time() + + def _build_rooms(self, data): + "Get or Create Rooms based on schedule type and set of Tracks" + created_rooms = [] + rooms = sorted(set([x[self.ROOM_KEY] for x in data])) + for i, room in enumerate(rooms): + room, created = Room.objects.get_or_create( + schedule=self.schedule, name=room, order=i + ) + if created: + created_rooms.append(room) + return created_rooms + + def _build_days(self, data): + "Get or Create Days based on schedule type and set of Days" + created_days = [] + days = set([x[self.DATE_KEY] for x in data]) + for day in days: + date = datetime.strptime(day, "%m/%d/%Y") + day, created = Day.objects.get_or_create( + schedule=self.schedule, date=date + ) + if created: + created_days.append(day) + return created_days + + def build_schedule(self): + created_items = [] + reader = csv.DictReader(self.cleaned_data.get('filename')) + data = [dict((k.strip(), v.strip()) for k, v in x.items()) for x in reader] + # build rooms + created_items.extend(self._build_rooms(data)) + # build_days + created_items.extend(self._build_days(data)) + # build Slot -> SlotRoom + for row in data: + room = Room.objects.get( + schedule=self.schedule, name=row[self.ROOM_KEY] + ) + date = datetime.strptime(row[self.DATE_KEY], "%m/%d/%Y") + day = Day.objects.get(schedule=self.schedule, date=date) + start, end = self._get_start_end_times(row) + slot_kind, created = SlotKind.objects.get_or_create( + label=row[self.KIND], schedule=self.schedule + ) + if created: + created_items.append(slot_kind) + if row[self.KIND] == 'plenary': + slot, created = Slot.objects.get_or_create( + kind=slot_kind, day=day, start=start, end=end + ) + if created: + created_items.append(slot) + else: + slot = Slot.objects.create( + kind=slot_kind, day=day, start=start, end=end + ) + created_items.append(slot) + try: + SlotRoom.objects.create(slot=slot, room=room) + except IntegrityError: + transaction.rollback() + # delete all created objects and report error + for x in created_items: + x.delete() + return messages.ERROR, u'An overlap occurred; the import was cancelled.' + return messages.SUCCESS, u'Your schedule has been imported.' + + def delete_schedule(self): + self.schedule.day_set.all().delete() + return messages.SUCCESS, u'Your schedule has been deleted.' diff --git a/symposion/schedule/views.py b/symposion/schedule/views.py index 1367808b..6b229c09 100644 --- a/symposion/schedule/views.py +++ b/symposion/schedule/views.py @@ -3,8 +3,9 @@ from django.shortcuts import render, get_object_or_404, redirect from django.template import loader, Context from django.contrib.auth.decorators import login_required +from django.contrib import messages -from symposion.schedule.forms import SlotEditForm +from symposion.schedule.forms import SlotEditForm, ScheduleSectionForm from symposion.schedule.models import Schedule, Day, Slot, Presentation from symposion.schedule.timetable import TimeTable @@ -100,11 +101,24 @@ def schedule_edit(request, slug=None): schedule = fetch_schedule(slug) + if request.method == "POST": + form = ScheduleSectionForm( + request.POST, request.FILES, schedule=schedule + ) + if form.is_valid(): + if 'submit' in form.data: + msg = form.build_schedule() + elif 'delete' in form.data: + msg = form.delete_schedule() + messages.add_message(request, msg[0], msg[1]) + else: + form = ScheduleSectionForm(schedule=schedule) days_qs = Day.objects.filter(schedule=schedule) days = [TimeTable(day) for day in days_qs] ctx = { "schedule": schedule, "days": days, + "form": form } return render(request, "schedule/schedule_edit.html", ctx) diff --git a/symposion/templates/schedule/schedule_edit.html b/symposion/templates/schedule/schedule_edit.html index 5de11af2..d6713aa5 100644 --- a/symposion/templates/schedule/schedule_edit.html +++ b/symposion/templates/schedule/schedule_edit.html @@ -18,13 +18,19 @@

    Schedule Edit

    - + {% for timetable in days %}

    {{ timetable.day.date }}

    {% include "schedule/_edit_grid.html" %} {% endfor %}
    - + {% if request.user.is_staff %} +
    {% csrf_token %} + {{ form.as_p }} + + +
    + {% endif %}
    {% endblock %} @@ -41,5 +47,19 @@ e.preventDefault(); }); }); + $(function() { + //submit event handler + $("form#schedule-builder :submit").click(function(e) { + var name = this.name; + if(name == 'delete') { + if (!confirm("Are you sure you want to delete the schedule?")) + { + e.preventDefault(); + return; + } + } + }); + }); + {% endblock %} From 5f27b014522327c6cf7fa867bc020d1ea32c1384 Mon Sep 17 00:00:00 2001 From: David Ray Date: Fri, 28 Feb 2014 12:17:48 -0500 Subject: [PATCH 39/46] remove unecessary check --- symposion/templates/schedule/schedule_edit.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/symposion/templates/schedule/schedule_edit.html b/symposion/templates/schedule/schedule_edit.html index d6713aa5..9b1ab864 100644 --- a/symposion/templates/schedule/schedule_edit.html +++ b/symposion/templates/schedule/schedule_edit.html @@ -24,13 +24,11 @@ {% include "schedule/_edit_grid.html" %} {% endfor %} - {% if request.user.is_staff %}
    {% csrf_token %} {{ form.as_p }}
    - {% endif %} {% endblock %} From 6102c4e5e4070458030433292bf307e3b3335bbf Mon Sep 17 00:00:00 2001 From: David Ray Date: Mon, 3 Mar 2014 08:38:47 -0500 Subject: [PATCH 40/46] adding back in ws --- symposion/schedule/forms.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/symposion/schedule/forms.py b/symposion/schedule/forms.py index 3e4c9ff4..16187b29 100644 --- a/symposion/schedule/forms.py +++ b/symposion/schedule/forms.py @@ -15,7 +15,7 @@ from symposion.schedule.models import (Day, Presentation, Room, SlotKind, Slot, class SlotEditForm(forms.Form): - + def __init__(self, *args, **kwargs): self.slot = kwargs.pop("slot") super(SlotEditForm, self).__init__(*args, **kwargs) @@ -24,7 +24,7 @@ class SlotEditForm(forms.Form): self.fields["presentation"] = self.build_presentation_field() else: self.fields["content_override"] = self.build_content_override_field() - + def build_presentation_field(self): kwargs = {} queryset = Presentation.objects.all() @@ -39,7 +39,7 @@ class SlotEditForm(forms.Form): kwargs["required"] = True kwargs["queryset"] = queryset return forms.ModelChoiceField(**kwargs) - + def build_content_override_field(self): kwargs = { "label": "Content", From 62289cad36c57905a778a5b53875b91474f7840e Mon Sep 17 00:00:00 2001 From: David Ray Date: Mon, 3 Mar 2014 13:47:46 -0500 Subject: [PATCH 41/46] make private methods more robust --- symposion/schedule/forms.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/symposion/schedule/forms.py b/symposion/schedule/forms.py index 16187b29..8d709197 100644 --- a/symposion/schedule/forms.py +++ b/symposion/schedule/forms.py @@ -75,11 +75,15 @@ class ScheduleSectionForm(forms.Form): def _get_start_end_times(self, data): "Return start and end time objects" - start_time = time.strptime(data[self.START_KEY], '%I:%M %p') - start = datetime(100, 1, 1, start_time.tm_hour, start_time.tm_min, 00) - end_time = time.strptime(data[self.END_KEY], '%I:%M %p') - end = datetime(100, 1, 1, end_time.tm_hour, end_time.tm_min, 00) - return start.time(), end.time() + times = [] + for x in [data[self.START_KEY], data[self.END_KEY]]: + try: + time_obj = time.strptime(x, '%I:%M %p') + except: + return messages.ERROR, u'Malformed time found: %s.' % x + time_obj = datetime(100, 1, 1, time_obj.tm_hour, time_obj.tm_min, 00) + times.append(time_obj.time()) + return times def _build_rooms(self, data): "Get or Create Rooms based on schedule type and set of Tracks" @@ -98,7 +102,11 @@ class ScheduleSectionForm(forms.Form): created_days = [] days = set([x[self.DATE_KEY] for x in data]) for day in days: - date = datetime.strptime(day, "%m/%d/%Y") + try: + date = datetime.strptime(day, "%m/%d/%Y") + except ValueError: + [x.delete() for x in created_days] + return messages.ERROR, u'Malformed data found: %s.' % day day, created = Day.objects.get_or_create( schedule=self.schedule, date=date ) @@ -139,9 +147,9 @@ class ScheduleSectionForm(forms.Form): ) created_items.append(slot) try: - SlotRoom.objects.create(slot=slot, room=room) + with transaction.atomic(): + SlotRoom.objects.create(slot=slot, room=room) except IntegrityError: - transaction.rollback() # delete all created objects and report error for x in created_items: x.delete() From 0ce5e36c24fbca4d5ea6466a50d6349c88ada11c Mon Sep 17 00:00:00 2001 From: David Ray Date: Mon, 3 Mar 2014 13:48:24 -0500 Subject: [PATCH 42/46] add tests for build schedule form --- symposion/schedule/tests/__init__.py | 0 symposion/schedule/tests/data/schedule.csv | 13 ++ .../schedule/tests/data/schedule_overlap.csv | 14 ++ symposion/schedule/tests/test_forms.py | 156 ++++++++++++++++++ 4 files changed, 183 insertions(+) create mode 100644 symposion/schedule/tests/__init__.py create mode 100644 symposion/schedule/tests/data/schedule.csv create mode 100644 symposion/schedule/tests/data/schedule_overlap.csv create mode 100644 symposion/schedule/tests/test_forms.py diff --git a/symposion/schedule/tests/__init__.py b/symposion/schedule/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/schedule/tests/data/schedule.csv b/symposion/schedule/tests/data/schedule.csv new file mode 100644 index 00000000..66a87bdc --- /dev/null +++ b/symposion/schedule/tests/data/schedule.csv @@ -0,0 +1,13 @@ +"date","time_start","time_end","kind"," room " +"12/12/2013","10:00 AM","11:00 AM","plenary","Room2" +"12/12/2013","10:00 AM","11:00 AM","plenary","Room1" +"12/12/2013","11:00 AM","12:00 PM","talk","Room1" +"12/12/2013","11:00 AM","12:00 PM","talk","Room2" +"12/12/2013","12:00 PM","12:45 PM","plenary","Room1" +"12/12/2013","12:00 PM","12:45 PM","plenary","Room2" +"12/13/2013","10:00 AM","11:00 AM","plenary","Room2" +"12/13/2013","10:00 AM","11:00 AM","plenary","Room1" +"12/13/2013","11:00 AM","12:00 PM","talk","Room1" +"12/13/2013","11:00 AM","12:00 PM","talk","Room2" +"12/13/2013","12:00 PM","12:45 PM","plenary","Room1" +"12/13/2013","12:00 PM","12:45 PM","plenary","Room2" diff --git a/symposion/schedule/tests/data/schedule_overlap.csv b/symposion/schedule/tests/data/schedule_overlap.csv new file mode 100644 index 00000000..3c02ce2b --- /dev/null +++ b/symposion/schedule/tests/data/schedule_overlap.csv @@ -0,0 +1,14 @@ +"date","time_start","time_end","kind"," room " +"12/12/2013","10:00 AM","11:00 AM","plenary","Room2" +"12/12/2013","10:00 AM","11:00 AM","plenary","Room1" +"12/12/2013","11:00 AM","12:00 PM","talk","Room1" +"12/12/2013","11:00 AM","12:00 PM","talk","Room2" +"12/12/2013","12:00 PM","12:45 PM","plenary","Room1" +"12/12/2013","12:00 PM","12:45 PM","plenary","Room2" +"12/13/2013","10:00 AM","11:00 AM","plenary","Room2" +"12/13/2013","10:00 AM","11:00 AM","plenary","Room1" +"12/13/2013","11:00 AM","12:00 PM","talk","Room1" +"12/13/2013","11:00 AM","12:00 PM","talk","Room2" +"12/13/2013","12:00 PM","12:45 PM","plenary","Room1" +"12/13/2013","12:00 PM","12:45 PM","plenary","Room2" +"12/13/2013","12:00 PM","12:45 PM","plenary","Room2" diff --git a/symposion/schedule/tests/test_forms.py b/symposion/schedule/tests/test_forms.py new file mode 100644 index 00000000..883d7ac0 --- /dev/null +++ b/symposion/schedule/tests/test_forms.py @@ -0,0 +1,156 @@ +import os + +from datetime import datetime, timedelta + +from django.core.files.uploadedfile import SimpleUploadedFile +from django.test import TestCase + +from symposion.conference.models import Conference, Section + +from ..forms import ScheduleSectionForm +from ..models import Day, Room, Schedule, Slot, SlotKind + +DATA_DIR = os.path.join(os.path.dirname(__file__), 'data') + + +class ScheduleSectionFormTests(TestCase): + + def setUp(self): + self.conference = Conference.objects.create(title='test') + self.section = Section.objects.create( + conference=self.conference, + name='test') + self.schedule = Schedule.objects.create(section=self.section) + self.today = datetime.now() + self.tomorrow = self.today + timedelta(days=1) + + def test_clean_filename(self): + """Ensure a file is provided if the submit action was utilized""" + data = {'submit': 'Submit'} + form = ScheduleSectionForm(data=data, schedule=self.schedule) + self.assertIn('filename', form.errors) + + def test_clean_filename_not_required(self): + """Ensure file is not required if the delete action was utilize""" + data = {'delete': 'Delete'} + form = ScheduleSectionForm(data=data, schedule=self.schedule) + self.assertTrue(form.is_valid()) + + def test_delete(self): + """Delete schedule (Days) for supplied section""" + Day.objects.create(schedule=self.schedule, date=self.today) + Day.objects.create(schedule=self.schedule, date=self.tomorrow) + other_section = Section.objects.create(conference=self.conference, name='other') + other_schedule = Schedule.objects.create(section=other_section) + other_day = Day.objects.create(schedule=other_schedule, date=self.tomorrow) + self.assertEqual(3, Day.objects.all().count()) + data = {'delete': 'Delete'} + form = ScheduleSectionForm(data=data, schedule=self.schedule) + form.delete_schedule() + days = Day.objects.all() + self.assertEqual(1, days.count()) + self.assertIn(other_day, days) + + def test_build_days(self): + """Test private method to build days based off ingested CSV""" + form = ScheduleSectionForm(schedule=self.schedule) + data = ( + {'date': datetime.strftime(self.today, "%m/%d/%Y")}, + {'date': datetime.strftime(self.today, "%m/%d/%Y")}, + {'date': datetime.strftime(self.tomorrow, "%m/%d/%Y")}, + ) + self.assertEqual(0, Day.objects.all().count()) + form._build_days(data) + self.assertEqual(2, Day.objects.all().count()) + + def test_build_days_malformed(self): + """Test failure for malformed date in CSV""" + form = ScheduleSectionForm(schedule=self.schedule) + data = ( + {'date': datetime.strftime(self.today, "%m/%d/%Y")}, + {'date': '12-12-12'} + ) + self.assertEqual(0, Day.objects.all().count()) + msg_type, msg = form._build_days(data) + self.assertEqual(0, Day.objects.all().count()) + self.assertEqual(40, msg_type) + self.assertIn('12-12-12', msg) + + def test_build_rooms(self): + """Test private method to build rooms based off ingested CSV""" + form = ScheduleSectionForm(schedule=self.schedule) + data = ( + {'room': 'foo'}, + {'room': 'bar'}, + {'room': 'foo'}, + ) + self.assertEqual(0, Room.objects.all().count()) + form._build_rooms(data) + self.assertEqual(2, Room.objects.all().count()) + + def test_get_start_end_times(self): + """ + Test private method to convert start and end times based off + ingested CSV + """ + form = ScheduleSectionForm(schedule=self.schedule) + start = '12:00 PM' + end = '01:00 PM' + data = {'time_start': start, 'time_end': end} + start_time, end_time = form._get_start_end_times(data) + self.assertEqual(start, start_time.strftime('%I:%M %p')) + self.assertEqual(end, end_time.strftime('%I:%M %p')) + + def test_get_start_end_times_malformed(self): + """ + Test private method for malformed time based off ingested CSV + """ + form = ScheduleSectionForm(schedule=self.schedule) + start = '12:00' + end = '01:00' + data = {'time_start': start, 'time_end': end} + msg_type, msg = form._get_start_end_times(data) + self.assertEqual(40, msg_type) + self.assertIn('Malformed', msg) + + def test_build_schedule(self): + """ + Test successful schedule build based off ingested CSV + """ + self.assertEqual(0, Day.objects.all().count()) + self.assertEqual(0, Room.objects.all().count()) + self.assertEqual(0, Slot.objects.all().count()) + self.assertEqual(0, SlotKind.objects.all().count()) + schedule_csv = open(os.path.join(DATA_DIR, 'schedule.csv'), 'rb') + file_data = {'filename': SimpleUploadedFile(schedule_csv.name, schedule_csv.read())} + data = {'submit': 'Submit'} + form = ScheduleSectionForm(data, file_data, schedule=self.schedule) + form.is_valid() + msg_type, msg = form.build_schedule() + self.assertEqual(25, msg_type) + self.assertIn('imported', msg) + self.assertEqual(2, Day.objects.all().count()) + self.assertEqual(2, Room.objects.all().count()) + self.assertEqual(8, Slot.objects.all().count()) + self.assertEqual(2, SlotKind.objects.all().count()) + + def test_build_schedule_overlap(self): + """ + Test rolledback schedule build based off ingested CSV with Slot overlap + """ + self.assertEqual(0, Day.objects.all().count()) + self.assertEqual(0, Room.objects.all().count()) + self.assertEqual(0, Slot.objects.all().count()) + self.assertEqual(0, SlotKind.objects.all().count()) + schedule_csv = open(os.path.join(DATA_DIR, 'schedule_overlap.csv'), 'rb') + file_data = {'filename': SimpleUploadedFile(schedule_csv.name, schedule_csv.read())} + data = {'submit': 'Submit'} + form = ScheduleSectionForm(data, file_data, schedule=self.schedule) + form.is_valid() + msg_type, msg = form.build_schedule() + self.assertEqual(40, msg_type) + self.assertIn('overlap', msg) + self.assertEqual(0, Day.objects.all().count()) + self.assertEqual(0, Room.objects.all().count()) + self.assertEqual(0, Slot.objects.all().count()) + self.assertEqual(0, SlotKind.objects.all().count()) From 55ad74ab1206a54d56104ec965d472f322066395 Mon Sep 17 00:00:00 2001 From: David Ray Date: Mon, 3 Mar 2014 14:10:28 -0500 Subject: [PATCH 43/46] add schedule docs --- docs/index.rst | 1 + docs/schedule.rst | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 docs/schedule.rst diff --git a/docs/index.rst b/docs/index.rst index d8e9391e..732670ca 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -19,6 +19,7 @@ Apps: sponsorship speakers proposals + schedule Indices and tables diff --git a/docs/schedule.rst b/docs/schedule.rst new file mode 100644 index 00000000..13d942a8 --- /dev/null +++ b/docs/schedule.rst @@ -0,0 +1,49 @@ +Schedule App +=========== + +The ``schedule`` app allows staff members to create the schedule for the +conference's presentations, breaks, lunches, etc. + +The ```schedule``` app has a number of models that facilitate building the +structured schedule: + + * Schedule: A high level container that maps to each Conference Section. + * Day: A Day associated with a Schedule. + * Room: A Room associated with a Schedule. + * Slot Kind: A type of Slot associated with a Schedule. + * Slot: A discreet time period for a Schedule. + * Slot Room: A mapping of a Room and Slot for a given Schedule. + * Presentation: A mapping of a Slot to an approved Proposal from the ```proposals``` app. + +Schedule Builder Form +--------------------- + +It can be cumbersone to generate a schedule through the admin. With that in mind, +a generic schedule builder is available via a Schedule's edit view. For instance, +if a Conference site has a Talks Section and Schedule, the form would be +available for Staff at:: + +/schedule/talks/edit + +The form consume a structured CSV file, from which it will build the schedule. +Sample CSV data is included below:: + +"date","time_start","time_end","kind"," room " +"12/12/2013","10:00 AM","11:00 AM","plenary","Room2" +"12/12/2013","10:00 AM","11:00 AM","plenary","Room1" +"12/12/2013","11:00 AM","12:00 PM","talk","Room1" +"12/12/2013","11:00 AM","12:00 PM","talk","Room2" +"12/12/2013","12:00 PM","12:45 PM","plenary","Room1" +"12/12/2013","12:00 PM","12:45 PM","plenary","Room2" +"12/13/2013","10:00 AM","11:00 AM","plenary","Room2" +"12/13/2013","10:00 AM","11:00 AM","plenary","Room1" +"12/13/2013","11:00 AM","12:00 PM","talk","Room1" +"12/13/2013","11:00 AM","12:00 PM","talk","Room2" +"12/13/2013","12:00 PM","12:45 PM","plenary","Room1" +"12/13/2013","12:00 PM","12:45 PM","plenary","Room2" + +It is worth noting that this generates the **structure** of the schedule. It +does not create Presentation objects. This will need to be done manually. + +One can also **delete** an existing schedule via the delete action. This is +irreversible (save for a database restore). From 0e4dcef2a0b847f6abbaaddf2398591b33d69c5c Mon Sep 17 00:00:00 2001 From: David Ray Date: Tue, 4 Mar 2014 08:47:19 -0500 Subject: [PATCH 44/46] fix typos --- docs/schedule.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/schedule.rst b/docs/schedule.rst index 13d942a8..15d37fa1 100644 --- a/docs/schedule.rst +++ b/docs/schedule.rst @@ -11,21 +11,21 @@ structured schedule: * Day: A Day associated with a Schedule. * Room: A Room associated with a Schedule. * Slot Kind: A type of Slot associated with a Schedule. - * Slot: A discreet time period for a Schedule. + * Slot: A discrete time period for a Schedule. * Slot Room: A mapping of a Room and Slot for a given Schedule. * Presentation: A mapping of a Slot to an approved Proposal from the ```proposals``` app. Schedule Builder Form --------------------- -It can be cumbersone to generate a schedule through the admin. With that in mind, +It can be cumbersome to generate a schedule through the admin. With that in mind, a generic schedule builder is available via a Schedule's edit view. For instance, if a Conference site has a Talks Section and Schedule, the form would be available for Staff at:: /schedule/talks/edit -The form consume a structured CSV file, from which it will build the schedule. +The form consumes a structured CSV file, from which it will build the schedule. Sample CSV data is included below:: "date","time_start","time_end","kind"," room " From 5b853f9300827ea163fa04a8ed21b48e2175e8d0 Mon Sep 17 00:00:00 2001 From: David Ray Date: Thu, 19 Jun 2014 23:55:15 -0400 Subject: [PATCH 45/46] Fixes #11 --- symposion/reviews/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/symposion/reviews/views.py b/symposion/reviews/views.py index 8278778a..b1666f76 100644 --- a/symposion/reviews/views.py +++ b/symposion/reviews/views.py @@ -69,7 +69,7 @@ def review_section(request, section_slug, assigned=False, reviewed="all"): return access_not_permitted(request) section = get_object_or_404(ProposalSection, section__slug=section_slug) - queryset = ProposalBase.objects.filter(kind__section=section) + queryset = ProposalBase.objects.filter(kind__section=section.section) if assigned: assignments = ReviewAssignment.objects.filter(user=request.user).values_list("proposal__id") From 2f6930ae11c6dcffd55d2e36c347fbcedd8552fa Mon Sep 17 00:00:00 2001 From: David Ray Date: Mon, 11 Aug 2014 16:33:23 -0400 Subject: [PATCH 46/46] Fixes #12; 500 error when re/un assigning slot presentations --- symposion/schedule/models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/symposion/schedule/models.py b/symposion/schedule/models.py index c4614437..5ffd63ce 100644 --- a/symposion/schedule/models.py +++ b/symposion/schedule/models.py @@ -77,9 +77,10 @@ class Slot(models.Model): """ Unassign the associated content with this slot. """ - if self.content and self.content.slot_id: - self.content.slot = None - self.content.save() + content = self.content + if content and content.slot_id: + content.slot = None + content.save() @property def content(self):