commit
6d5c24e635
66 changed files with 611 additions and 604 deletions
|
@ -1,5 +1,3 @@
|
|||
import datetime
|
||||
|
||||
from django.db import models
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# flake8: noqa
|
||||
from django.conf.urls.defaults import url, patterns
|
||||
|
||||
|
||||
|
|
|
@ -7,7 +7,8 @@ from symposion.boxes.forms import BoxForm
|
|||
from symposion.boxes.models import Box
|
||||
|
||||
|
||||
# @@@ problem with this is that the box_edit.html and box_create.html won't have domain objects in context
|
||||
# @@@ problem with this is that the box_edit.html and box_create.html won't have domain objects in
|
||||
# context
|
||||
def get_auth_vars(request):
|
||||
auth_vars = {}
|
||||
if request.method == "POST":
|
||||
|
|
|
@ -4,6 +4,7 @@ import reversion
|
|||
|
||||
from .models import Page
|
||||
|
||||
|
||||
class PageAdmin(reversion.VersionAdmin):
|
||||
|
||||
pass
|
||||
|
|
|
@ -2,6 +2,7 @@ from datetime import datetime
|
|||
|
||||
from django.db import models
|
||||
|
||||
|
||||
class PublishedPageManager(models.Manager):
|
||||
|
||||
def get_query_set(self):
|
||||
|
|
|
@ -53,7 +53,8 @@ class Page(models.Model):
|
|||
def clean_fields(self, exclude=None):
|
||||
super(Page, self).clean_fields(exclude)
|
||||
if not re.match(settings.SYMPOSION_PAGE_REGEX, self.path):
|
||||
raise ValidationError({"path": [_("Path can only contain letters, numbers and hyphens and end with /")]})
|
||||
raise ValidationError(
|
||||
{"path": [_("Path can only contain letters, numbers and hyphens and end with /")]})
|
||||
|
||||
|
||||
reversion.register(Page)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# flake8: noqa
|
||||
from django.conf.urls.defaults import url, patterns
|
||||
|
||||
PAGE_RE = r"(([\w-]{1,})(/[\w-]{1,})*)/"
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from django.conf import settings
|
||||
|
||||
from appconf import AppConf
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.conf.urls.defaults import *
|
||||
# flake8: noqa
|
||||
from django.conf.urls.defaults import patterns, url
|
||||
|
||||
|
||||
urlpatterns = patterns("symposion.conference.views",
|
||||
|
|
|
@ -26,5 +26,6 @@ class SignupForm(account.forms.SignupForm):
|
|||
email_confirm = self.cleaned_data["email_confirm"]
|
||||
if email:
|
||||
if email != email_confirm:
|
||||
raise forms.ValidationError("Email address must match previously typed email address")
|
||||
raise forms.ValidationError(
|
||||
"Email address must match previously typed email address")
|
||||
return email_confirm
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import html5lib
|
||||
from html5lib import html5parser, sanitizer
|
||||
|
||||
import markdown
|
||||
|
|
|
@ -3,8 +3,7 @@ import csv
|
|||
from django.http import HttpResponse
|
||||
|
||||
|
||||
def export_as_csv_action(
|
||||
description="Export selected objects as CSV file",
|
||||
def export_as_csv_action(description="Export selected objects as CSV file",
|
||||
fields=None, exclude=None, header=True):
|
||||
"""
|
||||
This function returns an export csv action
|
||||
|
@ -24,12 +23,14 @@ def export_as_csv_action(
|
|||
excludeset = set(exclude)
|
||||
field_names = field_names - excludeset
|
||||
response = HttpResponse(mimetype="text/csv")
|
||||
response["Content-Disposition"] = "attachment; filename=%s.csv" % unicode(opts).replace(".", "_")
|
||||
response["Content-Disposition"] = \
|
||||
"attachment; filename=%s.csv" % unicode(opts).replace(".", "_")
|
||||
writer = csv.writer(response)
|
||||
if header:
|
||||
writer.writerow(list(field_names))
|
||||
for obj in queryset:
|
||||
writer.writerow([unicode(getattr(obj, field)).encode("utf-8", "replace") for field in field_names])
|
||||
writer.writerow(
|
||||
[unicode(getattr(obj, field)).encode("utf-8", "replace") for field in field_names])
|
||||
return response
|
||||
export_as_csv.short_description = description
|
||||
return export_as_csv
|
||||
|
|
|
@ -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)
|
|
@ -85,22 +85,29 @@ class ProposalBase(models.Model):
|
|||
description = models.TextField(
|
||||
_("Brief Description"),
|
||||
max_length=400, # @@@ need to enforce 400 in UI
|
||||
help_text="If your proposal is accepted this will be made public and printed in the program. Should be one paragraph, maximum 400 characters."
|
||||
help_text=_("If your proposal is accepted this will be made public and printed in the "
|
||||
"program. Should be one paragraph, maximum 400 characters.")
|
||||
)
|
||||
abstract = MarkupField(
|
||||
_("Detailed Abstract"),
|
||||
help_text=_("Detailed outline. Will be made public if your proposal is accepted. Edit using <a href='http://daringfireball.net/projects/markdown/basics' target='_blank'>Markdown</a>.")
|
||||
help_text=_("Detailed outline. Will be made public if your proposal is accepted. Edit "
|
||||
"using <a href='http://daringfireball.net/projects/markdown/basics' "
|
||||
"target='_blank'>Markdown</a>.")
|
||||
)
|
||||
additional_notes = MarkupField(
|
||||
blank=True,
|
||||
help_text=_("Anything else you'd like the program committee to know when making their selection: your past experience, etc. This is not made public. Edit using <a href='http://daringfireball.net/projects/markdown/basics' target='_blank'>Markdown</a>.")
|
||||
help_text=_("Anything else you'd like the program committee to know when making their "
|
||||
"selection: your past experience, etc. This is not made public. Edit using "
|
||||
"<a href='http://daringfireball.net/projects/markdown/basics' "
|
||||
"target='_blank'>Markdown</a>.")
|
||||
)
|
||||
submitted = models.DateTimeField(
|
||||
default=datetime.datetime.now,
|
||||
editable=False,
|
||||
)
|
||||
speaker = models.ForeignKey("speakers.Speaker", related_name="proposals")
|
||||
additional_speakers = models.ManyToManyField("speakers.Speaker", through="AdditionalSpeaker", blank=True)
|
||||
additional_speakers = models.ManyToManyField("speakers.Speaker", through="AdditionalSpeaker",
|
||||
blank=True)
|
||||
cancelled = models.BooleanField(default=False)
|
||||
|
||||
def can_edit(self):
|
||||
|
@ -120,7 +127,9 @@ class ProposalBase(models.Model):
|
|||
|
||||
def speakers(self):
|
||||
yield self.speaker
|
||||
for speaker in self.additional_speakers.exclude(additionalspeaker__status=AdditionalSpeaker.SPEAKING_STATUS_DECLINED):
|
||||
speakers = self.additional_speakers.exclude(
|
||||
additionalspeaker__status=AdditionalSpeaker.SPEAKING_STATUS_DECLINED)
|
||||
for speaker in speakers:
|
||||
yield speaker
|
||||
|
||||
def notification_email_context(self):
|
||||
|
@ -172,4 +181,5 @@ class SupportingDocument(models.Model):
|
|||
description = models.CharField(max_length=140)
|
||||
|
||||
def download_url(self):
|
||||
return reverse("proposal_document_download", args=[self.pk, os.path.basename(self.file.name).lower()])
|
||||
return reverse("proposal_document_download",
|
||||
args=[self.pk, os.path.basename(self.file.name).lower()])
|
||||
|
|
|
@ -70,4 +70,3 @@ def associated_proposals(parser, token):
|
|||
{% associated_proposals as associated_proposals %}
|
||||
"""
|
||||
return AssociatedProposalsNode.handle_token(parser, token)
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# flake8: noqa
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
|
||||
|
|
|
@ -152,7 +152,8 @@ def proposal_speaker_manage(request, pk):
|
|||
[email_address], "speaker_invite",
|
||||
context=message_ctx
|
||||
)
|
||||
invitation, created = AdditionalSpeaker.objects.get_or_create(proposalbase=proposal.proposalbase_ptr, speaker=speaker)
|
||||
invitation, created = AdditionalSpeaker.objects.get_or_create(
|
||||
proposalbase=proposal.proposalbase_ptr, speaker=speaker)
|
||||
messages.success(request, "Speaker invited to proposal.")
|
||||
return redirect("proposal_speaker_manage", proposal.pk)
|
||||
else:
|
||||
|
@ -311,7 +312,8 @@ def proposal_leave(request, pk):
|
|||
@login_required
|
||||
def proposal_pending_join(request, pk):
|
||||
proposal = get_object_or_404(ProposalBase, pk=pk)
|
||||
speaking = get_object_or_404(AdditionalSpeaker, speaker=request.user.speaker_profile, proposalbase=proposal)
|
||||
speaking = get_object_or_404(AdditionalSpeaker, speaker=request.user.speaker_profile,
|
||||
proposalbase=proposal)
|
||||
if speaking.status == AdditionalSpeaker.SPEAKING_STATUS_PENDING:
|
||||
speaking.status = AdditionalSpeaker.SPEAKING_STATUS_ACCEPTED
|
||||
speaking.save()
|
||||
|
@ -324,7 +326,8 @@ def proposal_pending_join(request, pk):
|
|||
@login_required
|
||||
def proposal_pending_decline(request, pk):
|
||||
proposal = get_object_or_404(ProposalBase, pk=pk)
|
||||
speaking = get_object_or_404(AdditionalSpeaker, speaker=request.user.speaker_profile, proposalbase=proposal)
|
||||
speaking = get_object_or_404(AdditionalSpeaker, speaker=request.user.speaker_profile,
|
||||
proposalbase=proposal)
|
||||
if speaking.status == AdditionalSpeaker.SPEAKING_STATUS_PENDING:
|
||||
speaking.status = AdditionalSpeaker.SPEAKING_STATUS_DECLINED
|
||||
speaking.save()
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from django.contrib.contenttypes.models import ContentType
|
||||
|
||||
from symposion.proposals.models import ProposalSection
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
from django.core.management.base import BaseCommand
|
||||
|
||||
from django.contrib.auth.models import Group
|
||||
|
||||
from symposion.reviews.models import ProposalResult
|
||||
|
||||
|
||||
|
|
|
@ -12,4 +12,5 @@ class Command(BaseCommand):
|
|||
|
||||
for result in accepted_proposals:
|
||||
promote_proposal(result.proposal)
|
||||
connections["default"].cursor().execute("SELECT setval('schedule_session_id_seq', (SELECT max(id) FROM schedule_session))")
|
||||
connections["default"].cursor().execute(
|
||||
"SELECT setval('schedule_session_id_seq', (SELECT max(id) FROM schedule_session))")
|
||||
|
|
|
@ -152,7 +152,8 @@ class Review(models.Model):
|
|||
if self == latest:
|
||||
# self is the latest review; revert the latest vote to the
|
||||
# previous vote
|
||||
previous = user_reviews.filter(submitted_at__lt=self.submitted_at).order_by("-submitted_at")[0]
|
||||
previous = user_reviews.filter(submitted_at__lt=self.submitted_at)\
|
||||
.order_by("-submitted_at")[0]
|
||||
self.proposal.result.update_vote(self.vote, previous=previous.vote, removal=True)
|
||||
lv = LatestVote.objects.filter(proposal=self.proposal, user=self.user)
|
||||
lv.update(
|
||||
|
@ -303,7 +304,8 @@ class NotificationTemplate(models.Model):
|
|||
class ResultNotification(models.Model):
|
||||
|
||||
proposal = models.ForeignKey("proposals.ProposalBase", related_name="notifications")
|
||||
template = models.ForeignKey(NotificationTemplate, null=True, blank=True, on_delete=models.SET_NULL)
|
||||
template = models.ForeignKey(NotificationTemplate, null=True, blank=True,
|
||||
on_delete=models.SET_NULL)
|
||||
timestamp = models.DateTimeField(default=datetime.now)
|
||||
to_address = models.EmailField()
|
||||
from_address = models.EmailField()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from django import template
|
||||
|
||||
from symposion.reviews.models import Review, ReviewAssignment
|
||||
from symposion.reviews.models import ReviewAssignment
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# flake8: noqa
|
||||
from django.conf.urls.defaults import patterns, url
|
||||
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ def has_permission(user, proposal, speaker=False, reviewer=False):
|
|||
if user.is_superuser:
|
||||
return True
|
||||
if speaker:
|
||||
if (user == proposal.speaker.user or
|
||||
proposal.additional_speakers.filter(user=user).exists()):
|
||||
if user == proposal.speaker.user or \
|
||||
proposal.additional_speakers.filter(user=user).exists():
|
||||
return True
|
||||
if reviewer:
|
||||
if user.groups.filter(name="reviewers").exists():
|
||||
|
|
|
@ -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
|
||||
|
@ -62,8 +60,8 @@ def proposals_generator(request, queryset, user_pk=None, check_speaker=True):
|
|||
yield obj
|
||||
|
||||
|
||||
# Returns a list of all proposals, proposals reviewed by the user, or the proposals the user has yet to review
|
||||
# depending on the link user clicks in dashboard
|
||||
# Returns a list of all proposals, proposals reviewed by the user, or the proposals the user has
|
||||
# yet to review depending on the link user clicks in dashboard
|
||||
@login_required
|
||||
def review_section(request, section_slug, assigned=False, reviewed="all"):
|
||||
|
||||
|
@ -74,7 +72,8 @@ def review_section(request, section_slug, assigned=False, reviewed="all"):
|
|||
queryset = ProposalBase.objects.filter(kind__section=section)
|
||||
|
||||
if assigned:
|
||||
assignments = ReviewAssignment.objects.filter(user=request.user).values_list("proposal__id")
|
||||
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
|
||||
|
@ -99,6 +98,7 @@ def review_section(request, section_slug, assigned=False, reviewed="all"):
|
|||
|
||||
return render(request, "reviews/review_list.html", ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
def review_list(request, section_slug, user_pk):
|
||||
|
||||
|
@ -315,16 +315,26 @@ def review_status(request, section_slug=None, key=None):
|
|||
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"),
|
||||
# proposals with at least VOTE_THRESHOLD reviews and at least one -1 and no +1s, reverse sorted by the 'score'
|
||||
"negative": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD, result__minus_one__gt=0, result__plus_one=0).order_by("result__score"),
|
||||
# proposals with at least VOTE_THRESHOLD reviews and neither a +1 or a -1, sorted by total votes (lowest first)
|
||||
"indifferent": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD, result__minus_one=0, result__plus_one=0).order_by("result__vote_count"),
|
||||
# proposals with at least VOTE_THRESHOLD reviews and both a +1 and -1, sorted by total votes (highest first)
|
||||
"controversial": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD, result__plus_one__gt=0, result__minus_one__gt=0).order_by("-result__vote_count"),
|
||||
# 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"),
|
||||
# proposals with at least VOTE_THRESHOLD reviews and at least one -1 and no +1s, reverse
|
||||
# sorted by the 'score'
|
||||
"negative": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD, result__minus_one__gt=0,
|
||||
result__plus_one=0).order_by("result__score"),
|
||||
# proposals with at least VOTE_THRESHOLD reviews and neither a +1 or a -1, sorted by total
|
||||
# votes (lowest first)
|
||||
"indifferent": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD, result__minus_one=0,
|
||||
result__plus_one=0).order_by("result__vote_count"),
|
||||
# proposals with at least VOTE_THRESHOLD reviews and both a +1 and -1, sorted by total
|
||||
# votes (highest first)
|
||||
"controversial": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD,
|
||||
result__plus_one__gt=0, result__minus_one__gt=0)
|
||||
.order_by("-result__vote_count"),
|
||||
# proposals with fewer than VOTE_THRESHOLD reviews
|
||||
"too_few": queryset.filter(result__vote_count__lt=VOTE_THRESHOLD).order_by("result__vote_count"),
|
||||
"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)
|
||||
|
@ -332,7 +342,8 @@ def review_status(request, section_slug=None, key=None):
|
|||
for status in proposals:
|
||||
if key and key != status:
|
||||
continue
|
||||
proposals[status] = list(proposals_generator(request, proposals[status], check_speaker=not admin))
|
||||
proposals[status] = list(proposals_generator(request, proposals[status],
|
||||
check_speaker=not admin))
|
||||
|
||||
if key:
|
||||
ctx.update({
|
||||
|
@ -361,14 +372,13 @@ def review_assignments(request):
|
|||
@login_required
|
||||
@require_POST
|
||||
def review_assignment_opt_out(request, pk):
|
||||
review_assignment = get_object_or_404(ReviewAssignment,
|
||||
pk=pk,
|
||||
user=request.user
|
||||
)
|
||||
review_assignment = get_object_or_404(
|
||||
ReviewAssignment, pk=pk, user=request.user)
|
||||
if not review_assignment.opted_out:
|
||||
review_assignment.opted_out = True
|
||||
review_assignment.save()
|
||||
ReviewAssignment.create_assignments(review_assignment.proposal, origin=ReviewAssignment.AUTO_ASSIGNED_LATER)
|
||||
ReviewAssignment.create_assignments(
|
||||
review_assignment.proposal, origin=ReviewAssignment.AUTO_ASSIGNED_LATER)
|
||||
return redirect("review_assignments")
|
||||
|
||||
|
||||
|
@ -398,7 +408,9 @@ 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()
|
||||
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 = {
|
||||
|
|
|
@ -2,7 +2,6 @@ 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
|
||||
|
@ -127,7 +126,8 @@ class Presentation(models.Model):
|
|||
description = MarkupField()
|
||||
abstract = MarkupField()
|
||||
speaker = models.ForeignKey("speakers.Speaker", related_name="presentations")
|
||||
additional_speakers = models.ManyToManyField("speakers.Speaker", related_name="copresentations", blank=True)
|
||||
additional_speakers = models.ManyToManyField("speakers.Speaker", related_name="copresentations",
|
||||
blank=True)
|
||||
cancelled = models.BooleanField(default=False)
|
||||
proposal_base = models.OneToOneField(ProposalBase, related_name="presentation")
|
||||
section = models.ForeignKey(Section, related_name="presentations")
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import itertools
|
||||
import operator
|
||||
|
||||
from django.db.models import Count, Min
|
||||
|
||||
|
@ -19,7 +18,8 @@ class TimeTable(object):
|
|||
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.filter(
|
||||
pk__in=SlotRoom.objects.filter(slot__in=self.slots_qs().values("pk")).values("room"))
|
||||
qs = qs.order_by("order")
|
||||
return qs
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# flake8: noqa
|
||||
from django.conf.urls.defaults import url, patterns
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -5,5 +5,4 @@ from symposion.speakers.models import Speaker
|
|||
|
||||
admin.site.register(Speaker,
|
||||
list_display=["name", "email", "created"],
|
||||
search_fields = ["name"],
|
||||
)
|
||||
search_fields=["name"])
|
||||
|
|
|
@ -19,8 +19,8 @@ def speakers():
|
|||
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.",
|
||||
biography=("I wrote Ruby, and named it after the rare gem Ruby, a pun "
|
||||
"on Perl/pearl."),
|
||||
)
|
||||
Speaker.objects.create(
|
||||
user=larry,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
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
|
||||
|
||||
|
|
|
@ -16,8 +16,12 @@ class Speaker(models.Model):
|
|||
]
|
||||
|
||||
user = models.OneToOneField(User, null=True, related_name="speaker_profile")
|
||||
name = models.CharField(max_length=100, help_text="As you would like it to appear in the conference program.")
|
||||
biography = MarkupField(blank=True, help_text="A little bit about you. Edit using <a href='http://warpedvisions.org/projects/markdown-cheat-sheet/' target='_blank'>Markdown</a>.")
|
||||
name = models.CharField(max_length=100, help_text=("As you would like it to appear in the "
|
||||
"conference program."))
|
||||
biography = MarkupField(blank=True, help_text=("A little bit about you. Edit using "
|
||||
"<a href='http://warpedvisions.org/projects/"
|
||||
"markdown-cheat-sheet/target='_blank'>"
|
||||
"Markdown</a>."))
|
||||
photo = models.ImageField(upload_to="speaker_photos", blank=True)
|
||||
annotation = models.TextField() # staff only
|
||||
invite_email = models.CharField(max_length=200, unique=True, null=True, db_index=True)
|
||||
|
@ -36,7 +40,6 @@ class Speaker(models.Model):
|
|||
else:
|
||||
return "?"
|
||||
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse("speaker_edit")
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# flake8: noqa
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
|
||||
|
|
|
@ -88,8 +88,8 @@ def speaker_create_token(request, token):
|
|||
).update(
|
||||
speaker=existing_speaker
|
||||
)
|
||||
messages.info(request, "You have been associated with all pending "
|
||||
"talk proposals")
|
||||
messages.info(request, ("You have been associated with all pending "
|
||||
"talk proposals"))
|
||||
return redirect("dashboard")
|
||||
else:
|
||||
if not request.user.is_authenticated():
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from symposion.sponsorship.models import SponsorLevel, Sponsor, Benefit, BenefitLevel, SponsorBenefit
|
||||
from symposion.sponsorship.models import SponsorLevel, Sponsor, Benefit, BenefitLevel, \
|
||||
SponsorBenefit
|
||||
|
||||
|
||||
class BenefitLevelInline(admin.TabularInline):
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
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):
|
||||
|
|
|
@ -35,7 +35,8 @@ class SponsorLevel(models.Model):
|
|||
|
||||
class Sponsor(models.Model):
|
||||
|
||||
applicant = models.ForeignKey(User, related_name="sponsorships", verbose_name=_("applicant"), null=True)
|
||||
applicant = models.ForeignKey(User, related_name="sponsorships", verbose_name=_("applicant"),
|
||||
null=True)
|
||||
|
||||
name = models.CharField(_("Sponsor Name"), max_length=100)
|
||||
external_url = models.URLField(_("external URL"))
|
||||
|
@ -47,7 +48,8 @@ class Sponsor(models.Model):
|
|||
active = models.BooleanField(_("active"), default=False)
|
||||
|
||||
# Denormalization (this assumes only one logo)
|
||||
sponsor_logo = models.ForeignKey("SponsorBenefit", related_name="+", null=True, blank=True, editable=False)
|
||||
sponsor_logo = models.ForeignKey("SponsorBenefit", related_name="+", null=True, blank=True,
|
||||
editable=False)
|
||||
|
||||
objects = SponsorManager()
|
||||
|
||||
|
@ -66,7 +68,8 @@ class Sponsor(models.Model):
|
|||
@property
|
||||
def website_logo(self):
|
||||
if self.sponsor_logo is None:
|
||||
benefits = self.sponsor_benefits.filter(benefit__type="weblogo", upload__isnull=False)[:1]
|
||||
benefits = self.sponsor_benefits.filter(
|
||||
benefit__type="weblogo", upload__isnull=False)[:1]
|
||||
if benefits.count():
|
||||
if benefits[0].upload:
|
||||
self.sponsor_logo = benefits[0]
|
||||
|
@ -120,7 +123,8 @@ class Sponsor(models.Model):
|
|||
|
||||
# Any remaining sponsor benefits that don't normally belong to
|
||||
# this level are set to inactive
|
||||
self.sponsor_benefits.exclude(pk__in=allowed_benefits).update(active=False, max_words=None, other_limits="")
|
||||
self.sponsor_benefits.exclude(pk__in=allowed_benefits)\
|
||||
.update(active=False, max_words=None, other_limits="")
|
||||
|
||||
def send_coordinator_emails(self):
|
||||
pass # @@@ should this just be done centrally?
|
||||
|
@ -150,7 +154,8 @@ class Benefit(models.Model):
|
|||
|
||||
name = models.CharField(_("name"), max_length=100)
|
||||
description = models.TextField(_("description"), blank=True)
|
||||
type = models.CharField(_("type"), choices=BENEFIT_TYPE_CHOICES, max_length=10, default="simple")
|
||||
type = models.CharField(_("type"), choices=BENEFIT_TYPE_CHOICES, max_length=10,
|
||||
default="simple")
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
|
|
@ -30,9 +30,12 @@ class SponsorsNode(template.Node):
|
|||
conference = current_conference()
|
||||
if self.level:
|
||||
level = self.level.resolve(context)
|
||||
queryset = Sponsor.objects.filter(level__conference = conference, level__name__iexact = level, active = True).order_by("added")
|
||||
queryset = Sponsor.objects.filter(
|
||||
level__conference=conference, level__name__iexact=level, active=True)\
|
||||
.order_by("added")
|
||||
else:
|
||||
queryset = Sponsor.objects.filter(level__conference = conference, active = True).order_by("level__order", "added")
|
||||
queryset = Sponsor.objects.filter(level__conference=conference, active=True)\
|
||||
.order_by("level__order", "added")
|
||||
context[self.context_var] = queryset
|
||||
return u""
|
||||
|
||||
|
@ -72,4 +75,3 @@ def sponsor_levels(parser, token):
|
|||
{% sponsor_levels as levels %}
|
||||
"""
|
||||
return SponsorLevelNode.handle_token(parser, token)
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
# flake8: noqa
|
||||
from django.conf.urls.defaults import patterns, url
|
||||
from django.views.generic.simple import direct_to_template
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@ from django.template import RequestContext
|
|||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
from symposion.sponsorship.forms import SponsorApplicationForm, SponsorDetailsForm, SponsorBenefitsFormSet
|
||||
from symposion.sponsorship.forms import SponsorApplicationForm, SponsorDetailsForm, \
|
||||
SponsorBenefitsFormSet
|
||||
from symposion.sponsorship.models import Sponsor, SponsorBenefit
|
||||
|
||||
|
||||
|
|
|
@ -5,8 +5,7 @@ import reversion
|
|||
from symposion.teams.models import Team, Membership
|
||||
|
||||
admin.site.register(Team,
|
||||
prepopulated_fields={"slug": ("name",)},
|
||||
)
|
||||
prepopulated_fields={"slug": ("name",)})
|
||||
|
||||
|
||||
class MembershipAdmin(reversion.VersionAdmin):
|
||||
|
|
|
@ -10,7 +10,8 @@ from symposion.teams.models import Membership
|
|||
|
||||
class TeamInvitationForm(forms.Form):
|
||||
|
||||
email = forms.EmailField(help_text="email address must be that of an account on this conference site")
|
||||
email = forms.EmailField(help_text=("email address must be that of an account on this "
|
||||
"conference site"))
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.team = kwargs.pop("team")
|
||||
|
@ -28,7 +29,9 @@ class TeamInvitationForm(forms.Form):
|
|||
except User.DoesNotExist:
|
||||
# eventually we can invite them but for now assume they are
|
||||
# already on the site
|
||||
raise forms.ValidationError(mark_safe("no account with email address <b>%s</b> found on this conference site" % escape(email)))
|
||||
raise forms.ValidationError(
|
||||
mark_safe("no account with email address <b>%s</b> found on this conference "
|
||||
"site" % escape(email)))
|
||||
|
||||
state = self.team.get_state_for_user(user)
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@ class Team(models.Model):
|
|||
permissions = models.ManyToManyField(Permission, blank=True, related_name="member_teams")
|
||||
|
||||
# manager permissions
|
||||
manager_permissions = models.ManyToManyField(Permission, blank=True, related_name="manager_teams")
|
||||
manager_permissions = models.ManyToManyField(Permission, blank=True,
|
||||
related_name="manager_teams")
|
||||
|
||||
created = models.DateTimeField(default=datetime.datetime.now, editable=False)
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# flake8: noqa
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ from symposion.teams.forms import TeamInvitationForm
|
|||
from symposion.teams.models import Team, Membership
|
||||
|
||||
|
||||
## perm checks
|
||||
# perm checks
|
||||
#
|
||||
# @@@ these can be moved
|
||||
|
||||
|
@ -50,7 +50,7 @@ def can_invite(team, user):
|
|||
return False
|
||||
|
||||
|
||||
## views
|
||||
# views
|
||||
|
||||
|
||||
@login_required
|
||||
|
|
Loading…
Reference in a new issue