Merge pull request #56 from chromano/master

Fix flake8 warnings
This commit is contained in:
Patrick Altman 2014-07-30 16:16:03 -05:00
commit 6d5c24e635
66 changed files with 611 additions and 604 deletions

View file

@ -1,5 +1,3 @@
import datetime
from django.db import models from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User

View file

@ -1,10 +1,5 @@
from django import template from django import template
from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import reverse 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.models import Box
from symposion.boxes.forms import BoxForm from symposion.boxes.forms import BoxForm

View file

@ -1,3 +1,4 @@
# flake8: noqa
from django.conf.urls.defaults import url, patterns from django.conf.urls.defaults import url, patterns

View file

@ -7,7 +7,8 @@ from symposion.boxes.forms import BoxForm
from symposion.boxes.models import Box 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): def get_auth_vars(request):
auth_vars = {} auth_vars = {}
if request.method == "POST": if request.method == "POST":

View file

@ -4,6 +4,7 @@ import reversion
from .models import Page from .models import Page
class PageAdmin(reversion.VersionAdmin): class PageAdmin(reversion.VersionAdmin):
pass pass

View file

@ -2,6 +2,7 @@ from datetime import datetime
from django.db import models from django.db import models
class PublishedPageManager(models.Manager): class PublishedPageManager(models.Manager):
def get_query_set(self): def get_query_set(self):

View file

@ -53,7 +53,8 @@ class Page(models.Model):
def clean_fields(self, exclude=None): def clean_fields(self, exclude=None):
super(Page, self).clean_fields(exclude) super(Page, self).clean_fields(exclude)
if not re.match(settings.SYMPOSION_PAGE_REGEX, self.path): 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) reversion.register(Page)

View file

@ -1,3 +1,4 @@
# flake8: noqa
from django.conf.urls.defaults import url, patterns from django.conf.urls.defaults import url, patterns
PAGE_RE = r"(([\w-]{1,})(/[\w-]{1,})*)/" PAGE_RE = r"(([\w-]{1,})(/[\w-]{1,})*)/"

View file

@ -1,5 +1,3 @@
from django.conf import settings
from appconf import AppConf from appconf import AppConf

View file

@ -6,6 +6,6 @@ from symposion.conference.models import Conference, Section
admin.site.register(Conference, list_display=("title", "start_date", "end_date")) admin.site.register(Conference, list_display=("title", "start_date", "end_date"))
admin.site.register( admin.site.register(
Section, Section,
prepopulated_fields = {"slug": ("name",)}, prepopulated_fields={"slug": ("name",)},
list_display = ("name", "conference", "start_date", "end_date") list_display=("name", "conference", "start_date", "end_date")
) )

View file

@ -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", urlpatterns = patterns("symposion.conference.views",

View file

@ -26,5 +26,6 @@ class SignupForm(account.forms.SignupForm):
email_confirm = self.cleaned_data["email_confirm"] email_confirm = self.cleaned_data["email_confirm"]
if email: if email:
if email != email_confirm: 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 return email_confirm

View file

@ -1,4 +1,3 @@
import html5lib
from html5lib import html5parser, sanitizer from html5lib import html5parser, sanitizer
import markdown import markdown

View file

@ -3,9 +3,8 @@ import csv
from django.http import HttpResponse from django.http import HttpResponse
def export_as_csv_action( def export_as_csv_action(description="Export selected objects as CSV file",
description="Export selected objects as CSV file", fields=None, exclude=None, header=True):
fields=None, exclude=None, header=True):
""" """
This function returns an export csv action This function returns an export csv action
'fields' and 'exclude' work like in Django ModelForm 'fields' and 'exclude' work like in Django ModelForm
@ -24,12 +23,14 @@ def export_as_csv_action(
excludeset = set(exclude) excludeset = set(exclude)
field_names = field_names - excludeset field_names = field_names - excludeset
response = HttpResponse(mimetype="text/csv") 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) writer = csv.writer(response)
if header: if header:
writer.writerow(list(field_names)) writer.writerow(list(field_names))
for obj in queryset: 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 return response
export_as_csv.short_description = description export_as_csv.short_description = description
return export_as_csv return export_as_csv

View file

@ -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)

View file

@ -85,22 +85,29 @@ class ProposalBase(models.Model):
description = models.TextField( description = models.TextField(
_("Brief Description"), _("Brief Description"),
max_length=400, # @@@ need to enforce 400 in UI 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( abstract = MarkupField(
_("Detailed Abstract"), _("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( additional_notes = MarkupField(
blank=True, 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( submitted = models.DateTimeField(
default=datetime.datetime.now, default=datetime.datetime.now,
editable=False, editable=False,
) )
speaker = models.ForeignKey("speakers.Speaker", related_name="proposals") 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) cancelled = models.BooleanField(default=False)
def can_edit(self): def can_edit(self):
@ -120,7 +127,9 @@ class ProposalBase(models.Model):
def speakers(self): def speakers(self):
yield self.speaker 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 yield speaker
def notification_email_context(self): def notification_email_context(self):
@ -172,4 +181,5 @@ class SupportingDocument(models.Model):
description = models.CharField(max_length=140) description = models.CharField(max_length=140)
def download_url(self): 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()])

View file

@ -70,4 +70,3 @@ def associated_proposals(parser, token):
{% associated_proposals as associated_proposals %} {% associated_proposals as associated_proposals %}
""" """
return AssociatedProposalsNode.handle_token(parser, token) return AssociatedProposalsNode.handle_token(parser, token)

View file

@ -1,3 +1,4 @@
# flake8: noqa
from django.conf.urls.defaults import * from django.conf.urls.defaults import *

View file

@ -135,13 +135,13 @@ def proposal_speaker_manage(request, pk):
# fire off email to user to create profile # fire off email to user to create profile
send_email( send_email(
[email_address], "speaker_no_profile", [email_address], "speaker_no_profile",
context = message_ctx context=message_ctx
) )
else: else:
# fire off email to user letting them they are loved. # fire off email to user letting them they are loved.
send_email( send_email(
[email_address], "speaker_addition", [email_address], "speaker_addition",
context = message_ctx context=message_ctx
) )
else: else:
speaker, token = create_speaker_token(email_address) speaker, token = create_speaker_token(email_address)
@ -150,9 +150,10 @@ def proposal_speaker_manage(request, pk):
# account and speaker profile # account and speaker profile
send_email( send_email(
[email_address], "speaker_invite", [email_address], "speaker_invite",
context = message_ctx 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.") messages.success(request, "Speaker invited to proposal.")
return redirect("proposal_speaker_manage", proposal.pk) return redirect("proposal_speaker_manage", proposal.pk)
else: else:
@ -311,7 +312,8 @@ def proposal_leave(request, pk):
@login_required @login_required
def proposal_pending_join(request, pk): def proposal_pending_join(request, pk):
proposal = get_object_or_404(ProposalBase, pk=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: if speaking.status == AdditionalSpeaker.SPEAKING_STATUS_PENDING:
speaking.status = AdditionalSpeaker.SPEAKING_STATUS_ACCEPTED speaking.status = AdditionalSpeaker.SPEAKING_STATUS_ACCEPTED
speaking.save() speaking.save()
@ -324,7 +326,8 @@ def proposal_pending_join(request, pk):
@login_required @login_required
def proposal_pending_decline(request, pk): def proposal_pending_decline(request, pk):
proposal = get_object_or_404(ProposalBase, pk=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: if speaking.status == AdditionalSpeaker.SPEAKING_STATUS_PENDING:
speaking.status = AdditionalSpeaker.SPEAKING_STATUS_DECLINED speaking.status = AdditionalSpeaker.SPEAKING_STATUS_DECLINED
speaking.save() speaking.save()

View file

@ -1,5 +1,3 @@
from django.contrib.contenttypes.models import ContentType
from symposion.proposals.models import ProposalSection from symposion.proposals.models import ProposalSection

View file

@ -9,13 +9,13 @@ class ReviewForm(forms.ModelForm):
class Meta: class Meta:
model = Review model = Review
fields = ["vote", "comment"] fields = ["vote", "comment"]
widgets = { "comment": MarkItUpWidget() } widgets = {"comment": MarkItUpWidget()}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ReviewForm, self).__init__(*args, **kwargs) super(ReviewForm, self).__init__(*args, **kwargs)
self.fields["vote"] = forms.ChoiceField( self.fields["vote"] = forms.ChoiceField(
widget = forms.RadioSelect(), widget=forms.RadioSelect(),
choices = VOTES.CHOICES choices=VOTES.CHOICES
) )
@ -23,14 +23,14 @@ class ReviewCommentForm(forms.ModelForm):
class Meta: class Meta:
model = Comment model = Comment
fields = ["text"] fields = ["text"]
widgets = { "text": MarkItUpWidget() } widgets = {"text": MarkItUpWidget()}
class SpeakerCommentForm(forms.ModelForm): class SpeakerCommentForm(forms.ModelForm):
class Meta: class Meta:
model = ProposalMessage model = ProposalMessage
fields = ["message"] fields = ["message"]
widgets = { "message": MarkItUpWidget() } widgets = {"message": MarkItUpWidget()}
class BulkPresentationForm(forms.Form): class BulkPresentationForm(forms.Form):

View file

@ -1,8 +1,3 @@
import csv
import os
import random
from django.contrib.auth import models
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from symposion.reviews.models import ReviewAssignment from symposion.reviews.models import ReviewAssignment

View file

@ -1,7 +1,5 @@
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.contrib.auth.models import Group
from symposion.reviews.models import ProposalResult from symposion.reviews.models import ProposalResult

View file

@ -12,4 +12,5 @@ class Command(BaseCommand):
for result in accepted_proposals: for result in accepted_proposals:
promote_proposal(result.proposal) 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))")

View file

@ -117,11 +117,11 @@ class Review(models.Model):
def save(self, **kwargs): def save(self, **kwargs):
if self.vote: if self.vote:
vote, created = LatestVote.objects.get_or_create( vote, created = LatestVote.objects.get_or_create(
proposal = self.proposal, proposal=self.proposal,
user = self.user, user=self.user,
defaults = dict( defaults=dict(
vote = self.vote, vote=self.vote,
submitted_at = self.submitted_at, submitted_at=self.submitted_at,
) )
) )
if not created: if not created:
@ -152,7 +152,8 @@ class Review(models.Model):
if self == latest: if self == latest:
# self is the latest review; revert the latest vote to the # self is the latest review; revert the latest vote to the
# previous vote # 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) self.proposal.result.update_vote(self.vote, previous=previous.vote, removal=True)
lv = LatestVote.objects.filter(proposal=self.proposal, user=self.user) lv = LatestVote.objects.filter(proposal=self.proposal, user=self.user)
lv.update( lv.update(
@ -231,20 +232,20 @@ class ProposalResult(models.Model):
result.comment_count = Review.objects.filter(proposal=proposal).count() result.comment_count = Review.objects.filter(proposal=proposal).count()
result.vote_count = LatestVote.objects.filter(proposal=proposal).count() result.vote_count = LatestVote.objects.filter(proposal=proposal).count()
result.plus_one = LatestVote.objects.filter( result.plus_one = LatestVote.objects.filter(
proposal = proposal, proposal=proposal,
vote = VOTES.PLUS_ONE vote=VOTES.PLUS_ONE
).count() ).count()
result.plus_zero = LatestVote.objects.filter( result.plus_zero = LatestVote.objects.filter(
proposal = proposal, proposal=proposal,
vote = VOTES.PLUS_ZERO vote=VOTES.PLUS_ZERO
).count() ).count()
result.minus_zero = LatestVote.objects.filter( result.minus_zero = LatestVote.objects.filter(
proposal = proposal, proposal=proposal,
vote = VOTES.MINUS_ZERO vote=VOTES.MINUS_ZERO
).count() ).count()
result.minus_one = LatestVote.objects.filter( result.minus_one = LatestVote.objects.filter(
proposal = proposal, proposal=proposal,
vote = VOTES.MINUS_ONE vote=VOTES.MINUS_ONE
).count() ).count()
result.save() result.save()
cls._default_manager.filter(pk=result.pk).update(score=ProposalScoreExpression()) cls._default_manager.filter(pk=result.pk).update(score=ProposalScoreExpression())
@ -303,7 +304,8 @@ class NotificationTemplate(models.Model):
class ResultNotification(models.Model): class ResultNotification(models.Model):
proposal = models.ForeignKey("proposals.ProposalBase", related_name="notifications") 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) timestamp = models.DateTimeField(default=datetime.now)
to_address = models.EmailField() to_address = models.EmailField()
from_address = models.EmailField() from_address = models.EmailField()
@ -321,12 +323,12 @@ def promote_proposal(proposal):
presentation = proposal.presentation presentation = proposal.presentation
else: else:
presentation = Presentation( presentation = Presentation(
title = proposal.title, title=proposal.title,
description = proposal.description, description=proposal.description,
abstract = proposal.abstract, abstract=proposal.abstract,
speaker = proposal.speaker, speaker=proposal.speaker,
section = proposal.section, section=proposal.section,
proposal_base = proposal, proposal_base=proposal,
) )
presentation.save() presentation.save()
for speaker in proposal.additional_speakers.all(): for speaker in proposal.additional_speakers.all():

View file

@ -1,6 +1,6 @@
from django import template from django import template
from symposion.reviews.models import Review, ReviewAssignment from symposion.reviews.models import ReviewAssignment
register = template.Library() register = template.Library()

View file

@ -1,3 +1,4 @@
# flake8: noqa
from django.conf.urls.defaults import patterns, url from django.conf.urls.defaults import patterns, url

View file

@ -10,8 +10,8 @@ def has_permission(user, proposal, speaker=False, reviewer=False):
if user.is_superuser: if user.is_superuser:
return True return True
if speaker: if speaker:
if (user == proposal.speaker.user or if user == proposal.speaker.user or \
proposal.additional_speakers.filter(user=user).exists()): proposal.additional_speakers.filter(user=user).exists():
return True return True
if reviewer: if reviewer:
if user.groups.filter(name="reviewers").exists(): if user.groups.filter(name="reviewers").exists():

View file

@ -1,5 +1,3 @@
import re
from django.core.mail import send_mass_mail from django.core.mail import send_mass_mail
from django.db.models import Q from django.db.models import Q
from django.http import HttpResponseBadRequest, HttpResponseNotAllowed from django.http import HttpResponseBadRequest, HttpResponseNotAllowed
@ -62,8 +60,8 @@ def proposals_generator(request, queryset, user_pk=None, check_speaker=True):
yield obj yield obj
# Returns a list of all proposals, proposals reviewed by the user, or the proposals the user has yet to review # Returns a list of all proposals, proposals reviewed by the user, or the proposals the user has
# depending on the link user clicks in dashboard # yet to review depending on the link user clicks in dashboard
@login_required @login_required
def review_section(request, section_slug, assigned=False, reviewed="all"): 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) queryset = ProposalBase.objects.filter(kind__section=section)
if assigned: 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) queryset = queryset.filter(id__in=assignments)
# passing reviewed in from reviews.urls and out to review_list for # 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) return render(request, "reviews/review_list.html", ctx)
@login_required @login_required
def review_list(request, section_slug, user_pk): def review_list(request, section_slug, user_pk):
@ -142,20 +142,20 @@ def review_admin(request, section_slug):
user.comment_count = Review.objects.filter(user=user).count() user.comment_count = Review.objects.filter(user=user).count()
user.total_votes = LatestVote.objects.filter(user=user).count() user.total_votes = LatestVote.objects.filter(user=user).count()
user.plus_one = LatestVote.objects.filter( user.plus_one = LatestVote.objects.filter(
user = user, user=user,
vote = LatestVote.VOTES.PLUS_ONE vote=LatestVote.VOTES.PLUS_ONE
).count() ).count()
user.plus_zero = LatestVote.objects.filter( user.plus_zero = LatestVote.objects.filter(
user = user, user=user,
vote = LatestVote.VOTES.PLUS_ZERO vote=LatestVote.VOTES.PLUS_ZERO
).count() ).count()
user.minus_zero = LatestVote.objects.filter( user.minus_zero = LatestVote.objects.filter(
user = user, user=user,
vote = LatestVote.VOTES.MINUS_ZERO vote=LatestVote.VOTES.MINUS_ZERO
).count() ).count()
user.minus_one = LatestVote.objects.filter( user.minus_one = LatestVote.objects.filter(
user = user, user=user,
vote = LatestVote.VOTES.MINUS_ONE vote=LatestVote.VOTES.MINUS_ONE
).count() ).count()
yield user yield user
@ -222,7 +222,7 @@ def review_detail(request, pk):
} }
send_email( send_email(
[speaker.email], "proposal_new_message", [speaker.email], "proposal_new_message",
context = ctx context=ctx
) )
return redirect(request.path) return redirect(request.path)
@ -315,16 +315,26 @@ def review_status(request, section_slug=None, key=None):
queryset = queryset.filter(kind__section__slug=section_slug) queryset = queryset.filter(kind__section__slug=section_slug)
proposals = { proposals = {
# proposals with at least VOTE_THRESHOLD reviews and at least one +1 and no -1s, sorted by the 'score' # proposals with at least VOTE_THRESHOLD reviews and at least one +1 and no -1s, sorted by
"positive": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD, result__plus_one__gt=0, result__minus_one=0).order_by("-result__score"), # the 'score'
# proposals with at least VOTE_THRESHOLD reviews and at least one -1 and no +1s, reverse sorted by the 'score' "positive": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD, result__plus_one__gt=0,
"negative": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD, result__minus_one__gt=0, result__plus_one=0).order_by("result__score"), result__minus_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) # proposals with at least VOTE_THRESHOLD reviews and at least one -1 and no +1s, reverse
"indifferent": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD, result__minus_one=0, result__plus_one=0).order_by("result__vote_count"), # sorted by the 'score'
# proposals with at least VOTE_THRESHOLD reviews and both a +1 and -1, sorted by total votes (highest first) "negative": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD, result__minus_one__gt=0,
"controversial": queryset.filter(result__vote_count__gte=VOTE_THRESHOLD, result__plus_one__gt=0, result__minus_one__gt=0).order_by("-result__vote_count"), 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 # 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) 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: for status in proposals:
if key and key != status: if key and key != status:
continue 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: if key:
ctx.update({ ctx.update({
@ -361,14 +372,13 @@ def review_assignments(request):
@login_required @login_required
@require_POST @require_POST
def review_assignment_opt_out(request, pk): def review_assignment_opt_out(request, pk):
review_assignment = get_object_or_404(ReviewAssignment, review_assignment = get_object_or_404(
pk=pk, ReviewAssignment, pk=pk, user=request.user)
user=request.user
)
if not review_assignment.opted_out: if not review_assignment.opted_out:
review_assignment.opted_out = True review_assignment.opted_out = True
review_assignment.save() 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") 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): if not request.user.has_perm("reviews.can_manage_%s" % section_slug):
return access_not_permitted(request) 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() notification_templates = NotificationTemplate.objects.all()
ctx = { ctx = {

View file

@ -2,7 +2,6 @@ from django.core.exceptions import ObjectDoesNotExist
from django.db import models from django.db import models
from markitup.fields import MarkupField from markitup.fields import MarkupField
from model_utils.managers import InheritanceManager
from symposion.proposals.models import ProposalBase from symposion.proposals.models import ProposalBase
from symposion.conference.models import Section from symposion.conference.models import Section
@ -127,7 +126,8 @@ class Presentation(models.Model):
description = MarkupField() description = MarkupField()
abstract = MarkupField() abstract = MarkupField()
speaker = models.ForeignKey("speakers.Speaker", related_name="presentations") 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) cancelled = models.BooleanField(default=False)
proposal_base = models.OneToOneField(ProposalBase, related_name="presentation") proposal_base = models.OneToOneField(ProposalBase, related_name="presentation")
section = models.ForeignKey(Section, related_name="presentations") section = models.ForeignKey(Section, related_name="presentations")

View file

@ -1,5 +1,4 @@
import itertools import itertools
import operator
from django.db.models import Count, Min from django.db.models import Count, Min
@ -19,7 +18,8 @@ class TimeTable(object):
def rooms(self): def rooms(self):
qs = Room.objects.all() qs = Room.objects.all()
qs = qs.filter(schedule=self.day.schedule) 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") qs = qs.order_by("order")
return qs return qs

View file

@ -1,3 +1,4 @@
# flake8: noqa
from django.conf.urls.defaults import url, patterns from django.conf.urls.defaults import url, patterns

View file

@ -1,4 +1,3 @@
from django.core.exceptions import ObjectDoesNotExist
from django.http import Http404, HttpResponse from django.http import Http404, HttpResponse
from django.shortcuts import render, get_object_or_404, redirect from django.shortcuts import render, get_object_or_404, redirect
from django.template import loader, Context from django.template import loader, Context

View file

@ -4,6 +4,5 @@ from symposion.speakers.models import Speaker
admin.site.register(Speaker, admin.site.register(Speaker,
list_display = ["name", "email", "created"], list_display=["name", "email", "created"],
search_fields = ["name"], search_fields=["name"])
)

View file

@ -19,8 +19,8 @@ def speakers():
Speaker.objects.create( Speaker.objects.create(
user=matz, user=matz,
name="Yukihiro Matsumoto", name="Yukihiro Matsumoto",
biography="I wrote Ruby, and named it after the rare gem Ruby, a pun " biography=("I wrote Ruby, and named it after the rare gem Ruby, a pun "
"on Perl/pearl.", "on Perl/pearl."),
) )
Speaker.objects.create( Speaker.objects.create(
user=larry, user=larry,

View file

@ -1,7 +1,7 @@
import csv import csv
import os import os
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand
from symposion.speakers.models import Speaker from symposion.speakers.models import Speaker

View file

@ -16,15 +16,19 @@ class Speaker(models.Model):
] ]
user = models.OneToOneField(User, null=True, related_name="speaker_profile") 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.") name = models.CharField(max_length=100, help_text=("As you would like it to appear in the "
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>.") "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) photo = models.ImageField(upload_to="speaker_photos", blank=True)
annotation = models.TextField() # staff only annotation = models.TextField() # staff only
invite_email = models.CharField(max_length=200, unique=True, null=True, db_index=True) invite_email = models.CharField(max_length=200, unique=True, null=True, db_index=True)
invite_token = models.CharField(max_length=40, db_index=True) invite_token = models.CharField(max_length=40, db_index=True)
created = models.DateTimeField( created = models.DateTimeField(
default = datetime.datetime.now, default=datetime.datetime.now,
editable = False editable=False
) )
class Meta: class Meta:
@ -36,7 +40,6 @@ class Speaker(models.Model):
else: else:
return "?" return "?"
def get_absolute_url(self): def get_absolute_url(self):
return reverse("speaker_edit") return reverse("speaker_edit")

View file

@ -1,3 +1,4 @@
# flake8: noqa
from django.conf.urls.defaults import * from django.conf.urls.defaults import *

View file

@ -88,8 +88,8 @@ def speaker_create_token(request, token):
).update( ).update(
speaker=existing_speaker speaker=existing_speaker
) )
messages.info(request, "You have been associated with all pending " messages.info(request, ("You have been associated with all pending "
"talk proposals") "talk proposals"))
return redirect("dashboard") return redirect("dashboard")
else: else:
if not request.user.is_authenticated(): if not request.user.is_authenticated():

View file

@ -1,6 +1,7 @@
from django.contrib import admin 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): class BenefitLevelInline(admin.TabularInline):

View file

@ -1,8 +1,6 @@
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.contrib.auth.models import Group from symposion.sponsorship.models import Sponsor, SponsorBenefit, SponsorLevel
from symposion.sponsorship.models import Sponsor, SponsorBenefit
class Command(BaseCommand): class Command(BaseCommand):

View file

@ -35,7 +35,8 @@ class SponsorLevel(models.Model):
class Sponsor(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) name = models.CharField(_("Sponsor Name"), max_length=100)
external_url = models.URLField(_("external URL")) external_url = models.URLField(_("external URL"))
@ -47,7 +48,8 @@ class Sponsor(models.Model):
active = models.BooleanField(_("active"), default=False) active = models.BooleanField(_("active"), default=False)
# Denormalization (this assumes only one logo) # 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() objects = SponsorManager()
@ -66,7 +68,8 @@ class Sponsor(models.Model):
@property @property
def website_logo(self): def website_logo(self):
if self.sponsor_logo is None: 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.count():
if benefits[0].upload: if benefits[0].upload:
self.sponsor_logo = benefits[0] self.sponsor_logo = benefits[0]
@ -120,7 +123,8 @@ class Sponsor(models.Model):
# Any remaining sponsor benefits that don't normally belong to # Any remaining sponsor benefits that don't normally belong to
# this level are set to inactive # 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): def send_coordinator_emails(self):
pass # @@@ should this just be done centrally? pass # @@@ should this just be done centrally?
@ -150,7 +154,8 @@ class Benefit(models.Model):
name = models.CharField(_("name"), max_length=100) name = models.CharField(_("name"), max_length=100)
description = models.TextField(_("description"), blank=True) 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): def __unicode__(self):
return self.name return self.name

View file

@ -30,9 +30,12 @@ class SponsorsNode(template.Node):
conference = current_conference() conference = current_conference()
if self.level: if self.level:
level = self.level.resolve(context) 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: 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 context[self.context_var] = queryset
return u"" return u""
@ -72,4 +75,3 @@ def sponsor_levels(parser, token):
{% sponsor_levels as levels %} {% sponsor_levels as levels %}
""" """
return SponsorLevelNode.handle_token(parser, token) return SponsorLevelNode.handle_token(parser, token)

View file

@ -1,3 +1,4 @@
# flake8: noqa
from django.conf.urls.defaults import patterns, url from django.conf.urls.defaults import patterns, url
from django.views.generic.simple import direct_to_template from django.views.generic.simple import direct_to_template

View file

@ -5,7 +5,8 @@ from django.template import RequestContext
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required 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 from symposion.sponsorship.models import Sponsor, SponsorBenefit

View file

@ -5,8 +5,7 @@ import reversion
from symposion.teams.models import Team, Membership from symposion.teams.models import Team, Membership
admin.site.register(Team, admin.site.register(Team,
prepopulated_fields={"slug": ("name",)}, prepopulated_fields={"slug": ("name",)})
)
class MembershipAdmin(reversion.VersionAdmin): class MembershipAdmin(reversion.VersionAdmin):

View file

@ -10,7 +10,8 @@ from symposion.teams.models import Membership
class TeamInvitationForm(forms.Form): 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): def __init__(self, *args, **kwargs):
self.team = kwargs.pop("team") self.team = kwargs.pop("team")
@ -28,7 +29,9 @@ class TeamInvitationForm(forms.Form):
except User.DoesNotExist: except User.DoesNotExist:
# eventually we can invite them but for now assume they are # eventually we can invite them but for now assume they are
# already on the site # 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) state = self.team.get_state_for_user(user)

View file

@ -25,7 +25,8 @@ class Team(models.Model):
permissions = models.ManyToManyField(Permission, blank=True, related_name="member_teams") permissions = models.ManyToManyField(Permission, blank=True, related_name="member_teams")
# manager permissions # 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) created = models.DateTimeField(default=datetime.datetime.now, editable=False)

View file

@ -1,3 +1,4 @@
# flake8: noqa
from django.conf.urls.defaults import * from django.conf.urls.defaults import *

View file

@ -10,7 +10,7 @@ from symposion.teams.forms import TeamInvitationForm
from symposion.teams.models import Team, Membership from symposion.teams.models import Team, Membership
## perm checks # perm checks
# #
# @@@ these can be moved # @@@ these can be moved
@ -50,7 +50,7 @@ def can_invite(team, user):
return False return False
## views # views
@login_required @login_required