Merge branch 'miurahr-i18n-all'

This commit is contained in:
Patrick Altman 2015-09-08 15:07:36 -05:00
commit d23363621b
25 changed files with 340 additions and 241 deletions

View file

@ -2,6 +2,7 @@ from __future__ import unicode_literals
from django.db import models from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.utils.encoding import python_2_unicode_compatible from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
import reversion import reversion
@ -11,17 +12,17 @@ from markitup.fields import MarkupField
@python_2_unicode_compatible @python_2_unicode_compatible
class Box(models.Model): class Box(models.Model):
label = models.CharField(max_length=100, db_index=True) label = models.CharField(max_length=100, db_index=True, verbose_name=_("Label"))
content = MarkupField(blank=True) content = MarkupField(blank=True)
created_by = models.ForeignKey(User, related_name="boxes") created_by = models.ForeignKey(User, related_name="boxes", verbose_name=_("Created by"))
last_updated_by = models.ForeignKey(User, related_name="updated_boxes") last_updated_by = models.ForeignKey(User, related_name="updated_boxes", verbose_name=_("Last updated by"))
def __str__(self): def __str__(self):
return self.label return self.label
class Meta: class Meta:
verbose_name_plural = "boxes" verbose_name = _("Box")
verbose_name_plural = _("Boxes")
reversion.register(Box) reversion.register(Box)

View file

@ -40,6 +40,10 @@ class Page(models.Model):
def __str__(self): def __str__(self):
return self.title return self.title
class Meta:
verbose_name = _("page")
verbose_name_plural = _("pages")
@models.permalink @models.permalink
def get_absolute_url(self): def get_absolute_url(self):
return ("cms_page", [self.path]) return ("cms_page", [self.path])

View file

@ -1,8 +1,9 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.apps import AppConfig from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class ConferenceConfig(AppConfig): class ConferenceConfig(AppConfig):
name = "symposion.conference" name = "symposion.conference"
label = "symposion_conference" label = "symposion_conference"
verbose_name = "Symposion Conference" verbose_name = _("Symposion Conference")

View file

@ -15,11 +15,11 @@ class Conference(models.Model):
the full conference for a specific year, e.g. US PyCon 2012. the full conference for a specific year, e.g. US PyCon 2012.
""" """
title = models.CharField(_("title"), max_length=100) title = models.CharField(_("Title"), max_length=100)
# when the conference runs # when the conference runs
start_date = models.DateField(_("start date"), null=True, blank=True) start_date = models.DateField(_("Start date"), null=True, blank=True)
end_date = models.DateField(_("end date"), null=True, blank=True) end_date = models.DateField(_("End date"), null=True, blank=True)
# timezone the conference is in # timezone the conference is in
timezone = TimeZoneField(blank=True, verbose_name=_("timezone")) timezone = TimeZoneField(blank=True, verbose_name=_("timezone"))
@ -53,14 +53,14 @@ class Section(models.Model):
scheduling process. scheduling process.
""" """
conference = models.ForeignKey(Conference, verbose_name=_("conference")) conference = models.ForeignKey(Conference, verbose_name=_("Conference"))
name = models.CharField(_("name"), max_length=100) name = models.CharField(_("Name"), max_length=100)
slug = models.SlugField() slug = models.SlugField(verbose_name=_("Slug"))
# when the section runs # when the section runs
start_date = models.DateField(_("start date"), null=True, blank=True) start_date = models.DateField(_("Start date"), null=True, blank=True)
end_date = models.DateField(_("end date"), null=True, blank=True) end_date = models.DateField(_("End date"), null=True, blank=True)
def __str__(self): def __str__(self):
return "%s %s" % (self.conference, self.name) return "%s %s" % (self.conference, self.name)

View file

@ -6,13 +6,14 @@ except ImportError:
from django import forms from django import forms
import account.forms import account.forms
from django.utils.translation import ugettext_lazy as _
class SignupForm(account.forms.SignupForm): class SignupForm(account.forms.SignupForm):
first_name = forms.CharField() first_name = forms.CharField(label=_("First name"))
last_name = forms.CharField() last_name = forms.CharField(label=_("Last name"))
email_confirm = forms.EmailField(label="Confirm Email") email_confirm = forms.EmailField(label=_("Confirm Email"))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(SignupForm, self).__init__(*args, **kwargs) super(SignupForm, self).__init__(*args, **kwargs)
@ -32,7 +33,7 @@ class SignupForm(account.forms.SignupForm):
if email: if email:
if email != email_confirm: if email != email_confirm:
raise forms.ValidationError( raise forms.ValidationError(
"Email address must match previously typed email address") _("Email address must match previously typed email address"))
return email_confirm return email_confirm

View file

@ -2,10 +2,11 @@ from __future__ import unicode_literals
import csv import csv
from django.http import HttpResponse from django.http import HttpResponse
from django.utils.translation import ugettext_lazy as _
def export_as_csv_action(description="Export selected objects as CSV file", def export_as_csv_action(description=None, fields=None, exclude=None,
fields=None, exclude=None, header=True): 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
@ -32,5 +33,7 @@ def export_as_csv_action(description="Export selected objects as CSV file",
writer.writerow( writer.writerow(
[unicode(getattr(obj, field)).encode("utf-8", "replace") for field in field_names]) [unicode(getattr(obj, field)).encode("utf-8", "replace") for field in field_names])
return response return response
if description is None:
description = _("Export selected objects as CSV file")
export_as_csv.short_description = description export_as_csv.short_description = description
return export_as_csv return export_as_csv

View file

@ -1,8 +1,9 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.apps import AppConfig from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class ProposalsConfig(AppConfig): class ProposalsConfig(AppConfig):
name = "symposion.proposals" name = "symposion.proposals"
label = "symposion_proposals" label = "symposion_proposals"
verbose_name = "Symposion Proposals" verbose_name = _("Symposion Proposals")

View file

@ -1,6 +1,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django import forms from django import forms
from django.db.models import Q from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
from symposion.proposals.models import SupportingDocument from symposion.proposals.models import SupportingDocument
# from markitup.widgets import MarkItUpWidget # from markitup.widgets import MarkItUpWidget
@ -12,7 +13,7 @@ from symposion.proposals.models import SupportingDocument
class AddSpeakerForm(forms.Form): class AddSpeakerForm(forms.Form):
email = forms.EmailField( email = forms.EmailField(
label="Email address of new speaker (use their email address, not yours)" label=_("Email address of new speaker (use their email address, not yours)")
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -27,7 +28,7 @@ class AddSpeakerForm(forms.Form):
).exists() ).exists()
if exists: if exists:
raise forms.ValidationError( raise forms.ValidationError(
"This email address has already been invited to your talk proposal" _("This email address has already been invited to your talk proposal")
) )
return value return value

View file

@ -34,12 +34,12 @@ class ProposalSection(models.Model):
* closed is NULL or False * closed is NULL or False
""" """
section = models.OneToOneField(Section) section = models.OneToOneField(Section, verbose_name=_("Section"))
start = models.DateTimeField(null=True, blank=True) start = models.DateTimeField(null=True, blank=True, verbose_name=_("Start"))
end = models.DateTimeField(null=True, blank=True) end = models.DateTimeField(null=True, blank=True, verbose_name=_("End"))
closed = models.NullBooleanField() closed = models.NullBooleanField(verbose_name=_("Closed"))
published = models.NullBooleanField() published = models.NullBooleanField(verbose_name=_("Published"))
@classmethod @classmethod
def available(cls): def available(cls):
@ -71,10 +71,10 @@ class ProposalKind(models.Model):
to distinguish the section as well as the kind. to distinguish the section as well as the kind.
""" """
section = models.ForeignKey(Section, related_name="proposal_kinds") section = models.ForeignKey(Section, related_name="proposal_kinds", verbose_name=_("Section"))
name = models.CharField(_("Name"), max_length=100) name = models.CharField(_("Name"), max_length=100)
slug = models.SlugField() slug = models.SlugField(verbose_name=_("Slug"))
def __str__(self): def __str__(self):
return self.name return self.name
@ -85,9 +85,9 @@ class ProposalBase(models.Model):
objects = InheritanceManager() objects = InheritanceManager()
kind = models.ForeignKey(ProposalKind) kind = models.ForeignKey(ProposalKind, verbose_name=_("Kind"))
title = models.CharField(max_length=100) title = models.CharField(max_length=100, verbose_name=_("Title"))
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
@ -101,6 +101,7 @@ class ProposalBase(models.Model):
"target='_blank'>Markdown</a>.") "target='_blank'>Markdown</a>.")
) )
additional_notes = MarkupField( additional_notes = MarkupField(
_("Addtional Notes"),
blank=True, blank=True,
help_text=_("Anything else you'd like the program committee to know when making their " 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 " "selection: your past experience, etc. This is not made public. Edit using "
@ -110,8 +111,9 @@ class ProposalBase(models.Model):
submitted = models.DateTimeField( submitted = models.DateTimeField(
default=now, default=now,
editable=False, editable=False,
verbose_name=_("Submitted")
) )
speaker = models.ForeignKey(Speaker, related_name="proposals") speaker = models.ForeignKey(Speaker, related_name="proposals", verbose_name=_("Speaker"))
def additional_speaker_validator(self, a_speaker): def additional_speaker_validator(self, a_speaker):
if a_speaker.speaker.email == self.speaker.email: if a_speaker.speaker.email == self.speaker.email:
@ -120,8 +122,9 @@ class ProposalBase(models.Model):
raise ValidationError(_("%s has already been in speakers.") % a_speaker.speaker.email) raise ValidationError(_("%s has already been in speakers.") % a_speaker.speaker.email)
additional_speakers = models.ManyToManyField(Speaker, through="AdditionalSpeaker", additional_speakers = models.ManyToManyField(Speaker, through="AdditionalSpeaker",
blank=True, validators=[additional_speaker_validator]) blank=True, verbose_name=_("Addtional speakers"),
cancelled = models.BooleanField(default=False) validators=[additional_speaker_validator])
cancelled = models.BooleanField(default=False, verbose_name=_("Cancelled"))
def can_edit(self): def can_edit(self):
return True return True
@ -179,12 +182,14 @@ class AdditionalSpeaker(models.Model):
(SPEAKING_STATUS_DECLINED, _("Declined")), (SPEAKING_STATUS_DECLINED, _("Declined")),
] ]
speaker = models.ForeignKey(Speaker) speaker = models.ForeignKey(Speaker, verbose_name=_("Speaker"))
proposalbase = models.ForeignKey(ProposalBase) proposalbase = models.ForeignKey(ProposalBase, verbose_name=_("Proposalbase"))
status = models.IntegerField(choices=SPEAKING_STATUS, default=SPEAKING_STATUS_PENDING) status = models.IntegerField(choices=SPEAKING_STATUS, default=SPEAKING_STATUS_PENDING, verbose_name=_("Status"))
class Meta: class Meta:
unique_together = ("speaker", "proposalbase") unique_together = ("speaker", "proposalbase")
verbose_name = _("Addtional speaker")
verbose_name_plural = _("Additional speakers")
def __str__(self): def __str__(self):
if self.status is self.SPEAKING_STATUS_PENDING: if self.status is self.SPEAKING_STATUS_PENDING:
@ -203,14 +208,14 @@ def uuid_filename(instance, filename):
class SupportingDocument(models.Model): class SupportingDocument(models.Model):
proposal = models.ForeignKey(ProposalBase, related_name="supporting_documents") proposal = models.ForeignKey(ProposalBase, related_name="supporting_documents", verbose_name=_("Proposal"))
uploaded_by = models.ForeignKey(User) uploaded_by = models.ForeignKey(User, verbose_name=_("Uploaded by"))
created_at = models.DateTimeField(default=now) created_at = models.DateTimeField(default=now, verbose_name=_("Created at"))
file = models.FileField(upload_to=uuid_filename) file = models.FileField(upload_to=uuid_filename, verbose_name=_("File"))
description = models.CharField(max_length=140) description = models.CharField(max_length=140, verbose_name=_("Description"))
def download_url(self): def download_url(self):
return reverse("proposal_document_download", return reverse("proposal_document_download",

View file

@ -88,7 +88,7 @@ def proposal_submit_kind(request, kind_slug):
proposal.speaker = speaker_profile proposal.speaker = speaker_profile
proposal.save() proposal.save()
form.save_m2m() form.save_m2m()
messages.success(request, "Proposal submitted.") messages.success(request, _("Proposal submitted."))
if "add-speakers" in request.POST: if "add-speakers" in request.POST:
return redirect("proposal_speaker_manage", proposal.pk) return redirect("proposal_speaker_manage", proposal.pk)
return redirect("dashboard") return redirect("dashboard")

View file

@ -1,8 +1,9 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.apps import AppConfig from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class ReviewsConfig(AppConfig): class ReviewsConfig(AppConfig):
name = "symposion.reviews" name = "symposion.reviews"
label = "symposion_reviews" label = "symposion_reviews"
verbose_name = "Symposion Reviews" verbose_name = _("Symposion Reviews")

View file

@ -1,5 +1,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django import forms from django import forms
from django.utils.translation import ugettext_lazy as _
from markitup.widgets import MarkItUpWidget from markitup.widgets import MarkItUpWidget
@ -36,6 +37,7 @@ class SpeakerCommentForm(forms.ModelForm):
class BulkPresentationForm(forms.Form): class BulkPresentationForm(forms.Form):
talk_ids = forms.CharField( talk_ids = forms.CharField(
label=_("Talk ids"),
max_length=500, max_length=500,
help_text="Provide a comma seperated list of talk ids to accept." help_text=_("Provide a comma seperated list of talk ids to accept.")
) )

View file

@ -8,6 +8,7 @@ from django.db.models import Q
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
from markitup.fields import MarkupField from markitup.fields import MarkupField
@ -32,10 +33,10 @@ class Votes(object):
MINUS_ONE = "1" MINUS_ONE = "1"
CHOICES = [ CHOICES = [
(PLUS_ONE, u"+1 — Good proposal and I will argue for it to be accepted."), (PLUS_ONE, _("+1 — Good proposal and I will argue for it to be accepted.")),
(PLUS_ZERO, u"+0 — OK proposal, but I will not argue for it to be accepted."), (PLUS_ZERO, _("+0 — OK proposal, but I will not argue for it to be accepted.")),
(MINUS_ZERO, u"0 — Weak proposal, but I will not argue strongly against acceptance."), (MINUS_ZERO, _("0 — Weak proposal, but I will not argue strongly against acceptance.")),
(MINUS_ONE, u"1 — Serious issues and I will argue to reject this proposal."), (MINUS_ONE, _("1 — Serious issues and I will argue to reject this proposal.")),
] ]
VOTES = Votes() VOTES = Votes()
@ -48,18 +49,18 @@ class ReviewAssignment(models.Model):
NUM_REVIEWERS = 3 NUM_REVIEWERS = 3
ORIGIN_CHOICES = [ ORIGIN_CHOICES = [
(AUTO_ASSIGNED_INITIAL, "auto-assigned, initial"), (AUTO_ASSIGNED_INITIAL, _("auto-assigned, initial")),
(OPT_IN, "opted-in"), (OPT_IN, _("opted-in")),
(AUTO_ASSIGNED_LATER, "auto-assigned, later"), (AUTO_ASSIGNED_LATER, _("auto-assigned, later")),
] ]
proposal = models.ForeignKey(ProposalBase) proposal = models.ForeignKey(ProposalBase, verbose_name=_("Proposal"))
user = models.ForeignKey(User) user = models.ForeignKey(User, verbose_name=_("User"))
origin = models.IntegerField(choices=ORIGIN_CHOICES) origin = models.IntegerField(choices=ORIGIN_CHOICES, verbose_name=_("Origin"))
assigned_at = models.DateTimeField(default=datetime.now) assigned_at = models.DateTimeField(default=datetime.now, verbose_name=_("Assigned at"))
opted_out = models.BooleanField(default=False) opted_out = models.BooleanField(default=False, verbose_name=_("Opted out"))
@classmethod @classmethod
def create_assignments(cls, proposal, origin=AUTO_ASSIGNED_INITIAL): def create_assignments(cls, proposal, origin=AUTO_ASSIGNED_INITIAL):
@ -93,27 +94,29 @@ class ReviewAssignment(models.Model):
class ProposalMessage(models.Model): class ProposalMessage(models.Model):
proposal = models.ForeignKey(ProposalBase, related_name="messages") proposal = models.ForeignKey(ProposalBase, related_name="messages", verbose_name=_("Proposal"))
user = models.ForeignKey(User) user = models.ForeignKey(User, verbose_name=_("User"))
message = MarkupField() message = MarkupField(verbose_name=_("Message"))
submitted_at = models.DateTimeField(default=datetime.now, editable=False) submitted_at = models.DateTimeField(default=datetime.now, editable=False, verbose_name=_("Submitted at"))
class Meta: class Meta:
ordering = ["submitted_at"] ordering = ["submitted_at"]
verbose_name = _("proposal message")
verbose_name_plural = _("proposal messages")
class Review(models.Model): class Review(models.Model):
VOTES = VOTES VOTES = VOTES
proposal = models.ForeignKey(ProposalBase, related_name="reviews") proposal = models.ForeignKey(ProposalBase, related_name="reviews", verbose_name=_("Proposal"))
user = models.ForeignKey(User) user = models.ForeignKey(User, verbose_name=_("User"))
# No way to encode "-0" vs. "+0" into an IntegerField, and I don't feel # No way to encode "-0" vs. "+0" into an IntegerField, and I don't feel
# like some complicated encoding system. # like some complicated encoding system.
vote = models.CharField(max_length=2, blank=True, choices=VOTES.CHOICES) vote = models.CharField(max_length=2, blank=True, choices=VOTES.CHOICES, verbose_name=_("Vote"))
comment = MarkupField() comment = MarkupField(verbose_name=_("Comment"))
submitted_at = models.DateTimeField(default=datetime.now, editable=False) submitted_at = models.DateTimeField(default=datetime.now, editable=False, verbose_name=_("Submitted at"))
def save(self, **kwargs): def save(self, **kwargs):
if self.vote: if self.vote:
@ -181,20 +184,26 @@ class Review(models.Model):
def section(self): def section(self):
return self.proposal.kind.section.slug return self.proposal.kind.section.slug
class Meta:
verbose_name = _("review")
verbose_name_plural = _("reviews")
class LatestVote(models.Model): class LatestVote(models.Model):
VOTES = VOTES VOTES = VOTES
proposal = models.ForeignKey(ProposalBase, related_name="votes") proposal = models.ForeignKey(ProposalBase, related_name="votes", verbose_name=_("Proposal"))
user = models.ForeignKey(User) user = models.ForeignKey(User, verbose_name=_("User"))
# No way to encode "-0" vs. "+0" into an IntegerField, and I don't feel # No way to encode "-0" vs. "+0" into an IntegerField, and I don't feel
# like some complicated encoding system. # like some complicated encoding system.
vote = models.CharField(max_length=2, choices=VOTES.CHOICES) vote = models.CharField(max_length=2, choices=VOTES.CHOICES, verbose_name=_("Vote"))
submitted_at = models.DateTimeField(default=datetime.now, editable=False) submitted_at = models.DateTimeField(default=datetime.now, editable=False, verbose_name=_("Submitted at"))
class Meta: class Meta:
unique_together = [("proposal", "user")] unique_together = [("proposal", "user")]
verbose_name = _("latest vote")
verbose_name_plural = _("latest votes")
def css_class(self): def css_class(self):
return { return {
@ -206,25 +215,25 @@ class LatestVote(models.Model):
class ProposalResult(models.Model): class ProposalResult(models.Model):
proposal = models.OneToOneField(ProposalBase, related_name="result") proposal = models.OneToOneField(ProposalBase, related_name="result", verbose_name=_("Proposal"))
score = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal("0.00")) score = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal("0.00"), verbose_name=_("Score"))
comment_count = models.PositiveIntegerField(default=0) comment_count = models.PositiveIntegerField(default=0, verbose_name=_("Comment count"))
vote_count = models.PositiveIntegerField(default=0) vote_count = models.PositiveIntegerField(default=0, verbose_name=_("Vote count"))
plus_one = models.PositiveIntegerField(default=0) plus_one = models.PositiveIntegerField(default=0, verbose_name=_("Plus one"))
plus_zero = models.PositiveIntegerField(default=0) plus_zero = models.PositiveIntegerField(default=0, verbose_name=_("Plus zero"))
minus_zero = models.PositiveIntegerField(default=0) minus_zero = models.PositiveIntegerField(default=0, verbose_name=_("Minus zero"))
minus_one = models.PositiveIntegerField(default=0) minus_one = models.PositiveIntegerField(default=0, verbose_name=_("Minus one"))
accepted = models.NullBooleanField(choices=[ accepted = models.NullBooleanField(choices=[
(True, "accepted"), (True, "accepted"),
(False, "rejected"), (False, "rejected"),
(None, "undecided"), (None, "undecided"),
], default=None) ], default=None, verbose_name=_("Accepted"))
status = models.CharField(max_length=20, choices=[ status = models.CharField(max_length=20, choices=[
("accepted", "accepted"), ("accepted", _("accepted")),
("rejected", "rejected"), ("rejected", _("rejected")),
("undecided", "undecided"), ("undecided", _("undecided")),
("standby", "standby"), ("standby", _("standby")),
], default="undecided") ], default="undecided", verbose_name=_("Status"))
@classmethod @classmethod
def full_calculate(cls): def full_calculate(cls):
@ -280,35 +289,47 @@ class ProposalResult(models.Model):
model = self.__class__ model = self.__class__
model._default_manager.filter(pk=self.pk).update(score=ProposalScoreExpression()) model._default_manager.filter(pk=self.pk).update(score=ProposalScoreExpression())
class Meta:
verbose_name = _("proposal_result")
verbose_name_plural = _("proposal_results")
class Comment(models.Model): class Comment(models.Model):
proposal = models.ForeignKey(ProposalBase, related_name="comments") proposal = models.ForeignKey(ProposalBase, related_name="comments", verbose_name=_("Proposal"))
commenter = models.ForeignKey(User) commenter = models.ForeignKey(User, verbose_name=_("Commenter"))
text = MarkupField() text = MarkupField(verbose_name=_("Text"))
# Or perhaps more accurately, can the user see this comment. # Or perhaps more accurately, can the user see this comment.
public = models.BooleanField(choices=[(True, "public"), (False, "private")], default=False) public = models.BooleanField(choices=[(True, _("public")), (False, _("private"))], default=False, verbose_name=_("Public"))
commented_at = models.DateTimeField(default=datetime.now) commented_at = models.DateTimeField(default=datetime.now, verbose_name=_("Commented at"))
class Meta:
verbose_name = _("comment")
verbose_name_plural = _("comments")
class NotificationTemplate(models.Model): class NotificationTemplate(models.Model):
label = models.CharField(max_length=100) label = models.CharField(max_length=100, verbose_name=_("Label"))
from_address = models.EmailField() from_address = models.EmailField(verbose_name=_("From address"))
subject = models.CharField(max_length=100) subject = models.CharField(max_length=100, verbose_name=_("Subject"))
body = models.TextField() body = models.TextField(verbose_name=_("Body"))
class Meta:
verbose_name = _("notification template")
verbose_name_plural = _("notification templates")
class ResultNotification(models.Model): class ResultNotification(models.Model):
proposal = models.ForeignKey(ProposalBase, related_name="notifications") proposal = models.ForeignKey(ProposalBase, related_name="notifications", verbose_name=_("Proposal"))
template = models.ForeignKey(NotificationTemplate, null=True, blank=True, template = models.ForeignKey(NotificationTemplate, null=True, blank=True,
on_delete=models.SET_NULL) on_delete=models.SET_NULL, verbose_name=_("Template"))
timestamp = models.DateTimeField(default=datetime.now) timestamp = models.DateTimeField(default=datetime.now, verbose_name=_("Timestamp"))
to_address = models.EmailField() to_address = models.EmailField(verbose_name=_("To address"))
from_address = models.EmailField() from_address = models.EmailField(verbose_name=_("From address"))
subject = models.CharField(max_length=100) subject = models.CharField(max_length=100, verbose_name=_("Subject"))
body = models.TextField() body = models.TextField(verbose_name=_("Body"))
def recipients(self): def recipients(self):
for speaker in self.proposal.speakers(): for speaker in self.proposal.speakers():

View file

@ -1,10 +1,12 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime import datetime
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db import models from django.db import models
from django.utils.encoding import python_2_unicode_compatible from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from markitup.fields import MarkupField from markitup.fields import MarkupField
@ -16,22 +18,24 @@ from symposion.speakers.models import Speaker
@python_2_unicode_compatible @python_2_unicode_compatible
class Schedule(models.Model): class Schedule(models.Model):
section = models.OneToOneField(Section) section = models.OneToOneField(Section, verbose_name=_("Section"))
published = models.BooleanField(default=True) published = models.BooleanField(default=True, verbose_name=_("Published"))
hidden = models.BooleanField("Hide schedule from overall conference view", default=False) hidden = models.BooleanField(_("Hide schedule from overall conference view"), default=False)
def __str__(self): def __str__(self):
return "%s Schedule" % self.section return "%s Schedule" % self.section
class Meta: class Meta:
ordering = ["section"] ordering = ["section"]
verbose_name = _('Schedule')
verbose_name_plural = _('Schedules')
@python_2_unicode_compatible @python_2_unicode_compatible
class Day(models.Model): class Day(models.Model):
schedule = models.ForeignKey(Schedule) schedule = models.ForeignKey(Schedule, verbose_name=_("Schedule"))
date = models.DateField() date = models.DateField(verbose_name=_("Date"))
def __str__(self): def __str__(self):
return "%s" % self.date return "%s" % self.date
@ -39,18 +43,24 @@ class Day(models.Model):
class Meta: class Meta:
unique_together = [("schedule", "date")] unique_together = [("schedule", "date")]
ordering = ["date"] ordering = ["date"]
verbose_name = _("date")
verbose_name_plural = _("dates")
@python_2_unicode_compatible @python_2_unicode_compatible
class Room(models.Model): class Room(models.Model):
schedule = models.ForeignKey(Schedule) schedule = models.ForeignKey(Schedule, verbose_name=_("Schedule"))
name = models.CharField(max_length=65) name = models.CharField(max_length=65, verbose_name=_("Name"))
order = models.PositiveIntegerField() order = models.PositiveIntegerField(verbose_name=_("Order"))
def __str__(self): def __str__(self):
return self.name return self.name
class Meta:
verbose_name = _("Room")
verbose_name_plural = _("Rooms")
@python_2_unicode_compatible @python_2_unicode_compatible
class SlotKind(models.Model): class SlotKind(models.Model):
@ -59,21 +69,25 @@ class SlotKind(models.Model):
break, lunch, or X-minute talk. break, lunch, or X-minute talk.
""" """
schedule = models.ForeignKey(Schedule) schedule = models.ForeignKey(Schedule, verbose_name=_("schedule"))
label = models.CharField(max_length=50) label = models.CharField(max_length=50, verbose_name=_("Label"))
def __str__(self): def __str__(self):
return self.label return self.label
class Meta:
verbose_name = _("Slot kind")
verbose_name_plural = _("Slot kinds")
@python_2_unicode_compatible @python_2_unicode_compatible
class Slot(models.Model): class Slot(models.Model):
day = models.ForeignKey(Day) day = models.ForeignKey(Day, verbose_name=_("Day"))
kind = models.ForeignKey(SlotKind) kind = models.ForeignKey(SlotKind, verbose_name=_("Kind"))
start = models.TimeField() start = models.TimeField(verbose_name=_("Start"))
end = models.TimeField() end = models.TimeField(verbose_name=_("End"))
content_override = MarkupField(blank=True) content_override = MarkupField(blank=True, verbose_name=_("Content override"))
def assign(self, content): def assign(self, content):
""" """
@ -137,6 +151,8 @@ class Slot(models.Model):
class Meta: class Meta:
ordering = ["day", "start", "end"] ordering = ["day", "start", "end"]
verbose_name = _("slot")
verbose_name_plural = _("slots")
@python_2_unicode_compatible @python_2_unicode_compatible
@ -145,8 +161,8 @@ class SlotRoom(models.Model):
Links a slot with a room. Links a slot with a room.
""" """
slot = models.ForeignKey(Slot) slot = models.ForeignKey(Slot, verbose_name=_("Slot"))
room = models.ForeignKey(Room) room = models.ForeignKey(Room, verbose_name=_("Room"))
def __str__(self): def __str__(self):
return "%s %s" % (self.room, self.slot) return "%s %s" % (self.room, self.slot)
@ -154,21 +170,23 @@ class SlotRoom(models.Model):
class Meta: class Meta:
unique_together = [("slot", "room")] unique_together = [("slot", "room")]
ordering = ["slot", "room__order"] ordering = ["slot", "room__order"]
verbose_name = _("Slot room")
verbose_name_plural = _("Slot rooms")
@python_2_unicode_compatible @python_2_unicode_compatible
class Presentation(models.Model): class Presentation(models.Model):
slot = models.OneToOneField(Slot, null=True, blank=True, related_name="content_ptr") slot = models.OneToOneField(Slot, null=True, blank=True, related_name="content_ptr", verbose_name=_("Slot"))
title = models.CharField(max_length=100) title = models.CharField(max_length=100, verbose_name=_("Title"))
description = MarkupField() description = MarkupField(verbose_name=_("Description"))
abstract = MarkupField() abstract = MarkupField(verbose_name=_("Abstract"))
speaker = models.ForeignKey(Speaker, related_name="presentations") speaker = models.ForeignKey(Speaker, related_name="presentations", verbose_name=_("Speaker"))
additional_speakers = models.ManyToManyField(Speaker, related_name="copresentations", additional_speakers = models.ManyToManyField(Speaker, related_name="copresentations",
blank=True) blank=True, verbose_name=_("Additional speakers"))
cancelled = models.BooleanField(default=False) cancelled = models.BooleanField(default=False, verbose_name=_("Cancelled"))
proposal_base = models.OneToOneField(ProposalBase, related_name="presentation") proposal_base = models.OneToOneField(ProposalBase, related_name="presentation", verbose_name=_("Proposal base"))
section = models.ForeignKey(Section, related_name="presentations") section = models.ForeignKey(Section, related_name="presentations", verbose_name=_("Section"))
@property @property
def number(self): def number(self):
@ -191,13 +209,15 @@ class Presentation(models.Model):
class Meta: class Meta:
ordering = ["slot"] ordering = ["slot"]
verbose_name = _("presentation")
verbose_name_plural = _("presentations")
@python_2_unicode_compatible @python_2_unicode_compatible
class Session(models.Model): class Session(models.Model):
day = models.ForeignKey(Day, related_name="sessions") day = models.ForeignKey(Day, related_name="sessions", verbose_name=_("Day"))
slots = models.ManyToManyField(Slot, related_name="sessions") slots = models.ManyToManyField(Slot, related_name="sessions", verbose_name=_("Slots"))
def sorted_slots(self): def sorted_slots(self):
return self.slots.order_by("start") return self.slots.order_by("start")
@ -227,6 +247,10 @@ class Session(models.Model):
) )
return "" return ""
class Meta:
verbose_name = _("Session")
verbose_name_plural = _("Sessions")
@python_2_unicode_compatible @python_2_unicode_compatible
class SessionRole(models.Model): class SessionRole(models.Model):
@ -235,19 +259,21 @@ class SessionRole(models.Model):
SESSION_ROLE_RUNNER = 2 SESSION_ROLE_RUNNER = 2
SESSION_ROLE_TYPES = [ SESSION_ROLE_TYPES = [
(SESSION_ROLE_CHAIR, "Session Chair"), (SESSION_ROLE_CHAIR, _("Session Chair")),
(SESSION_ROLE_RUNNER, "Session Runner"), (SESSION_ROLE_RUNNER, _("Session Runner")),
] ]
session = models.ForeignKey(Session) session = models.ForeignKey(Session, verbose_name=_("Session"))
user = models.ForeignKey(User) user = models.ForeignKey(User, verbose_name=_("User"))
role = models.IntegerField(choices=SESSION_ROLE_TYPES) role = models.IntegerField(choices=SESSION_ROLE_TYPES, verbose_name=_("Role"))
status = models.NullBooleanField() status = models.NullBooleanField(verbose_name=_("Status"))
submitted = models.DateTimeField(default=datetime.datetime.now) submitted = models.DateTimeField(default=datetime.datetime.now)
class Meta: class Meta:
unique_together = [("session", "user", "role")] unique_together = [("session", "user", "role")]
verbose_name = _("Session role")
verbose_name_plural = _("Session roles")
def __str__(self): def __str__(self):
return "%s %s: %s" % (self.user, self.session, return "%s %s: %s" % (self.user, self.session,

View file

@ -1,8 +1,9 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.apps import AppConfig from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class SpeakersConfig(AppConfig): class SpeakersConfig(AppConfig):
name = "symposion.speakers" name = "symposion.speakers"
label = "symposion_speakers" label = "symposion_speakers"
verbose_name = "Symposion Speakers" verbose_name = _("Symposion Speakers")

View file

@ -1,9 +1,11 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime
from django.utils.encoding import python_2_unicode_compatible
from django.db import models import datetime
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User from django.contrib.auth.models import User
@ -18,24 +20,28 @@ class Speaker(models.Model):
(2, "Two") (2, "Two")
] ]
user = models.OneToOneField(User, null=True, related_name="speaker_profile") user = models.OneToOneField(User, null=True, related_name="speaker_profile", verbose_name=_("User"))
name = models.CharField(max_length=100, help_text=("As you would like it to appear in the " name = models.CharField(verbose_name=_("Name"), max_length=100,
"conference program.")) help_text=_("As you would like it to appear in the"
biography = MarkupField(blank=True, help_text=("A little bit about you. Edit using " " conference program."))
biography = MarkupField(blank=True, help_text=_("A little bit about you. Edit using "
"<a href='http://warpedvisions.org/projects/" "<a href='http://warpedvisions.org/projects/"
"markdown-cheat-sheet/target='_blank'>" "markdown-cheat-sheet/target='_blank'>"
"Markdown</a>.")) "Markdown</a>."), verbose_name=_("Biography"))
photo = models.ImageField(upload_to="speaker_photos", blank=True) photo = models.ImageField(upload_to="speaker_photos", blank=True, verbose_name=_("Photo"))
annotation = models.TextField() # staff only annotation = models.TextField(verbose_name=_("Annotation")) # 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, verbose_name=_("Invite_email"))
invite_token = models.CharField(max_length=40, db_index=True) invite_token = models.CharField(max_length=40, db_index=True, verbose_name=_("Invite token"))
created = models.DateTimeField( created = models.DateTimeField(
default=datetime.datetime.now, default=datetime.datetime.now,
editable=False editable=False,
verbose_name=_("Created")
) )
class Meta: class Meta:
ordering = ['name'] ordering = ['name']
verbose_name = _("Speaker")
verbose_name_plural = _("Speakers")
def __str__(self): def __str__(self):
if self.user: if self.user:

View file

@ -6,6 +6,7 @@ from django.shortcuts import render, redirect, get_object_or_404
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 django.contrib.auth.models import User from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
from symposion.proposals.models import ProposalBase from symposion.proposals.models import ProposalBase
from symposion.speakers.forms import SpeakerForm from symposion.speakers.forms import SpeakerForm
@ -34,7 +35,7 @@ def speaker_create(request):
if not found: if not found:
speaker.invite_email = None speaker.invite_email = None
speaker.save() speaker.save()
messages.success(request, "Speaker profile created.") messages.success(request, _("Speaker profile created."))
return redirect("dashboard") return redirect("dashboard")
else: else:
form = SpeakerForm(initial={"name": request.user.get_full_name()}) form = SpeakerForm(initial={"name": request.user.get_full_name()})
@ -62,7 +63,7 @@ def speaker_create_staff(request, pk):
speaker = form.save(commit=False) speaker = form.save(commit=False)
speaker.user = user speaker.user = user
speaker.save() speaker.save()
messages.success(request, "Speaker profile created.") messages.success(request, _("Speaker profile created."))
return redirect("user_list") return redirect("user_list")
else: else:
form = SpeakerForm(initial={"name": user.get_full_name()}) form = SpeakerForm(initial={"name": user.get_full_name()})
@ -89,7 +90,7 @@ 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:

View file

@ -69,9 +69,9 @@ class SponsorAdmin(admin.ModelAdmin):
# @@@ kinda ugly but using choices= on NullBooleanField is broken # @@@ kinda ugly but using choices= on NullBooleanField is broken
form = super(SponsorAdmin, self).get_form(*args, **kwargs) form = super(SponsorAdmin, self).get_form(*args, **kwargs)
form.base_fields["active"].widget.choices = [ form.base_fields["active"].widget.choices = [
(u"1", _("unreviewed")), ("1", _("unreviewed")),
(u"2", _("approved")), ("2", _("approved")),
(u"3", _("rejected")) ("3", _("rejected"))
] ]
return form return form

View file

@ -1,7 +1,9 @@
from __future__ import unicode_literals
from django.apps import AppConfig from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class SponsorshipConfig(AppConfig): class SponsorshipConfig(AppConfig):
name = "symposion.sponsorship" name = "symposion.sponsorship"
label = "symposion_sponsorship" label = "symposion_sponsorship"
verbose_name = "Symposion Sponsorship" verbose_name = _("Symposion Sponsorship")

View file

@ -3,6 +3,7 @@ from django import forms
from django.forms.models import inlineformset_factory, BaseInlineFormSet from django.forms.models import inlineformset_factory, BaseInlineFormSet
from django.contrib.admin.widgets import AdminFileWidget from django.contrib.admin.widgets import AdminFileWidget
from django.utils.translation import ugettext_lazy as _
from symposion.sponsorship.models import Sponsor, SponsorBenefit from symposion.sponsorship.models import Sponsor, SponsorBenefit
@ -65,7 +66,7 @@ class SponsorBenefitsInlineFormSet(BaseInlineFormSet):
# provide word limit as help_text # provide word limit as help_text
if form.instance.benefit.type == "text" and form.instance.max_words: if form.instance.benefit.type == "text" and form.instance.max_words:
form.fields[field].help_text = u"maximum %s words" % form.instance.max_words form.fields[field].help_text = _("maximum %s words") % form.instance.max_words
# use admin file widget that shows currently uploaded file # use admin file widget that shows currently uploaded file
if field == "upload": if field == "upload":

View file

@ -48,16 +48,16 @@ BENEFITS = [
@python_2_unicode_compatible @python_2_unicode_compatible
class SponsorLevel(models.Model): class SponsorLevel(models.Model):
conference = models.ForeignKey(Conference, verbose_name=_("conference")) conference = models.ForeignKey(Conference, verbose_name=_("Conference"))
name = models.CharField(_("name"), max_length=100) name = models.CharField(_("Name"), max_length=100)
order = models.IntegerField(_("order"), default=0) order = models.IntegerField(_("Order"), default=0)
cost = models.PositiveIntegerField(_("cost")) cost = models.PositiveIntegerField(_("Cost"))
description = models.TextField(_("description"), blank=True, help_text=_("This is private.")) description = models.TextField(_("Description"), blank=True, help_text=_("This is private."))
class Meta: class Meta:
ordering = ["conference", "order"] ordering = ["conference", "order"]
verbose_name = _("sponsor level") verbose_name = _("Sponsor level")
verbose_name_plural = _("sponsor levels") verbose_name_plural = _("Sponsor levels")
def __str__(self): def __str__(self):
return "%s %s" % (self.conference, self.name) return "%s %s" % (self.conference, self.name)
@ -69,22 +69,22 @@ class SponsorLevel(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class Sponsor(models.Model): class Sponsor(models.Model):
applicant = models.ForeignKey(User, related_name="sponsorships", verbose_name=_("applicant"), applicant = models.ForeignKey(User, related_name="sponsorships", verbose_name=_("Applicant"),
null=True) null=True)
name = models.CharField(_("Sponsor Name"), max_length=100) name = models.CharField(_("Sponsor Name"), max_length=100)
display_url = models.URLField(_("display URL"), blank=True) display_url = models.URLField(_("display URL"), blank=True)
external_url = models.URLField(_("external URL")) external_url = models.URLField(_("External URL"))
annotation = models.TextField(_("annotation"), blank=True) annotation = models.TextField(_("Annotation"), blank=True)
contact_name = models.CharField(_("Contact Name"), max_length=100) contact_name = models.CharField(_("Contact Name"), max_length=100)
contact_email = models.EmailField(_(u"Contact Email")) contact_email = models.EmailField(_("Contact Email"))
level = models.ForeignKey(SponsorLevel, verbose_name=_("level")) level = models.ForeignKey(SponsorLevel, verbose_name=_("level"))
added = models.DateTimeField(_("added"), default=datetime.datetime.now) added = models.DateTimeField(_("added"), default=datetime.datetime.now)
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, sponsor_logo = models.ForeignKey("SponsorBenefit", related_name="+", null=True, blank=True,
editable=False) editable=False, verbose_name=_("Sponsor logo"))
# Whether things are complete # Whether things are complete
# True = complete, False = incomplate, Null = n/a for this sponsor level # True = complete, False = incomplate, Null = n/a for this sponsor level
@ -99,8 +99,8 @@ class Sponsor(models.Model):
return self.name return self.name
class Meta: class Meta:
verbose_name = _("sponsor") verbose_name = _("Sponsor")
verbose_name_plural = _("sponsors") verbose_name_plural = _("Sponsors")
ordering = ['name'] ordering = ['name']
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
@ -213,12 +213,12 @@ post_save.connect(_check_level_change, sender=Sponsor)
BENEFIT_TYPE_CHOICES = [ BENEFIT_TYPE_CHOICES = [
("text", "Text"), ("text", _("Text")),
("richtext", "Rich Text"), ("file", _("File")),
("file", "File"), ("richtext", _("Rich Text")),
("weblogo", "Web Logo"), ("weblogo", _("Web Logo")),
("simple", "Simple"), ("simple", _("Simple")),
("option", "Option") ("option", _("Option"))
] ]
CONTENT_TYPE_CHOICES = [ CONTENT_TYPE_CHOICES = [
@ -231,10 +231,10 @@ CONTENT_TYPE_CHOICES = [
@python_2_unicode_compatible @python_2_unicode_compatible
class Benefit(models.Model): 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, type = models.CharField(_("Type"), choices=BENEFIT_TYPE_CHOICES, max_length=10,
max_length=10, default="simple") default="simple")
content_type = models.CharField(_("content type"), choices=CONTENT_TYPE_CHOICES, content_type = models.CharField(_("content type"), choices=CONTENT_TYPE_CHOICES,
max_length=20, default="simple") max_length=20, default="simple")
@ -245,15 +245,17 @@ class Benefit(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class BenefitLevel(models.Model): class BenefitLevel(models.Model):
benefit = models.ForeignKey(Benefit, related_name="benefit_levels", verbose_name=_("benefit")) benefit = models.ForeignKey(Benefit, related_name="benefit_levels", verbose_name=_("Benefit"))
level = models.ForeignKey(SponsorLevel, related_name="benefit_levels", verbose_name=_("level")) level = models.ForeignKey(SponsorLevel, related_name="benefit_levels", verbose_name=_("Level"))
# default limits for this benefit at given level # default limits for this benefit at given level
max_words = models.PositiveIntegerField(_("max words"), blank=True, null=True) max_words = models.PositiveIntegerField(_("Max words"), blank=True, null=True)
other_limits = models.CharField(_("other limits"), max_length=200, blank=True) other_limits = models.CharField(_("Other limits"), max_length=200, blank=True)
class Meta: class Meta:
ordering = ["level"] ordering = ["level"]
verbose_name = _("Benefit level")
verbose_name_plural = _("Benefit levels")
def __str__(self): def __str__(self):
return "%s - %s" % (self.level, self.benefit) return "%s - %s" % (self.level, self.benefit)
@ -262,18 +264,18 @@ class BenefitLevel(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class SponsorBenefit(models.Model): class SponsorBenefit(models.Model):
sponsor = models.ForeignKey(Sponsor, related_name="sponsor_benefits", verbose_name=_("sponsor")) sponsor = models.ForeignKey(Sponsor, related_name="sponsor_benefits", verbose_name=_("Sponsor"))
benefit = models.ForeignKey(Benefit, related_name="sponsor_benefits", verbose_name=_("benefit")) benefit = models.ForeignKey(Benefit, related_name="sponsor_benefits", verbose_name=_("Benefit"))
active = models.BooleanField(default=True) active = models.BooleanField(default=True, verbose_name=_("Active"))
# Limits: will initially be set to defaults from corresponding BenefitLevel # Limits: will initially be set to defaults from corresponding BenefitLevel
max_words = models.PositiveIntegerField(_("max words"), blank=True, null=True) max_words = models.PositiveIntegerField(_("Max words"), blank=True, null=True)
other_limits = models.CharField(_("other limits"), max_length=200, blank=True) other_limits = models.CharField(_("Other limits"), max_length=200, blank=True)
# Data: zero or one of these fields will be used, depending on the # Data: zero or one of these fields will be used, depending on the
# type of the Benefit (text, file, or simple) # type of the Benefit (text, file, or simple)
text = models.TextField(_("text"), blank=True) text = models.TextField(_("Text"), blank=True)
upload = models.FileField(_("file"), blank=True, upload_to="sponsor_files") upload = models.FileField(_("File"), blank=True, upload_to="sponsor_files")
# Whether any assets required from the sponsor have been provided # Whether any assets required from the sponsor have been provided
# (e.g. a logo file for a Web logo benefit). # (e.g. a logo file for a Web logo benefit).
@ -281,6 +283,8 @@ class SponsorBenefit(models.Model):
class Meta: class Meta:
ordering = ["-active"] ordering = ["-active"]
verbose_name = _("Sponsor benefit")
verbose_name_plural = _("Sponsor benefits")
def __str__(self): def __str__(self):
return "%s - %s (%s)" % (self.sponsor, self.benefit, self.benefit_type) return "%s - %s (%s)" % (self.sponsor, self.benefit, self.benefit_type)
@ -296,8 +300,8 @@ class SponsorBenefit(models.Model):
num_words = len(self.text.split()) num_words = len(self.text.split())
if self.max_words and num_words > self.max_words: if self.max_words and num_words > self.max_words:
raise ValidationError( raise ValidationError(
"Sponsorship level only allows for %s words, you provided %d." % ( _("Sponsorship level only allows for %(word)s words, you provided %(num)d.") % {
self.max_words, num_words)) "word": self.max_words, "num": num_words})
def data_fields(self): def data_fields(self):
""" """

View file

@ -7,16 +7,14 @@ import time
from zipfile import ZipFile, ZipInfo from zipfile import ZipFile, ZipInfo
from django.conf import settings from django.conf import settings
from django.contrib import messages
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth.decorators import login_required
from django.http import Http404, HttpResponse from django.http import Http404, HttpResponse
from django.shortcuts import render_to_response, redirect, get_object_or_404 from django.shortcuts import render_to_response, redirect, get_object_or_404
from django.template import RequestContext from django.template import RequestContext
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.contrib import messages
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth.decorators import login_required
from symposion.sponsorship.forms import SponsorApplicationForm, \ from symposion.sponsorship.forms import SponsorApplicationForm, \
SponsorDetailsForm, SponsorBenefitsFormSet SponsorDetailsForm, SponsorBenefitsFormSet
from symposion.sponsorship.models import Benefit, Sponsor, SponsorBenefit, \ from symposion.sponsorship.models import Benefit, Sponsor, SponsorBenefit, \
@ -91,7 +89,7 @@ def sponsor_detail(request, pk):
form.save() form.save()
formset.save() formset.save()
messages.success(request, "Sponsorship details have been updated") messages.success(request, _("Sponsorship details have been updated"))
return redirect("dashboard") return redirect("dashboard")
else: else:

View file

@ -3,6 +3,7 @@ from django import forms
from django.utils.html import escape from django.utils.html import escape
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User from django.contrib.auth.models import User
@ -11,7 +12,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 " email = forms.EmailField(label=_("Email"),
help_text=_("email address must be that of an account on this "
"conference site")) "conference site"))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -23,7 +25,7 @@ class TeamInvitationForm(forms.Form):
email = cleaned_data.get("email") email = cleaned_data.get("email")
if email is None: if email is None:
raise forms.ValidationError("valid email address required") raise forms.ValidationError(_("valid email address required"))
try: try:
user = User.objects.get(email=email) user = User.objects.get(email=email)
@ -31,16 +33,16 @@ class TeamInvitationForm(forms.Form):
# 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( raise forms.ValidationError(
mark_safe("no account with email address <b>%s</b> found on this conference " mark_safe(_("no account with email address <b>%s</b> found on this conference "
"site" % escape(email))) "site") % escape(email)))
state = self.team.get_state_for_user(user) state = self.team.get_state_for_user(user)
if state in ["member", "manager"]: if state in ["member", "manager"]:
raise forms.ValidationError("user already in team") raise forms.ValidationError(_("user already in team"))
if state in ["invited"]: if state in ["invited"]:
raise forms.ValidationError("user already invited to team") raise forms.ValidationError(_("user already invited to team"))
self.user = user self.user = user
self.state = state self.state = state

View file

@ -1,37 +1,44 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime import datetime
from django.db import models from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import Permission, User
import reversion import reversion
from django.contrib.auth.models import Permission, User
from django.utils.encoding import python_2_unicode_compatible
TEAM_ACCESS_CHOICES = [ TEAM_ACCESS_CHOICES = [
("open", "open"), ("open", _("open")),
("application", "by application"), ("application", _("by application")),
("invitation", "by invitation") ("invitation", _("by invitation"))
] ]
@python_2_unicode_compatible @python_2_unicode_compatible
class Team(models.Model): class Team(models.Model):
slug = models.SlugField(unique=True) slug = models.SlugField(unique=True, verbose_name=_("Slug"))
name = models.CharField(max_length=100) name = models.CharField(max_length=100, verbose_name=_("Name"))
description = models.TextField(blank=True) description = models.TextField(blank=True, verbose_name=_("Description"))
access = models.CharField(max_length=20, choices=TEAM_ACCESS_CHOICES) access = models.CharField(max_length=20, choices=TEAM_ACCESS_CHOICES,
verbose_name=_("Access"))
# member permissions # member permissions
permissions = models.ManyToManyField(Permission, blank=True, related_name="member_teams") permissions = models.ManyToManyField(Permission, blank=True,
related_name="member_teams",
verbose_name=_("Permissions"))
# manager permissions # manager permissions
manager_permissions = models.ManyToManyField(Permission, blank=True, manager_permissions = models.ManyToManyField(Permission, blank=True,
related_name="manager_teams") related_name="manager_teams",
verbose_name=_("Manager permissions"))
created = models.DateTimeField(default=datetime.datetime.now, editable=False) created = models.DateTimeField(default=datetime.datetime.now,
editable=False, verbose_name=_("Created"))
@models.permalink @models.permalink
def get_absolute_url(self): def get_absolute_url(self):
@ -58,23 +65,32 @@ class Team(models.Model):
def managers(self): def managers(self):
return self.memberships.filter(state="manager") return self.memberships.filter(state="manager")
class Meta:
verbose_name = _('Team')
verbose_name_plural = _('Teams')
MEMBERSHIP_STATE_CHOICES = [ MEMBERSHIP_STATE_CHOICES = [
("applied", "applied"), ("applied", _("applied")),
("invited", "invited"), ("invited", _("invited")),
("declined", "declined"), ("declined", _("declined")),
("rejected", "rejected"), ("rejected", _("rejected")),
("member", "member"), ("member", _("member")),
("manager", "manager"), ("manager", _("manager")),
] ]
class Membership(models.Model): class Membership(models.Model):
user = models.ForeignKey(User, related_name="memberships") user = models.ForeignKey(User, related_name="memberships",
team = models.ForeignKey(Team, related_name="memberships") verbose_name=_("User"))
state = models.CharField(max_length=20, choices=MEMBERSHIP_STATE_CHOICES) team = models.ForeignKey(Team, related_name="memberships",
message = models.TextField(blank=True) verbose_name=_("Team"))
state = models.CharField(max_length=20, choices=MEMBERSHIP_STATE_CHOICES,
verbose_name=_("State"))
message = models.TextField(blank=True, verbose_name=_("Message"))
class Meta:
verbose_name = _("Membership")
verbose_name_plural = _("Memberships")
reversion.register(Membership) reversion.register(Membership)

View file

@ -6,6 +6,7 @@ from django.contrib.auth.decorators import login_required
from django.contrib import messages from django.contrib import messages
from symposion.utils.mail import send_email from symposion.utils.mail import send_email
from django.utils.translation import ugettext_lazy as _
from symposion.teams.forms import TeamInvitationForm from symposion.teams.forms import TeamInvitationForm
from symposion.teams.models import Team, Membership from symposion.teams.models import Team, Membership
@ -67,7 +68,7 @@ def team_detail(request, slug):
if form.is_valid(): if form.is_valid():
form.invite() form.invite()
send_email([form.user.email], "teams_user_invited", context={"team": team}) send_email([form.user.email], "teams_user_invited", context={"team": team})
messages.success(request, "Invitation created.") messages.success(request, _("Invitation created."))
return redirect("team_detail", slug=slug) return redirect("team_detail", slug=slug)
else: else:
form = TeamInvitationForm(team=team) form = TeamInvitationForm(team=team)
@ -95,7 +96,7 @@ def team_join(request, slug):
membership, created = Membership.objects.get_or_create(team=team, user=request.user) membership, created = Membership.objects.get_or_create(team=team, user=request.user)
membership.state = "member" membership.state = "member"
membership.save() membership.save()
messages.success(request, "Joined team.") messages.success(request, _("Joined team."))
return redirect("team_detail", slug=slug) return redirect("team_detail", slug=slug)
else: else:
return redirect("team_detail", slug=slug) return redirect("team_detail", slug=slug)
@ -111,7 +112,7 @@ def team_leave(request, slug):
if can_leave(team, request.user) and request.method == "POST": if can_leave(team, request.user) and request.method == "POST":
membership = Membership.objects.get(team=team, user=request.user) membership = Membership.objects.get(team=team, user=request.user)
membership.delete() membership.delete()
messages.success(request, "Left team.") messages.success(request, _("Left team."))
return redirect("dashboard") return redirect("dashboard")
else: else:
return redirect("team_detail", slug=slug) return redirect("team_detail", slug=slug)
@ -133,7 +134,7 @@ def team_apply(request, slug):
"team": team, "team": team,
"user": request.user "user": request.user
}) })
messages.success(request, "Applied to join team.") messages.success(request, _("Applied to join team."))
return redirect("team_detail", slug=slug) return redirect("team_detail", slug=slug)
else: else:
return redirect("team_detail", slug=slug) return redirect("team_detail", slug=slug)
@ -149,7 +150,7 @@ def team_promote(request, pk):
if membership.state == "member": if membership.state == "member":
membership.state = "manager" membership.state = "manager"
membership.save() membership.save()
messages.success(request, "Promoted to manager.") messages.success(request, _("Promoted to manager."))
return redirect("team_detail", slug=membership.team.slug) return redirect("team_detail", slug=membership.team.slug)
@ -163,7 +164,7 @@ def team_demote(request, pk):
if membership.state == "manager": if membership.state == "manager":
membership.state = "member" membership.state = "member"
membership.save() membership.save()
messages.success(request, "Demoted from manager.") messages.success(request, _("Demoted from manager."))
return redirect("team_detail", slug=membership.team.slug) return redirect("team_detail", slug=membership.team.slug)
@ -177,7 +178,7 @@ def team_accept(request, pk):
if membership.state == "applied": if membership.state == "applied":
membership.state = "member" membership.state = "member"
membership.save() membership.save()
messages.success(request, "Accepted application.") messages.success(request, _("Accepted application."))
return redirect("team_detail", slug=membership.team.slug) return redirect("team_detail", slug=membership.team.slug)
@ -191,5 +192,5 @@ def team_reject(request, pk):
if membership.state == "applied": if membership.state == "applied":
membership.state = "rejected" membership.state = "rejected"
membership.save() membership.save()
messages.success(request, "Rejected application.") messages.success(request, _("Rejected application."))
return redirect("team_detail", slug=membership.team.slug) return redirect("team_detail", slug=membership.team.slug)