Merge branch 'miurahr-i18n-all'
This commit is contained in:
commit
d23363621b
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.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)
|
||||||
|
|
|
@ -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])
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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.")
|
||||||
)
|
)
|
||||||
|
|
|
@ -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():
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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":
|
||||||
|
|
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue