Merge branch 'i18n-all' of https://github.com/miurahr/symposion into miurahr-i18n-all
Conflicts: symposion/boxes/models.py symposion/conference/models.py symposion/schedule/models.py symposion/speakers/models.py symposion/sponsorship/admin.py symposion/sponsorship/models.py symposion/teams/models.py
This commit is contained in:
		
						commit
						67433cacb4
					
				
					 25 changed files with 340 additions and 241 deletions
				
			
		|  | @ -2,6 +2,7 @@ from __future__ import unicode_literals | |||
| from django.db import models | ||||
| from django.contrib.auth.models import User | ||||
| from django.utils.encoding import python_2_unicode_compatible | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| 
 | ||||
| import reversion | ||||
| 
 | ||||
|  | @ -11,17 +12,17 @@ from markitup.fields import MarkupField | |||
| @python_2_unicode_compatible | ||||
| 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) | ||||
| 
 | ||||
|     created_by = models.ForeignKey(User, related_name="boxes") | ||||
|     last_updated_by = models.ForeignKey(User, related_name="updated_boxes") | ||||
|     created_by = models.ForeignKey(User, related_name="boxes", verbose_name=_("Created by")) | ||||
|     last_updated_by = models.ForeignKey(User, related_name="updated_boxes", verbose_name=_("Last updated by")) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return self.label | ||||
| 
 | ||||
|     class Meta: | ||||
|         verbose_name_plural = "boxes" | ||||
| 
 | ||||
|         verbose_name = _("Box") | ||||
|         verbose_name_plural = _("Boxes") | ||||
| 
 | ||||
| reversion.register(Box) | ||||
|  |  | |||
|  | @ -40,6 +40,10 @@ class Page(models.Model): | |||
|     def __str__(self): | ||||
|         return self.title | ||||
| 
 | ||||
|     class Meta: | ||||
|         verbose_name = _("page") | ||||
|         verbose_name_plural = _("pages") | ||||
| 
 | ||||
|     @models.permalink | ||||
|     def get_absolute_url(self): | ||||
|         return ("cms_page", [self.path]) | ||||
|  |  | |||
|  | @ -1,8 +1,9 @@ | |||
| from __future__ import unicode_literals | ||||
| from django.apps import AppConfig | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| 
 | ||||
| 
 | ||||
| class ConferenceConfig(AppConfig): | ||||
|     name = "symposion.conference" | ||||
|     label = "symposion_conference" | ||||
|     verbose_name = "Symposion Conference" | ||||
|     verbose_name = _("Symposion Conference") | ||||
|  |  | |||
|  | @ -15,11 +15,11 @@ class Conference(models.Model): | |||
|     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 | ||||
|     start_date = models.DateField(_("start date"), null=True, blank=True) | ||||
|     end_date = models.DateField(_("end 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) | ||||
| 
 | ||||
|     # timezone the conference is in | ||||
|     timezone = TimeZoneField(blank=True, verbose_name=_("timezone")) | ||||
|  | @ -53,14 +53,14 @@ class Section(models.Model): | |||
|     scheduling process. | ||||
|     """ | ||||
| 
 | ||||
|     conference = models.ForeignKey(Conference, verbose_name=_("conference")) | ||||
|     conference = models.ForeignKey(Conference, verbose_name=_("Conference")) | ||||
| 
 | ||||
|     name = models.CharField(_("name"), max_length=100) | ||||
|     slug = models.SlugField() | ||||
|     name = models.CharField(_("Name"), max_length=100) | ||||
|     slug = models.SlugField(verbose_name=_("Slug")) | ||||
| 
 | ||||
|     # when the section runs | ||||
|     start_date = models.DateField(_("start date"), null=True, blank=True) | ||||
|     end_date = models.DateField(_("end 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) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return "%s %s" % (self.conference, self.name) | ||||
|  |  | |||
|  | @ -6,13 +6,14 @@ except ImportError: | |||
| from django import forms | ||||
| 
 | ||||
| import account.forms | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| 
 | ||||
| 
 | ||||
| class SignupForm(account.forms.SignupForm): | ||||
| 
 | ||||
|     first_name = forms.CharField() | ||||
|     last_name = forms.CharField() | ||||
|     email_confirm = forms.EmailField(label="Confirm Email") | ||||
|     first_name = forms.CharField(label=_("First name")) | ||||
|     last_name = forms.CharField(label=_("Last name")) | ||||
|     email_confirm = forms.EmailField(label=_("Confirm Email")) | ||||
| 
 | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         super(SignupForm, self).__init__(*args, **kwargs) | ||||
|  | @ -32,7 +33,7 @@ class SignupForm(account.forms.SignupForm): | |||
|         if email: | ||||
|             if email != email_confirm: | ||||
|                 raise forms.ValidationError( | ||||
|                     "Email address must match previously typed email address") | ||||
|                     _("Email address must match previously typed email address")) | ||||
|         return email_confirm | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,10 +2,11 @@ from __future__ import unicode_literals | |||
| import csv | ||||
| 
 | ||||
| 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", | ||||
|                          fields=None, exclude=None, header=True): | ||||
| def export_as_csv_action(description=None, fields=None, exclude=None, | ||||
|                          header=True): | ||||
|     """ | ||||
|     This function returns an export csv action | ||||
|     '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( | ||||
|                 [unicode(getattr(obj, field)).encode("utf-8", "replace") for field in field_names]) | ||||
|         return response | ||||
|     if description is None: | ||||
|         description = _("Export selected objects as CSV file") | ||||
|     export_as_csv.short_description = description | ||||
|     return export_as_csv | ||||
|  |  | |||
|  | @ -1,8 +1,9 @@ | |||
| from __future__ import unicode_literals | ||||
| from django.apps import AppConfig | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| 
 | ||||
| 
 | ||||
| class ProposalsConfig(AppConfig): | ||||
|     name = "symposion.proposals" | ||||
|     label = "symposion_proposals" | ||||
|     verbose_name = "Symposion Proposals" | ||||
|     verbose_name = _("Symposion Proposals") | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| from __future__ import unicode_literals | ||||
| from django import forms | ||||
| from django.db.models import Q | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| 
 | ||||
| from symposion.proposals.models import SupportingDocument | ||||
| # from markitup.widgets import MarkItUpWidget | ||||
|  | @ -12,7 +13,7 @@ from symposion.proposals.models import SupportingDocument | |||
| class AddSpeakerForm(forms.Form): | ||||
| 
 | ||||
|     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): | ||||
|  | @ -27,7 +28,7 @@ class AddSpeakerForm(forms.Form): | |||
|         ).exists() | ||||
|         if exists: | ||||
|             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 | ||||
| 
 | ||||
|  |  | |||
|  | @ -34,12 +34,12 @@ class ProposalSection(models.Model): | |||
|       * closed is NULL or False | ||||
|     """ | ||||
| 
 | ||||
|     section = models.OneToOneField(Section) | ||||
|     section = models.OneToOneField(Section, verbose_name=_("Section")) | ||||
| 
 | ||||
|     start = models.DateTimeField(null=True, blank=True) | ||||
|     end = models.DateTimeField(null=True, blank=True) | ||||
|     closed = models.NullBooleanField() | ||||
|     published = models.NullBooleanField() | ||||
|     start = models.DateTimeField(null=True, blank=True, verbose_name=_("Start")) | ||||
|     end = models.DateTimeField(null=True, blank=True, verbose_name=_("End")) | ||||
|     closed = models.NullBooleanField(verbose_name=_("Closed")) | ||||
|     published = models.NullBooleanField(verbose_name=_("Published")) | ||||
| 
 | ||||
|     @classmethod | ||||
|     def available(cls): | ||||
|  | @ -71,10 +71,10 @@ class ProposalKind(models.Model): | |||
|     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) | ||||
|     slug = models.SlugField() | ||||
|     slug = models.SlugField(verbose_name=_("Slug")) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return self.name | ||||
|  | @ -85,9 +85,9 @@ class ProposalBase(models.Model): | |||
| 
 | ||||
|     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( | ||||
|         _("Brief Description"), | ||||
|         max_length=400,  # @@@ need to enforce 400 in UI | ||||
|  | @ -101,6 +101,7 @@ class ProposalBase(models.Model): | |||
|                     "target='_blank'>Markdown</a>.") | ||||
|     ) | ||||
|     additional_notes = MarkupField( | ||||
|         _("Addtional Notes"), | ||||
|         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 " | ||||
|  | @ -110,8 +111,9 @@ class ProposalBase(models.Model): | |||
|     submitted = models.DateTimeField( | ||||
|         default=now, | ||||
|         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): | ||||
|         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) | ||||
| 
 | ||||
|     additional_speakers = models.ManyToManyField(Speaker, through="AdditionalSpeaker", | ||||
|                                                  blank=True, validators=[additional_speaker_validator]) | ||||
|     cancelled = models.BooleanField(default=False) | ||||
|                                                  blank=True, verbose_name=_("Addtional speakers"), | ||||
|                                                  validators=[additional_speaker_validator]) | ||||
|     cancelled = models.BooleanField(default=False, verbose_name=_("Cancelled")) | ||||
| 
 | ||||
|     def can_edit(self): | ||||
|         return True | ||||
|  | @ -179,12 +182,14 @@ class AdditionalSpeaker(models.Model): | |||
|         (SPEAKING_STATUS_DECLINED, _("Declined")), | ||||
|     ] | ||||
| 
 | ||||
|     speaker = models.ForeignKey(Speaker) | ||||
|     proposalbase = models.ForeignKey(ProposalBase) | ||||
|     status = models.IntegerField(choices=SPEAKING_STATUS, default=SPEAKING_STATUS_PENDING) | ||||
|     speaker = models.ForeignKey(Speaker, verbose_name=_("Speaker")) | ||||
|     proposalbase = models.ForeignKey(ProposalBase, verbose_name=_("Proposalbase")) | ||||
|     status = models.IntegerField(choices=SPEAKING_STATUS, default=SPEAKING_STATUS_PENDING, verbose_name=_("Status")) | ||||
| 
 | ||||
|     class Meta: | ||||
|         unique_together = ("speaker", "proposalbase") | ||||
|         verbose_name = _("Addtional speaker") | ||||
|         verbose_name_plural = _("Additional speakers") | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         if self.status is self.SPEAKING_STATUS_PENDING: | ||||
|  | @ -203,14 +208,14 @@ def uuid_filename(instance, filename): | |||
| 
 | ||||
| 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) | ||||
|     description = models.CharField(max_length=140) | ||||
|     file = models.FileField(upload_to=uuid_filename, verbose_name=_("File")) | ||||
|     description = models.CharField(max_length=140, verbose_name=_("Description")) | ||||
| 
 | ||||
|     def download_url(self): | ||||
|         return reverse("proposal_document_download", | ||||
|  |  | |||
|  | @ -88,7 +88,7 @@ def proposal_submit_kind(request, kind_slug): | |||
|             proposal.speaker = speaker_profile | ||||
|             proposal.save() | ||||
|             form.save_m2m() | ||||
|             messages.success(request, "Proposal submitted.") | ||||
|             messages.success(request, _("Proposal submitted.")) | ||||
|             if "add-speakers" in request.POST: | ||||
|                 return redirect("proposal_speaker_manage", proposal.pk) | ||||
|             return redirect("dashboard") | ||||
|  |  | |||
|  | @ -1,8 +1,9 @@ | |||
| from __future__ import unicode_literals | ||||
| from django.apps import AppConfig | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| 
 | ||||
| 
 | ||||
| class ReviewsConfig(AppConfig): | ||||
|     name = "symposion.reviews" | ||||
|     label = "symposion_reviews" | ||||
|     verbose_name = "Symposion Reviews" | ||||
|     verbose_name = _("Symposion Reviews") | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| from __future__ import unicode_literals | ||||
| from django import forms | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| 
 | ||||
| from markitup.widgets import MarkItUpWidget | ||||
| 
 | ||||
|  | @ -36,6 +37,7 @@ class SpeakerCommentForm(forms.ModelForm): | |||
| 
 | ||||
| class BulkPresentationForm(forms.Form): | ||||
|     talk_ids = forms.CharField( | ||||
|         label=_("Talk ids"), | ||||
|         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.") | ||||
|     ) | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ from django.db.models import Q | |||
| from django.db.models.signals import post_save | ||||
| 
 | ||||
| from django.contrib.auth.models import User | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| 
 | ||||
| from markitup.fields import MarkupField | ||||
| 
 | ||||
|  | @ -32,10 +33,10 @@ class Votes(object): | |||
|     MINUS_ONE = "−1" | ||||
| 
 | ||||
|     CHOICES = [ | ||||
|         (PLUS_ONE, u"+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."), | ||||
|         (MINUS_ZERO, u"−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."), | ||||
|         (PLUS_ONE, _("+1 — Good proposal and I will argue for it to be accepted.")), | ||||
|         (PLUS_ZERO, _("+0 — OK proposal, but I will not argue for it to be accepted.")), | ||||
|         (MINUS_ZERO, _("−0 — Weak proposal, but I will not argue strongly against acceptance.")), | ||||
|         (MINUS_ONE, _("−1 — Serious issues and I will argue to reject this proposal.")), | ||||
|     ] | ||||
| VOTES = Votes() | ||||
| 
 | ||||
|  | @ -48,18 +49,18 @@ class ReviewAssignment(models.Model): | |||
|     NUM_REVIEWERS = 3 | ||||
| 
 | ||||
|     ORIGIN_CHOICES = [ | ||||
|         (AUTO_ASSIGNED_INITIAL, "auto-assigned, initial"), | ||||
|         (OPT_IN, "opted-in"), | ||||
|         (AUTO_ASSIGNED_LATER, "auto-assigned, later"), | ||||
|         (AUTO_ASSIGNED_INITIAL, _("auto-assigned, initial")), | ||||
|         (OPT_IN, _("opted-in")), | ||||
|         (AUTO_ASSIGNED_LATER, _("auto-assigned, later")), | ||||
|     ] | ||||
| 
 | ||||
|     proposal = models.ForeignKey(ProposalBase) | ||||
|     user = models.ForeignKey(User) | ||||
|     proposal = models.ForeignKey(ProposalBase, verbose_name=_("Proposal")) | ||||
|     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) | ||||
|     opted_out = models.BooleanField(default=False) | ||||
|     assigned_at = models.DateTimeField(default=datetime.now, verbose_name=_("Assigned at")) | ||||
|     opted_out = models.BooleanField(default=False, verbose_name=_("Opted out")) | ||||
| 
 | ||||
|     @classmethod | ||||
|     def create_assignments(cls, proposal, origin=AUTO_ASSIGNED_INITIAL): | ||||
|  | @ -93,27 +94,29 @@ class ReviewAssignment(models.Model): | |||
| 
 | ||||
| 
 | ||||
| class ProposalMessage(models.Model): | ||||
|     proposal = models.ForeignKey(ProposalBase, related_name="messages") | ||||
|     user = models.ForeignKey(User) | ||||
|     proposal = models.ForeignKey(ProposalBase, related_name="messages", verbose_name=_("Proposal")) | ||||
|     user = models.ForeignKey(User, verbose_name=_("User")) | ||||
| 
 | ||||
|     message = MarkupField() | ||||
|     submitted_at = models.DateTimeField(default=datetime.now, editable=False) | ||||
|     message = MarkupField(verbose_name=_("Message")) | ||||
|     submitted_at = models.DateTimeField(default=datetime.now, editable=False, verbose_name=_("Submitted at")) | ||||
| 
 | ||||
|     class Meta: | ||||
|         ordering = ["submitted_at"] | ||||
|         verbose_name = _("proposal message") | ||||
|         verbose_name_plural = _("proposal messages") | ||||
| 
 | ||||
| 
 | ||||
| class Review(models.Model): | ||||
|     VOTES = VOTES | ||||
| 
 | ||||
|     proposal = models.ForeignKey(ProposalBase, related_name="reviews") | ||||
|     user = models.ForeignKey(User) | ||||
|     proposal = models.ForeignKey(ProposalBase, related_name="reviews", verbose_name=_("Proposal")) | ||||
|     user = models.ForeignKey(User, verbose_name=_("User")) | ||||
| 
 | ||||
|     # No way to encode "-0" vs. "+0" into an IntegerField, and I don't feel | ||||
|     # like some complicated encoding system. | ||||
|     vote = models.CharField(max_length=2, blank=True, choices=VOTES.CHOICES) | ||||
|     comment = MarkupField() | ||||
|     submitted_at = models.DateTimeField(default=datetime.now, editable=False) | ||||
|     vote = models.CharField(max_length=2, blank=True, choices=VOTES.CHOICES, verbose_name=_("Vote")) | ||||
|     comment = MarkupField(verbose_name=_("Comment")) | ||||
|     submitted_at = models.DateTimeField(default=datetime.now, editable=False, verbose_name=_("Submitted at")) | ||||
| 
 | ||||
|     def save(self, **kwargs): | ||||
|         if self.vote: | ||||
|  | @ -181,20 +184,26 @@ class Review(models.Model): | |||
|     def section(self): | ||||
|         return self.proposal.kind.section.slug | ||||
| 
 | ||||
|     class Meta: | ||||
|         verbose_name = _("review") | ||||
|         verbose_name_plural = _("reviews") | ||||
| 
 | ||||
| 
 | ||||
| class LatestVote(models.Model): | ||||
|     VOTES = VOTES | ||||
| 
 | ||||
|     proposal = models.ForeignKey(ProposalBase, related_name="votes") | ||||
|     user = models.ForeignKey(User) | ||||
|     proposal = models.ForeignKey(ProposalBase, related_name="votes", verbose_name=_("Proposal")) | ||||
|     user = models.ForeignKey(User, verbose_name=_("User")) | ||||
| 
 | ||||
|     # No way to encode "-0" vs. "+0" into an IntegerField, and I don't feel | ||||
|     # like some complicated encoding system. | ||||
|     vote = models.CharField(max_length=2, choices=VOTES.CHOICES) | ||||
|     submitted_at = models.DateTimeField(default=datetime.now, editable=False) | ||||
|     vote = models.CharField(max_length=2, choices=VOTES.CHOICES, verbose_name=_("Vote")) | ||||
|     submitted_at = models.DateTimeField(default=datetime.now, editable=False, verbose_name=_("Submitted at")) | ||||
| 
 | ||||
|     class Meta: | ||||
|         unique_together = [("proposal", "user")] | ||||
|         verbose_name = _("latest vote") | ||||
|         verbose_name_plural = _("latest votes") | ||||
| 
 | ||||
|     def css_class(self): | ||||
|         return { | ||||
|  | @ -206,25 +215,25 @@ class LatestVote(models.Model): | |||
| 
 | ||||
| 
 | ||||
| class ProposalResult(models.Model): | ||||
|     proposal = models.OneToOneField(ProposalBase, related_name="result") | ||||
|     score = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal("0.00")) | ||||
|     comment_count = models.PositiveIntegerField(default=0) | ||||
|     vote_count = models.PositiveIntegerField(default=0) | ||||
|     plus_one = models.PositiveIntegerField(default=0) | ||||
|     plus_zero = models.PositiveIntegerField(default=0) | ||||
|     minus_zero = models.PositiveIntegerField(default=0) | ||||
|     minus_one = models.PositiveIntegerField(default=0) | ||||
|     proposal = models.OneToOneField(ProposalBase, related_name="result", verbose_name=_("Proposal")) | ||||
|     score = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal("0.00"), verbose_name=_("Score")) | ||||
|     comment_count = models.PositiveIntegerField(default=0, verbose_name=_("Comment count")) | ||||
|     vote_count = models.PositiveIntegerField(default=0, verbose_name=_("Vote count")) | ||||
|     plus_one = models.PositiveIntegerField(default=0, verbose_name=_("Plus one")) | ||||
|     plus_zero = models.PositiveIntegerField(default=0, verbose_name=_("Plus zero")) | ||||
|     minus_zero = models.PositiveIntegerField(default=0, verbose_name=_("Minus zero")) | ||||
|     minus_one = models.PositiveIntegerField(default=0, verbose_name=_("Minus one")) | ||||
|     accepted = models.NullBooleanField(choices=[ | ||||
|         (True, "accepted"), | ||||
|         (False, "rejected"), | ||||
|         (None, "undecided"), | ||||
|     ], default=None) | ||||
|     ], default=None, verbose_name=_("Accepted")) | ||||
|     status = models.CharField(max_length=20, choices=[ | ||||
|         ("accepted", "accepted"), | ||||
|         ("rejected", "rejected"), | ||||
|         ("undecided", "undecided"), | ||||
|         ("standby", "standby"), | ||||
|     ], default="undecided") | ||||
|         ("accepted", _("accepted")), | ||||
|         ("rejected", _("rejected")), | ||||
|         ("undecided", _("undecided")), | ||||
|         ("standby", _("standby")), | ||||
|     ], default="undecided", verbose_name=_("Status")) | ||||
| 
 | ||||
|     @classmethod | ||||
|     def full_calculate(cls): | ||||
|  | @ -280,35 +289,47 @@ class ProposalResult(models.Model): | |||
|         model = self.__class__ | ||||
|         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): | ||||
|     proposal = models.ForeignKey(ProposalBase, related_name="comments") | ||||
|     commenter = models.ForeignKey(User) | ||||
|     text = MarkupField() | ||||
|     proposal = models.ForeignKey(ProposalBase, related_name="comments", verbose_name=_("Proposal")) | ||||
|     commenter = models.ForeignKey(User, verbose_name=_("Commenter")) | ||||
|     text = MarkupField(verbose_name=_("Text")) | ||||
| 
 | ||||
|     # Or perhaps more accurately, can the user see this comment. | ||||
|     public = models.BooleanField(choices=[(True, "public"), (False, "private")], default=False) | ||||
|     commented_at = models.DateTimeField(default=datetime.now) | ||||
|     public = models.BooleanField(choices=[(True, _("public")), (False, _("private"))], default=False, verbose_name=_("Public")) | ||||
|     commented_at = models.DateTimeField(default=datetime.now, verbose_name=_("Commented at")) | ||||
| 
 | ||||
|     class Meta: | ||||
|         verbose_name = _("comment") | ||||
|         verbose_name_plural = _("comments") | ||||
| 
 | ||||
| 
 | ||||
| class NotificationTemplate(models.Model): | ||||
| 
 | ||||
|     label = models.CharField(max_length=100) | ||||
|     from_address = models.EmailField() | ||||
|     subject = models.CharField(max_length=100) | ||||
|     body = models.TextField() | ||||
|     label = models.CharField(max_length=100, verbose_name=_("Label")) | ||||
|     from_address = models.EmailField(verbose_name=_("From address")) | ||||
|     subject = models.CharField(max_length=100, verbose_name=_("Subject")) | ||||
|     body = models.TextField(verbose_name=_("Body")) | ||||
| 
 | ||||
|     class Meta: | ||||
|         verbose_name = _("notification template") | ||||
|         verbose_name_plural = _("notification templates") | ||||
| 
 | ||||
| 
 | ||||
| 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, | ||||
|                                  on_delete=models.SET_NULL) | ||||
|     timestamp = models.DateTimeField(default=datetime.now) | ||||
|     to_address = models.EmailField() | ||||
|     from_address = models.EmailField() | ||||
|     subject = models.CharField(max_length=100) | ||||
|     body = models.TextField() | ||||
|                                  on_delete=models.SET_NULL, verbose_name=_("Template")) | ||||
|     timestamp = models.DateTimeField(default=datetime.now, verbose_name=_("Timestamp")) | ||||
|     to_address = models.EmailField(verbose_name=_("To address")) | ||||
|     from_address = models.EmailField(verbose_name=_("From address")) | ||||
|     subject = models.CharField(max_length=100, verbose_name=_("Subject")) | ||||
|     body = models.TextField(verbose_name=_("Body")) | ||||
| 
 | ||||
|     def recipients(self): | ||||
|         for speaker in self.proposal.speakers(): | ||||
|  |  | |||
|  | @ -1,10 +1,12 @@ | |||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| import datetime | ||||
| 
 | ||||
| from django.core.exceptions import ObjectDoesNotExist | ||||
| from django.contrib.auth.models import User | ||||
| from django.db import models | ||||
| from django.utils.encoding import python_2_unicode_compatible | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| 
 | ||||
| from markitup.fields import MarkupField | ||||
| 
 | ||||
|  | @ -16,22 +18,24 @@ from symposion.speakers.models import Speaker | |||
| @python_2_unicode_compatible | ||||
| class Schedule(models.Model): | ||||
| 
 | ||||
|     section = models.OneToOneField(Section) | ||||
|     published = models.BooleanField(default=True) | ||||
|     hidden = models.BooleanField("Hide schedule from overall conference view", default=False) | ||||
|     section = models.OneToOneField(Section, verbose_name=_("Section")) | ||||
|     published = models.BooleanField(default=True, verbose_name=_("Published")) | ||||
|     hidden = models.BooleanField(_("Hide schedule from overall conference view"), default=False) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return "%s Schedule" % self.section | ||||
| 
 | ||||
|     class Meta: | ||||
|         ordering = ["section"] | ||||
|         verbose_name = _('Schedule') | ||||
|         verbose_name_plural = _('Schedules') | ||||
| 
 | ||||
| 
 | ||||
| @python_2_unicode_compatible | ||||
| class Day(models.Model): | ||||
| 
 | ||||
|     schedule = models.ForeignKey(Schedule) | ||||
|     date = models.DateField() | ||||
|     schedule = models.ForeignKey(Schedule, verbose_name=_("Schedule")) | ||||
|     date = models.DateField(verbose_name=_("Date")) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return "%s" % self.date | ||||
|  | @ -39,18 +43,24 @@ class Day(models.Model): | |||
|     class Meta: | ||||
|         unique_together = [("schedule", "date")] | ||||
|         ordering = ["date"] | ||||
|         verbose_name = _("date") | ||||
|         verbose_name_plural = _("dates") | ||||
| 
 | ||||
| 
 | ||||
| @python_2_unicode_compatible | ||||
| class Room(models.Model): | ||||
| 
 | ||||
|     schedule = models.ForeignKey(Schedule) | ||||
|     name = models.CharField(max_length=65) | ||||
|     order = models.PositiveIntegerField() | ||||
|     schedule = models.ForeignKey(Schedule, verbose_name=_("Schedule")) | ||||
|     name = models.CharField(max_length=65, verbose_name=_("Name")) | ||||
|     order = models.PositiveIntegerField(verbose_name=_("Order")) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return self.name | ||||
| 
 | ||||
|     class Meta: | ||||
|         verbose_name = _("Room") | ||||
|         verbose_name_plural = _("Rooms") | ||||
| 
 | ||||
| 
 | ||||
| @python_2_unicode_compatible | ||||
| class SlotKind(models.Model): | ||||
|  | @ -59,21 +69,25 @@ class SlotKind(models.Model): | |||
|     break, lunch, or X-minute talk. | ||||
|     """ | ||||
| 
 | ||||
|     schedule = models.ForeignKey(Schedule) | ||||
|     label = models.CharField(max_length=50) | ||||
|     schedule = models.ForeignKey(Schedule, verbose_name=_("schedule")) | ||||
|     label = models.CharField(max_length=50, verbose_name=_("Label")) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return self.label | ||||
| 
 | ||||
|     class Meta: | ||||
|         verbose_name = _("Slot kind") | ||||
|         verbose_name_plural = _("Slot kinds") | ||||
| 
 | ||||
| 
 | ||||
| @python_2_unicode_compatible | ||||
| class Slot(models.Model): | ||||
| 
 | ||||
|     day = models.ForeignKey(Day) | ||||
|     kind = models.ForeignKey(SlotKind) | ||||
|     start = models.TimeField() | ||||
|     end = models.TimeField() | ||||
|     content_override = MarkupField(blank=True) | ||||
|     day = models.ForeignKey(Day, verbose_name=_("Day")) | ||||
|     kind = models.ForeignKey(SlotKind, verbose_name=_("Kind")) | ||||
|     start = models.TimeField(verbose_name=_("Start")) | ||||
|     end = models.TimeField(verbose_name=_("End")) | ||||
|     content_override = MarkupField(blank=True, verbose_name=_("Content override")) | ||||
| 
 | ||||
|     def assign(self, content): | ||||
|         """ | ||||
|  | @ -137,6 +151,8 @@ class Slot(models.Model): | |||
| 
 | ||||
|     class Meta: | ||||
|         ordering = ["day", "start", "end"] | ||||
|         verbose_name = _("slot") | ||||
|         verbose_name_plural = _("slots") | ||||
| 
 | ||||
| 
 | ||||
| @python_2_unicode_compatible | ||||
|  | @ -145,8 +161,8 @@ class SlotRoom(models.Model): | |||
|     Links a slot with a room. | ||||
|     """ | ||||
| 
 | ||||
|     slot = models.ForeignKey(Slot) | ||||
|     room = models.ForeignKey(Room) | ||||
|     slot = models.ForeignKey(Slot, verbose_name=_("Slot")) | ||||
|     room = models.ForeignKey(Room, verbose_name=_("Room")) | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return "%s %s" % (self.room, self.slot) | ||||
|  | @ -154,21 +170,23 @@ class SlotRoom(models.Model): | |||
|     class Meta: | ||||
|         unique_together = [("slot", "room")] | ||||
|         ordering = ["slot", "room__order"] | ||||
|         verbose_name = _("Slot room") | ||||
|         verbose_name_plural = _("Slot rooms") | ||||
| 
 | ||||
| 
 | ||||
| @python_2_unicode_compatible | ||||
| class Presentation(models.Model): | ||||
| 
 | ||||
|     slot = models.OneToOneField(Slot, null=True, blank=True, related_name="content_ptr") | ||||
|     title = models.CharField(max_length=100) | ||||
|     description = MarkupField() | ||||
|     abstract = MarkupField() | ||||
|     speaker = models.ForeignKey(Speaker, related_name="presentations") | ||||
|     slot = models.OneToOneField(Slot, null=True, blank=True, related_name="content_ptr", verbose_name=_("Slot")) | ||||
|     title = models.CharField(max_length=100, verbose_name=_("Title")) | ||||
|     description = MarkupField(verbose_name=_("Description")) | ||||
|     abstract = MarkupField(verbose_name=_("Abstract")) | ||||
|     speaker = models.ForeignKey(Speaker, related_name="presentations", verbose_name=_("Speaker")) | ||||
|     additional_speakers = models.ManyToManyField(Speaker, related_name="copresentations", | ||||
|                                                  blank=True) | ||||
|     cancelled = models.BooleanField(default=False) | ||||
|     proposal_base = models.OneToOneField(ProposalBase, related_name="presentation") | ||||
|     section = models.ForeignKey(Section, related_name="presentations") | ||||
|                                                  blank=True, verbose_name=_("Additional speakers")) | ||||
|     cancelled = models.BooleanField(default=False, verbose_name=_("Cancelled")) | ||||
|     proposal_base = models.OneToOneField(ProposalBase, related_name="presentation", verbose_name=_("Proposal base")) | ||||
|     section = models.ForeignKey(Section, related_name="presentations", verbose_name=_("Section")) | ||||
| 
 | ||||
|     @property | ||||
|     def number(self): | ||||
|  | @ -191,13 +209,15 @@ class Presentation(models.Model): | |||
| 
 | ||||
|     class Meta: | ||||
|         ordering = ["slot"] | ||||
|         verbose_name = _("presentation") | ||||
|         verbose_name_plural = _("presentations") | ||||
| 
 | ||||
| 
 | ||||
| @python_2_unicode_compatible | ||||
| class Session(models.Model): | ||||
| 
 | ||||
|     day = models.ForeignKey(Day, related_name="sessions") | ||||
|     slots = models.ManyToManyField(Slot, related_name="sessions") | ||||
|     day = models.ForeignKey(Day, related_name="sessions", verbose_name=_("Day")) | ||||
|     slots = models.ManyToManyField(Slot, related_name="sessions", verbose_name=_("Slots")) | ||||
| 
 | ||||
|     def sorted_slots(self): | ||||
|         return self.slots.order_by("start") | ||||
|  | @ -227,6 +247,10 @@ class Session(models.Model): | |||
|             ) | ||||
|         return "" | ||||
| 
 | ||||
|     class Meta: | ||||
|         verbose_name = _("Session") | ||||
|         verbose_name_plural = _("Sessions") | ||||
| 
 | ||||
| 
 | ||||
| @python_2_unicode_compatible | ||||
| class SessionRole(models.Model): | ||||
|  | @ -235,19 +259,21 @@ class SessionRole(models.Model): | |||
|     SESSION_ROLE_RUNNER = 2 | ||||
| 
 | ||||
|     SESSION_ROLE_TYPES = [ | ||||
|         (SESSION_ROLE_CHAIR, "Session Chair"), | ||||
|         (SESSION_ROLE_RUNNER, "Session Runner"), | ||||
|         (SESSION_ROLE_CHAIR, _("Session Chair")), | ||||
|         (SESSION_ROLE_RUNNER, _("Session Runner")), | ||||
|     ] | ||||
| 
 | ||||
|     session = models.ForeignKey(Session) | ||||
|     user = models.ForeignKey(User) | ||||
|     role = models.IntegerField(choices=SESSION_ROLE_TYPES) | ||||
|     status = models.NullBooleanField() | ||||
|     session = models.ForeignKey(Session, verbose_name=_("Session")) | ||||
|     user = models.ForeignKey(User, verbose_name=_("User")) | ||||
|     role = models.IntegerField(choices=SESSION_ROLE_TYPES, verbose_name=_("Role")) | ||||
|     status = models.NullBooleanField(verbose_name=_("Status")) | ||||
| 
 | ||||
|     submitted = models.DateTimeField(default=datetime.datetime.now) | ||||
| 
 | ||||
|     class Meta: | ||||
|         unique_together = [("session", "user", "role")] | ||||
|         verbose_name = _("Session role") | ||||
|         verbose_name_plural = _("Session roles") | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return "%s %s: %s" % (self.user, self.session, | ||||
|  |  | |||
|  | @ -1,8 +1,9 @@ | |||
| from __future__ import unicode_literals | ||||
| from django.apps import AppConfig | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| 
 | ||||
| 
 | ||||
| class SpeakersConfig(AppConfig): | ||||
|     name = "symposion.speakers" | ||||
|     label = "symposion_speakers" | ||||
|     verbose_name = "Symposion Speakers" | ||||
|     verbose_name = _("Symposion Speakers") | ||||
|  |  | |||
|  | @ -1,9 +1,11 @@ | |||
| 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.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 | ||||
| 
 | ||||
|  | @ -18,24 +20,28 @@ class Speaker(models.Model): | |||
|         (2, "Two") | ||||
|     ] | ||||
| 
 | ||||
|     user = models.OneToOneField(User, null=True, related_name="speaker_profile") | ||||
|     name = models.CharField(max_length=100, help_text=("As you would like it to appear in the " | ||||
|                                                        "conference program.")) | ||||
|     biography = MarkupField(blank=True, help_text=("A little bit about you.  Edit using " | ||||
|                                                    "<a href='http://warpedvisions.org/projects/" | ||||
|                                                    "markdown-cheat-sheet/target='_blank'>" | ||||
|                                                    "Markdown</a>.")) | ||||
|     photo = models.ImageField(upload_to="speaker_photos", blank=True) | ||||
|     annotation = models.TextField()  # staff only | ||||
|     invite_email = models.CharField(max_length=200, unique=True, null=True, db_index=True) | ||||
|     invite_token = models.CharField(max_length=40, db_index=True) | ||||
|     user = models.OneToOneField(User, null=True, related_name="speaker_profile", verbose_name=_("User")) | ||||
|     name = models.CharField(verbose_name=_("Name"), max_length=100, | ||||
|                             help_text=_("As you would like it to appear in the" | ||||
|                                         " conference program.")) | ||||
|     biography = MarkupField(blank=True, help_text=_("A little bit about you.  Edit using " | ||||
|                                                     "<a href='http://warpedvisions.org/projects/" | ||||
|                                                     "markdown-cheat-sheet/target='_blank'>" | ||||
|                                                     "Markdown</a>."), verbose_name=_("Biography")) | ||||
|     photo = models.ImageField(upload_to="speaker_photos", blank=True, verbose_name=_("Photo")) | ||||
|     annotation = models.TextField(verbose_name=_("Annotation"))  # staff only | ||||
|     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, verbose_name=_("Invite token")) | ||||
|     created = models.DateTimeField( | ||||
|         default=datetime.datetime.now, | ||||
|         editable=False | ||||
|         editable=False, | ||||
|         verbose_name=_("Created") | ||||
|     ) | ||||
| 
 | ||||
|     class Meta: | ||||
|         ordering = ['name'] | ||||
|         verbose_name = _("Speaker") | ||||
|         verbose_name_plural = _("Speakers") | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         if self.user: | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ from django.shortcuts import render, redirect, get_object_or_404 | |||
| from django.contrib import messages | ||||
| from django.contrib.auth.decorators import login_required | ||||
| from django.contrib.auth.models import User | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| 
 | ||||
| from symposion.proposals.models import ProposalBase | ||||
| from symposion.speakers.forms import SpeakerForm | ||||
|  | @ -34,7 +35,7 @@ def speaker_create(request): | |||
|             if not found: | ||||
|                 speaker.invite_email = None | ||||
|             speaker.save() | ||||
|             messages.success(request, "Speaker profile created.") | ||||
|             messages.success(request, _("Speaker profile created.")) | ||||
|             return redirect("dashboard") | ||||
|     else: | ||||
|         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.user = user | ||||
|             speaker.save() | ||||
|             messages.success(request, "Speaker profile created.") | ||||
|             messages.success(request, _("Speaker profile created.")) | ||||
|             return redirect("user_list") | ||||
|     else: | ||||
|         form = SpeakerForm(initial={"name": user.get_full_name()}) | ||||
|  | @ -89,8 +90,8 @@ def speaker_create_token(request, token): | |||
|             ).update( | ||||
|                 speaker=existing_speaker | ||||
|             ) | ||||
|             messages.info(request, ("You have been associated with all pending " | ||||
|                                     "talk proposals")) | ||||
|             messages.info(request, _("You have been associated with all pending " | ||||
|                                      "talk proposals")) | ||||
|             return redirect("dashboard") | ||||
|     else: | ||||
|         if not request.user.is_authenticated(): | ||||
|  |  | |||
|  | @ -69,9 +69,9 @@ class SponsorAdmin(admin.ModelAdmin): | |||
|         # @@@ kinda ugly but using choices= on NullBooleanField is broken | ||||
|         form = super(SponsorAdmin, self).get_form(*args, **kwargs) | ||||
|         form.base_fields["active"].widget.choices = [ | ||||
|             (u"1", _("unreviewed")), | ||||
|             (u"2", _("approved")), | ||||
|             (u"3", _("rejected")) | ||||
|             ("1", _("unreviewed")), | ||||
|             ("2", _("approved")), | ||||
|             ("3", _("rejected")) | ||||
|         ] | ||||
|         return form | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,7 +1,9 @@ | |||
| from __future__ import unicode_literals | ||||
| from django.apps import AppConfig | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| 
 | ||||
| 
 | ||||
| class SponsorshipConfig(AppConfig): | ||||
|     name = "symposion.sponsorship" | ||||
|     label = "symposion_sponsorship" | ||||
|     verbose_name = "Symposion Sponsorship" | ||||
|     verbose_name = _("Symposion Sponsorship") | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ from django import forms | |||
| from django.forms.models import inlineformset_factory, BaseInlineFormSet | ||||
| 
 | ||||
| from django.contrib.admin.widgets import AdminFileWidget | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| 
 | ||||
| from symposion.sponsorship.models import Sponsor, SponsorBenefit | ||||
| 
 | ||||
|  | @ -65,7 +66,7 @@ class SponsorBenefitsInlineFormSet(BaseInlineFormSet): | |||
| 
 | ||||
|             # provide word limit as help_text | ||||
|             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 | ||||
|             if field == "upload": | ||||
|  |  | |||
|  | @ -48,16 +48,16 @@ BENEFITS = [ | |||
| @python_2_unicode_compatible | ||||
| class SponsorLevel(models.Model): | ||||
| 
 | ||||
|     conference = models.ForeignKey(Conference, verbose_name=_("conference")) | ||||
|     name = models.CharField(_("name"), max_length=100) | ||||
|     order = models.IntegerField(_("order"), default=0) | ||||
|     cost = models.PositiveIntegerField(_("cost")) | ||||
|     description = models.TextField(_("description"), blank=True, help_text=_("This is private.")) | ||||
|     conference = models.ForeignKey(Conference, verbose_name=_("Conference")) | ||||
|     name = models.CharField(_("Name"), max_length=100) | ||||
|     order = models.IntegerField(_("Order"), default=0) | ||||
|     cost = models.PositiveIntegerField(_("Cost")) | ||||
|     description = models.TextField(_("Description"), blank=True, help_text=_("This is private.")) | ||||
| 
 | ||||
|     class Meta: | ||||
|         ordering = ["conference", "order"] | ||||
|         verbose_name = _("sponsor level") | ||||
|         verbose_name_plural = _("sponsor levels") | ||||
|         verbose_name = _("Sponsor level") | ||||
|         verbose_name_plural = _("Sponsor levels") | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return "%s %s" % (self.conference, self.name) | ||||
|  | @ -69,22 +69,22 @@ class SponsorLevel(models.Model): | |||
| @python_2_unicode_compatible | ||||
| 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) | ||||
| 
 | ||||
|     name = models.CharField(_("Sponsor Name"), max_length=100) | ||||
|     display_url = models.URLField(_("display URL"), blank=True) | ||||
|     external_url = models.URLField(_("external URL")) | ||||
|     annotation = models.TextField(_("annotation"), blank=True) | ||||
|     external_url = models.URLField(_("External URL")) | ||||
|     annotation = models.TextField(_("Annotation"), blank=True) | ||||
|     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")) | ||||
|     added = models.DateTimeField(_("added"), default=datetime.datetime.now) | ||||
|     active = models.BooleanField(_("active"), default=False) | ||||
| 
 | ||||
|     # Denormalization (this assumes only one logo) | ||||
|     sponsor_logo = models.ForeignKey("SponsorBenefit", related_name="+", null=True, blank=True, | ||||
|                                      editable=False) | ||||
|                                      editable=False, verbose_name=_("Sponsor logo")) | ||||
| 
 | ||||
|     # Whether things are complete | ||||
|     # True = complete, False = incomplate, Null = n/a for this sponsor level | ||||
|  | @ -99,8 +99,8 @@ class Sponsor(models.Model): | |||
|         return self.name | ||||
| 
 | ||||
|     class Meta: | ||||
|         verbose_name = _("sponsor") | ||||
|         verbose_name_plural = _("sponsors") | ||||
|         verbose_name = _("Sponsor") | ||||
|         verbose_name_plural = _("Sponsors") | ||||
|         ordering = ['name'] | ||||
| 
 | ||||
|     def save(self, *args, **kwargs): | ||||
|  | @ -213,12 +213,12 @@ post_save.connect(_check_level_change, sender=Sponsor) | |||
| 
 | ||||
| 
 | ||||
| BENEFIT_TYPE_CHOICES = [ | ||||
|     ("text", "Text"), | ||||
|     ("richtext", "Rich Text"), | ||||
|     ("file", "File"), | ||||
|     ("weblogo", "Web Logo"), | ||||
|     ("simple", "Simple"), | ||||
|     ("option", "Option") | ||||
|     ("text", _("Text")), | ||||
|     ("file", _("File")), | ||||
|     ("richtext", _("Rich Text")), | ||||
|     ("weblogo", _("Web Logo")), | ||||
|     ("simple", _("Simple")), | ||||
|     ("option", _("Option")) | ||||
| ] | ||||
| 
 | ||||
| CONTENT_TYPE_CHOICES = [ | ||||
|  | @ -231,10 +231,10 @@ CONTENT_TYPE_CHOICES = [ | |||
| @python_2_unicode_compatible | ||||
| class Benefit(models.Model): | ||||
| 
 | ||||
|     name = models.CharField(_("name"), max_length=100) | ||||
|     description = models.TextField(_("description"), blank=True) | ||||
|     type = models.CharField(_("type"), choices=BENEFIT_TYPE_CHOICES, | ||||
|                             max_length=10, default="simple") | ||||
|     name = models.CharField(_("Name"), max_length=100) | ||||
|     description = models.TextField(_("Description"), blank=True) | ||||
|     type = models.CharField(_("Type"), choices=BENEFIT_TYPE_CHOICES, max_length=10, | ||||
|                             default="simple") | ||||
|     content_type = models.CharField(_("content type"), choices=CONTENT_TYPE_CHOICES, | ||||
|                                     max_length=20, default="simple") | ||||
| 
 | ||||
|  | @ -245,15 +245,17 @@ class Benefit(models.Model): | |||
| @python_2_unicode_compatible | ||||
| class BenefitLevel(models.Model): | ||||
| 
 | ||||
|     benefit = models.ForeignKey(Benefit, related_name="benefit_levels", verbose_name=_("benefit")) | ||||
|     level = models.ForeignKey(SponsorLevel, related_name="benefit_levels", verbose_name=_("level")) | ||||
|     benefit = models.ForeignKey(Benefit, related_name="benefit_levels", verbose_name=_("Benefit")) | ||||
|     level = models.ForeignKey(SponsorLevel, related_name="benefit_levels", verbose_name=_("Level")) | ||||
| 
 | ||||
|     # default limits for this benefit at given level | ||||
|     max_words = models.PositiveIntegerField(_("max words"), blank=True, null=True) | ||||
|     other_limits = models.CharField(_("other limits"), max_length=200, blank=True) | ||||
|     max_words = models.PositiveIntegerField(_("Max words"), blank=True, null=True) | ||||
|     other_limits = models.CharField(_("Other limits"), max_length=200, blank=True) | ||||
| 
 | ||||
|     class Meta: | ||||
|         ordering = ["level"] | ||||
|         verbose_name = _("Benefit level") | ||||
|         verbose_name_plural = _("Benefit levels") | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         return "%s - %s" % (self.level, self.benefit) | ||||
|  | @ -262,18 +264,18 @@ class BenefitLevel(models.Model): | |||
| @python_2_unicode_compatible | ||||
| class SponsorBenefit(models.Model): | ||||
| 
 | ||||
|     sponsor = models.ForeignKey(Sponsor, related_name="sponsor_benefits", verbose_name=_("sponsor")) | ||||
|     benefit = models.ForeignKey(Benefit, related_name="sponsor_benefits", verbose_name=_("benefit")) | ||||
|     active = models.BooleanField(default=True) | ||||
|     sponsor = models.ForeignKey(Sponsor, related_name="sponsor_benefits", verbose_name=_("Sponsor")) | ||||
|     benefit = models.ForeignKey(Benefit, related_name="sponsor_benefits", verbose_name=_("Benefit")) | ||||
|     active = models.BooleanField(default=True, verbose_name=_("Active")) | ||||
| 
 | ||||
|     # Limits: will initially be set to defaults from corresponding BenefitLevel | ||||
|     max_words = models.PositiveIntegerField(_("max words"), blank=True, null=True) | ||||
|     other_limits = models.CharField(_("other limits"), max_length=200, blank=True) | ||||
|     max_words = models.PositiveIntegerField(_("Max words"), blank=True, null=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 | ||||
|     # type of the Benefit (text, file, or simple) | ||||
|     text = models.TextField(_("text"), blank=True) | ||||
|     upload = models.FileField(_("file"), blank=True, upload_to="sponsor_files") | ||||
|     text = models.TextField(_("Text"), blank=True) | ||||
|     upload = models.FileField(_("File"), blank=True, upload_to="sponsor_files") | ||||
| 
 | ||||
|     # Whether any assets required from the sponsor have been provided | ||||
|     # (e.g. a logo file for a Web logo benefit). | ||||
|  | @ -281,6 +283,8 @@ class SponsorBenefit(models.Model): | |||
| 
 | ||||
|     class Meta: | ||||
|         ordering = ["-active"] | ||||
|         verbose_name = _("Sponsor benefit") | ||||
|         verbose_name_plural = _("Sponsor benefits") | ||||
| 
 | ||||
|     def __str__(self): | ||||
|         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()) | ||||
|         if self.max_words and num_words > self.max_words: | ||||
|             raise ValidationError( | ||||
|                 "Sponsorship level only allows for %s words, you provided %d." % ( | ||||
|                     self.max_words, num_words)) | ||||
|                 _("Sponsorship level only allows for %(word)s words, you provided %(num)d.") % { | ||||
|                     "word": self.max_words, "num": num_words}) | ||||
| 
 | ||||
|     def data_fields(self): | ||||
|         """ | ||||
|  |  | |||
|  | @ -7,16 +7,14 @@ import time | |||
| from zipfile import ZipFile, ZipInfo | ||||
| 
 | ||||
| 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.shortcuts import render_to_response, redirect, get_object_or_404 | ||||
| from django.template import RequestContext | ||||
| 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, \ | ||||
|     SponsorDetailsForm, SponsorBenefitsFormSet | ||||
| from symposion.sponsorship.models import Benefit, Sponsor, SponsorBenefit, \ | ||||
|  | @ -91,7 +89,7 @@ def sponsor_detail(request, pk): | |||
|             form.save() | ||||
|             formset.save() | ||||
| 
 | ||||
|             messages.success(request, "Sponsorship details have been updated") | ||||
|             messages.success(request, _("Sponsorship details have been updated")) | ||||
| 
 | ||||
|             return redirect("dashboard") | ||||
|     else: | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ from django import forms | |||
| 
 | ||||
| from django.utils.html import escape | ||||
| from django.utils.safestring import mark_safe | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| 
 | ||||
| from django.contrib.auth.models import User | ||||
| 
 | ||||
|  | @ -11,8 +12,9 @@ from symposion.teams.models import Membership | |||
| 
 | ||||
| class TeamInvitationForm(forms.Form): | ||||
| 
 | ||||
|     email = forms.EmailField(help_text=("email address must be that of an account on this " | ||||
|                                         "conference site")) | ||||
|     email = forms.EmailField(label=_("Email"), | ||||
|                              help_text=_("email address must be that of an account on this " | ||||
|                                          "conference site")) | ||||
| 
 | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         self.team = kwargs.pop("team") | ||||
|  | @ -23,7 +25,7 @@ class TeamInvitationForm(forms.Form): | |||
|         email = cleaned_data.get("email") | ||||
| 
 | ||||
|         if email is None: | ||||
|             raise forms.ValidationError("valid email address required") | ||||
|             raise forms.ValidationError(_("valid email address required")) | ||||
| 
 | ||||
|         try: | ||||
|             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 | ||||
|             # already on the site | ||||
|             raise forms.ValidationError( | ||||
|                 mark_safe("no account with email address <b>%s</b> found on this conference " | ||||
|                           "site" % escape(email))) | ||||
|                 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) | ||||
| 
 | ||||
|         if state in ["member", "manager"]: | ||||
|             raise forms.ValidationError("user already in team") | ||||
|             raise forms.ValidationError(_("user already in team")) | ||||
| 
 | ||||
|         if state in ["invited"]: | ||||
|             raise forms.ValidationError("user already invited to team") | ||||
|             raise forms.ValidationError(_("user already invited to team")) | ||||
| 
 | ||||
|         self.user = user | ||||
|         self.state = state | ||||
|  |  | |||
|  | @ -1,37 +1,44 @@ | |||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| import datetime | ||||
| 
 | ||||
| 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 | ||||
| 
 | ||||
| from django.contrib.auth.models import Permission, User | ||||
| from django.utils.encoding import python_2_unicode_compatible | ||||
| 
 | ||||
| 
 | ||||
| TEAM_ACCESS_CHOICES = [ | ||||
|     ("open", "open"), | ||||
|     ("application", "by application"), | ||||
|     ("invitation", "by invitation") | ||||
|     ("open", _("open")), | ||||
|     ("application", _("by application")), | ||||
|     ("invitation", _("by invitation")) | ||||
| ] | ||||
| 
 | ||||
| 
 | ||||
| @python_2_unicode_compatible | ||||
| class Team(models.Model): | ||||
| 
 | ||||
|     slug = models.SlugField(unique=True) | ||||
|     name = models.CharField(max_length=100) | ||||
|     description = models.TextField(blank=True) | ||||
|     access = models.CharField(max_length=20, choices=TEAM_ACCESS_CHOICES) | ||||
|     slug = models.SlugField(unique=True, verbose_name=_("Slug")) | ||||
|     name = models.CharField(max_length=100, verbose_name=_("Name")) | ||||
|     description = models.TextField(blank=True, verbose_name=_("Description")) | ||||
|     access = models.CharField(max_length=20, choices=TEAM_ACCESS_CHOICES, | ||||
|                               verbose_name=_("Access")) | ||||
| 
 | ||||
|     # 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 = 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 | ||||
|     def get_absolute_url(self): | ||||
|  | @ -58,23 +65,32 @@ class Team(models.Model): | |||
|     def managers(self): | ||||
|         return self.memberships.filter(state="manager") | ||||
| 
 | ||||
|     class Meta: | ||||
|         verbose_name = _('Team') | ||||
|         verbose_name_plural = _('Teams') | ||||
| 
 | ||||
| MEMBERSHIP_STATE_CHOICES = [ | ||||
|     ("applied", "applied"), | ||||
|     ("invited", "invited"), | ||||
|     ("declined", "declined"), | ||||
|     ("rejected", "rejected"), | ||||
|     ("member", "member"), | ||||
|     ("manager", "manager"), | ||||
|     ("applied", _("applied")), | ||||
|     ("invited", _("invited")), | ||||
|     ("declined", _("declined")), | ||||
|     ("rejected", _("rejected")), | ||||
|     ("member", _("member")), | ||||
|     ("manager", _("manager")), | ||||
| ] | ||||
| 
 | ||||
| 
 | ||||
| class Membership(models.Model): | ||||
| 
 | ||||
|     user = models.ForeignKey(User, related_name="memberships") | ||||
|     team = models.ForeignKey(Team, related_name="memberships") | ||||
|     state = models.CharField(max_length=20, choices=MEMBERSHIP_STATE_CHOICES) | ||||
|     message = models.TextField(blank=True) | ||||
|     user = models.ForeignKey(User, related_name="memberships", | ||||
|                              verbose_name=_("User")) | ||||
|     team = models.ForeignKey(Team, related_name="memberships", | ||||
|                              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) | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ from django.contrib.auth.decorators import login_required | |||
| from django.contrib import messages | ||||
| 
 | ||||
| from symposion.utils.mail import send_email | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| 
 | ||||
| from symposion.teams.forms import TeamInvitationForm | ||||
| from symposion.teams.models import Team, Membership | ||||
|  | @ -67,7 +68,7 @@ def team_detail(request, slug): | |||
|             if form.is_valid(): | ||||
|                 form.invite() | ||||
|                 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) | ||||
|         else: | ||||
|             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.state = "member" | ||||
|         membership.save() | ||||
|         messages.success(request, "Joined team.") | ||||
|         messages.success(request, _("Joined team.")) | ||||
|         return redirect("team_detail", slug=slug) | ||||
|     else: | ||||
|         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": | ||||
|         membership = Membership.objects.get(team=team, user=request.user) | ||||
|         membership.delete() | ||||
|         messages.success(request, "Left team.") | ||||
|         messages.success(request, _("Left team.")) | ||||
|         return redirect("dashboard") | ||||
|     else: | ||||
|         return redirect("team_detail", slug=slug) | ||||
|  | @ -133,7 +134,7 @@ def team_apply(request, slug): | |||
|             "team": team, | ||||
|             "user": request.user | ||||
|         }) | ||||
|         messages.success(request, "Applied to join team.") | ||||
|         messages.success(request, _("Applied to join team.")) | ||||
|         return redirect("team_detail", slug=slug) | ||||
|     else: | ||||
|         return redirect("team_detail", slug=slug) | ||||
|  | @ -149,7 +150,7 @@ def team_promote(request, pk): | |||
|         if membership.state == "member": | ||||
|             membership.state = "manager" | ||||
|             membership.save() | ||||
|             messages.success(request, "Promoted to manager.") | ||||
|             messages.success(request, _("Promoted to manager.")) | ||||
|     return redirect("team_detail", slug=membership.team.slug) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -163,7 +164,7 @@ def team_demote(request, pk): | |||
|         if membership.state == "manager": | ||||
|             membership.state = "member" | ||||
|             membership.save() | ||||
|             messages.success(request, "Demoted from manager.") | ||||
|             messages.success(request, _("Demoted from manager.")) | ||||
|     return redirect("team_detail", slug=membership.team.slug) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -177,7 +178,7 @@ def team_accept(request, pk): | |||
|         if membership.state == "applied": | ||||
|             membership.state = "member" | ||||
|             membership.save() | ||||
|             messages.success(request, "Accepted application.") | ||||
|             messages.success(request, _("Accepted application.")) | ||||
|     return redirect("team_detail", slug=membership.team.slug) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -191,5 +192,5 @@ def team_reject(request, pk): | |||
|         if membership.state == "applied": | ||||
|             membership.state = "rejected" | ||||
|             membership.save() | ||||
|             messages.success(request, "Rejected application.") | ||||
|             messages.success(request, _("Rejected application.")) | ||||
|     return redirect("team_detail", slug=membership.team.slug) | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Patrick Altman
						Patrick Altman