Massively upgrade symposion
* Remove markitup (to be replaced with Ace editor) * Use DUA decorators * Removed custom signup bits * Upgraded dependencies * Added migrations * Namespaced template locations * Removed html5parser/sanitizer (for now) - parsing functionality should be moved out entirely to a hooks * Replaced ProposalScoreExpression object with a function that returns F() expressions
This commit is contained in:
parent
8b4282a48e
commit
11f697d137
36 changed files with 821 additions and 222 deletions
|
@ -1,13 +1,12 @@
|
|||
Django>=1.7.1
|
||||
django-appconf==0.6
|
||||
django-markitup==2.2.2
|
||||
django-model-utils==2.2
|
||||
django-reversion==1.8.5
|
||||
django-sitetree==1.2.1
|
||||
django-taggit==0.12.2
|
||||
django-timezone-field==1.2
|
||||
django-user-accounts==1.0
|
||||
Django==1.8.5
|
||||
django-appconf==1.0.1
|
||||
django-model-utils==2.3.1
|
||||
django-reversion==1.9.3
|
||||
django-sitetree==1.4.0
|
||||
django-taggit==0.17.1
|
||||
django-timezone-field==1.3
|
||||
django-user-accounts==1.2.0
|
||||
easy-thumbnails==2.2
|
||||
html5lib==0.999
|
||||
markdown==2.5.2
|
||||
pytz==2014.10
|
||||
html5lib==0.9999999
|
||||
markdown==2.6.2
|
||||
pytz==2015.6
|
||||
|
|
44
symposion/conference/migrations/0001_initial.py
Normal file
44
symposion/conference/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import timezone_field.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Conference',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, auto_created=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=100, verbose_name='Title')),
|
||||
('start_date', models.DateField(null=True, blank=True, verbose_name='Start date')),
|
||||
('end_date', models.DateField(null=True, blank=True, verbose_name='End date')),
|
||||
('timezone', timezone_field.fields.TimeZoneField(blank=True, verbose_name='timezone')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'conferences',
|
||||
'verbose_name': 'conference',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Section',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, auto_created=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100, verbose_name='Name')),
|
||||
('slug', models.SlugField(verbose_name='Slug')),
|
||||
('start_date', models.DateField(null=True, blank=True, verbose_name='Start date')),
|
||||
('end_date', models.DateField(null=True, blank=True, verbose_name='End date')),
|
||||
('conference', models.ForeignKey(to='symposion_conference.Conference', verbose_name='Conference')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['start_date'],
|
||||
'verbose_name_plural': 'sections',
|
||||
'verbose_name': 'section',
|
||||
},
|
||||
),
|
||||
]
|
0
symposion/conference/migrations/__init__.py
Normal file
0
symposion/conference/migrations/__init__.py
Normal file
|
@ -1,9 +1,10 @@
|
|||
from django.http import Http404
|
||||
from django.shortcuts import render
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from account.decorators import login_required
|
||||
|
||||
|
||||
@login_required
|
||||
def user_list(request):
|
||||
|
@ -11,6 +12,6 @@ def user_list(request):
|
|||
if not request.user.is_staff:
|
||||
raise Http404()
|
||||
|
||||
return render(request, "conference/user_list.html", {
|
||||
return render(request, "symposion/conference/user_list.html", {
|
||||
"users": User.objects.all(),
|
||||
})
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
try:
|
||||
from collections import OrderedDict
|
||||
except ImportError:
|
||||
OrderedDict = None
|
||||
|
||||
from django import forms
|
||||
|
||||
import account.forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class SignupForm(account.forms.SignupForm):
|
||||
|
||||
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)
|
||||
key_order = [
|
||||
"email",
|
||||
"email_confirm",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"password",
|
||||
"password_confirm"
|
||||
]
|
||||
self.fields = reorder_fields(self.fields, key_order)
|
||||
|
||||
def clean_email_confirm(self):
|
||||
email = self.cleaned_data.get("email")
|
||||
email_confirm = self.cleaned_data["email_confirm"]
|
||||
if email:
|
||||
if email != email_confirm:
|
||||
raise forms.ValidationError(
|
||||
_("Email address must match previously typed email address"))
|
||||
return email_confirm
|
||||
|
||||
|
||||
def reorder_fields(fields, order):
|
||||
"""Reorder form fields by order, removing items not in order.
|
||||
|
||||
>>> reorder_fields(
|
||||
... OrderedDict([('a', 1), ('b', 2), ('c', 3)]),
|
||||
... ['b', 'c', 'a'])
|
||||
OrderedDict([('b', 2), ('c', 3), ('a', 1)])
|
||||
"""
|
||||
for key, v in fields.items():
|
||||
if key not in order:
|
||||
del fields[key]
|
||||
|
||||
if not OrderedDict or hasattr(fields, "keyOrder"):
|
||||
# fields is SortedDict
|
||||
fields.keyOrder.sort(key=lambda k: order.index(k[0]))
|
||||
return fields
|
||||
else:
|
||||
# fields is OrderedDict
|
||||
return OrderedDict(sorted(fields.items(), key=lambda k: order.index(k[0])))
|
|
@ -10,8 +10,9 @@ def parse(text):
|
|||
text = markdown.markdown(text, extensions=["extra"], safe_mode=False)
|
||||
|
||||
# Sanitize using html5lib
|
||||
bits = []
|
||||
parser = html5parser.HTMLParser(tokenizer=sanitizer.HTMLSanitizer)
|
||||
for token in parser.parseFragment(text).childNodes:
|
||||
bits.append(token.toxml())
|
||||
return "".join(bits)
|
||||
# bits = []
|
||||
# parser = html5parser.HTMLParser(tokenizer=sanitizer.HTMLSanitizer)
|
||||
# for token in parser.parseFragment(text).childNodes:
|
||||
# bits.append(token.toxml())
|
||||
# return "".join(bits)
|
||||
return text
|
||||
|
|
|
@ -4,7 +4,6 @@ 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
|
||||
|
||||
|
||||
# @@@ generic proposal form
|
||||
|
|
100
symposion/proposals/migrations/0001_initial.py
Normal file
100
symposion/proposals/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,100 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.conf import settings
|
||||
import django.utils.timezone
|
||||
import symposion.proposals.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('symposion_speakers', '__first__'),
|
||||
('symposion_conference', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AdditionalSpeaker',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
|
||||
('status', models.IntegerField(verbose_name='Status', default=1, choices=[(1, 'Pending'), (2, 'Accepted'), (3, 'Declined')])),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Addtional speaker',
|
||||
'verbose_name_plural': 'Additional speakers',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ProposalBase',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
|
||||
('title', models.CharField(verbose_name='Title', max_length=100)),
|
||||
('description', models.TextField(verbose_name='Brief Description', max_length=400, help_text='If your proposal is accepted this will be made public and printed in the program. Should be one paragraph, maximum 400 characters.')),
|
||||
('abstract', models.TextField(verbose_name='Detailed Abstract', help_text="Detailed outline. Will be made public if your proposal is accepted. Edit using <a href='http://daringfireball.net/projects/markdown/basics' target='_blank'>Markdown</a>.")),
|
||||
('abstract_html', models.TextField(blank=True)),
|
||||
('additional_notes', models.TextField(blank=True, verbose_name='Addtional Notes', help_text="Anything else you'd like the program committee to know when making their selection: your past experience, etc. This is not made public. Edit using <a href='http://daringfireball.net/projects/markdown/basics' target='_blank'>Markdown</a>.")),
|
||||
('additional_notes_html', models.TextField(blank=True)),
|
||||
('submitted', models.DateTimeField(editable=False, default=django.utils.timezone.now, verbose_name='Submitted')),
|
||||
('cancelled', models.BooleanField(verbose_name='Cancelled', default=False)),
|
||||
('additional_speakers', models.ManyToManyField(blank=True, verbose_name='Addtional speakers', through='symposion_proposals.AdditionalSpeaker', to='symposion_speakers.Speaker')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ProposalKind',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
|
||||
('name', models.CharField(verbose_name='Name', max_length=100)),
|
||||
('slug', models.SlugField(verbose_name='Slug')),
|
||||
('section', models.ForeignKey(to='symposion_conference.Section', verbose_name='Section', related_name='proposal_kinds')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ProposalSection',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
|
||||
('start', models.DateTimeField(blank=True, verbose_name='Start', null=True)),
|
||||
('end', models.DateTimeField(blank=True, verbose_name='End', null=True)),
|
||||
('closed', models.NullBooleanField(verbose_name='Closed')),
|
||||
('published', models.NullBooleanField(verbose_name='Published')),
|
||||
('section', models.OneToOneField(to='symposion_conference.Section', verbose_name='Section')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SupportingDocument',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
|
||||
('created_at', models.DateTimeField(verbose_name='Created at', default=django.utils.timezone.now)),
|
||||
('file', models.FileField(verbose_name='File', upload_to=symposion.proposals.models.uuid_filename)),
|
||||
('description', models.CharField(verbose_name='Description', max_length=140)),
|
||||
('proposal', models.ForeignKey(to='symposion_proposals.ProposalBase', verbose_name='Proposal', related_name='supporting_documents')),
|
||||
('uploaded_by', models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name='Uploaded by')),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='proposalbase',
|
||||
name='kind',
|
||||
field=models.ForeignKey(to='symposion_proposals.ProposalKind', verbose_name='Kind'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='proposalbase',
|
||||
name='speaker',
|
||||
field=models.ForeignKey(to='symposion_speakers.Speaker', verbose_name='Speaker', related_name='proposals'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='additionalspeaker',
|
||||
name='proposalbase',
|
||||
field=models.ForeignKey(to='symposion_proposals.ProposalBase', verbose_name='Proposalbase'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='additionalspeaker',
|
||||
name='speaker',
|
||||
field=models.ForeignKey(to='symposion_speakers.Speaker', verbose_name='Speaker'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='additionalspeaker',
|
||||
unique_together=set([('speaker', 'proposalbase')]),
|
||||
),
|
||||
]
|
0
symposion/proposals/migrations/__init__.py
Normal file
0
symposion/proposals/migrations/__init__.py
Normal file
|
@ -15,10 +15,9 @@ from django.core.exceptions import ValidationError
|
|||
|
||||
import reversion
|
||||
|
||||
from markitup.fields import MarkupField
|
||||
|
||||
from model_utils.managers import InheritanceManager
|
||||
|
||||
from symposion.markdown_parser import parse
|
||||
from symposion.conference.models import Section
|
||||
from symposion.speakers.models import Speaker
|
||||
|
||||
|
@ -94,13 +93,14 @@ class ProposalBase(models.Model):
|
|||
help_text=_("If your proposal is accepted this will be made public and printed in the "
|
||||
"program. Should be one paragraph, maximum 400 characters.")
|
||||
)
|
||||
abstract = MarkupField(
|
||||
abstract = models.TextField(
|
||||
_("Detailed Abstract"),
|
||||
help_text=_("Detailed outline. Will be made public if your proposal is accepted. Edit "
|
||||
"using <a href='http://daringfireball.net/projects/markdown/basics' "
|
||||
"target='_blank'>Markdown</a>.")
|
||||
)
|
||||
additional_notes = MarkupField(
|
||||
abstract_html = models.TextField(blank=True)
|
||||
additional_notes = models.TextField(
|
||||
_("Addtional Notes"),
|
||||
blank=True,
|
||||
help_text=_("Anything else you'd like the program committee to know when making their "
|
||||
|
@ -108,6 +108,7 @@ class ProposalBase(models.Model):
|
|||
"<a href='http://daringfireball.net/projects/markdown/basics' "
|
||||
"target='_blank'>Markdown</a>.")
|
||||
)
|
||||
additional_notes_html = models.TextField(blank=True)
|
||||
submitted = models.DateTimeField(
|
||||
default=now,
|
||||
editable=False,
|
||||
|
@ -115,6 +116,9 @@ class ProposalBase(models.Model):
|
|||
)
|
||||
speaker = models.ForeignKey(Speaker, related_name="proposals", verbose_name=_("Speaker"))
|
||||
|
||||
# @@@ this validation used to exist as a validators keyword on additional_speakers
|
||||
# M2M field but that is no longer supported by Django. Should be moved to
|
||||
# the form level
|
||||
def additional_speaker_validator(self, a_speaker):
|
||||
if a_speaker.speaker.email == self.speaker.email:
|
||||
raise ValidationError(_("%s is same as primary speaker.") % a_speaker.speaker.email)
|
||||
|
@ -122,10 +126,14 @@ 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, verbose_name=_("Addtional speakers"),
|
||||
validators=[additional_speaker_validator])
|
||||
blank=True, verbose_name=_("Addtional speakers"))
|
||||
cancelled = models.BooleanField(default=False, verbose_name=_("Cancelled"))
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.abstract_html = parse(self.abstract)
|
||||
self.additional_notes_html = parse(self.additional_notes)
|
||||
return super(ProposalBase, self).save(*args, **kwargs)
|
||||
|
||||
def can_edit(self):
|
||||
return True
|
||||
|
||||
|
|
|
@ -13,11 +13,12 @@ from django.views import static
|
|||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from account.decorators import login_required
|
||||
from account.models import EmailAddress
|
||||
|
||||
from symposion.proposals.models import (
|
||||
ProposalBase, ProposalSection, ProposalKind
|
||||
)
|
||||
|
@ -58,7 +59,7 @@ def proposal_submit(request):
|
|||
for kind in proposal_section.section.proposal_kinds.all():
|
||||
kinds.append(kind)
|
||||
|
||||
return render(request, "proposals/proposal_submit.html", {
|
||||
return render(request, "symposion/proposals/proposal_submit.html", {
|
||||
"kinds": kinds,
|
||||
})
|
||||
|
||||
|
@ -95,9 +96,9 @@ def proposal_submit_kind(request, kind_slug):
|
|||
else:
|
||||
form = form_class()
|
||||
|
||||
return render(request, "proposals/proposal_submit_kind.html", {
|
||||
return render(request, "symposion/proposals/proposal_submit_kind.html", {
|
||||
"kind": kind,
|
||||
"form": form,
|
||||
"proposal_form": form,
|
||||
})
|
||||
|
||||
|
||||
|
@ -178,7 +179,7 @@ def proposal_speaker_manage(request, pk):
|
|||
"speakers": proposal.speakers(),
|
||||
"add_speaker_form": add_speaker_form,
|
||||
}
|
||||
return render(request, "proposals/proposal_speaker_manage.html", ctx)
|
||||
return render(request, "symposion/proposals/proposal_speaker_manage.html", ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
|
@ -195,7 +196,7 @@ def proposal_edit(request, pk):
|
|||
"title": "Proposal editing closed",
|
||||
"body": "Proposal editing is closed for this session type."
|
||||
}
|
||||
return render(request, "proposals/proposal_error.html", ctx)
|
||||
return render(request, "symposion/proposals/proposal_error.html", ctx)
|
||||
|
||||
form_class = get_form(settings.PROPOSAL_FORMS[proposal.kind.slug])
|
||||
|
||||
|
@ -223,7 +224,7 @@ def proposal_edit(request, pk):
|
|||
else:
|
||||
form = form_class(instance=proposal)
|
||||
|
||||
return render(request, "proposals/proposal_edit.html", {
|
||||
return render(request, "symposion/proposals/proposal_edit.html", {
|
||||
"proposal": proposal,
|
||||
"form": form,
|
||||
})
|
||||
|
@ -276,7 +277,7 @@ def proposal_detail(request, pk):
|
|||
else:
|
||||
message_form = None
|
||||
|
||||
return render(request, "proposals/proposal_detail.html", {
|
||||
return render(request, "symposion/proposals/proposal_detail.html", {
|
||||
"proposal": proposal,
|
||||
"message_form": message_form
|
||||
})
|
||||
|
@ -298,7 +299,7 @@ def proposal_cancel(request, pk):
|
|||
messages.success(request, "%s has been cancelled" % proposal.title)
|
||||
return redirect("dashboard")
|
||||
|
||||
return render(request, "proposals/proposal_cancel.html", {
|
||||
return render(request, "symposion/proposals/proposal_cancel.html", {
|
||||
"proposal": proposal,
|
||||
})
|
||||
|
||||
|
@ -321,7 +322,7 @@ def proposal_leave(request, pk):
|
|||
ctx = {
|
||||
"proposal": proposal,
|
||||
}
|
||||
return render(request, "proposals/proposal_leave.html", ctx)
|
||||
return render(request, "symposion/proposals/proposal_leave.html", ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
|
@ -372,7 +373,7 @@ def document_create(request, proposal_pk):
|
|||
else:
|
||||
form = SupportingDocumentCreateForm()
|
||||
|
||||
return render(request, "proposals/document_create.html", {
|
||||
return render(request, "symposion/proposals/document_create.html", {
|
||||
"proposal": proposal,
|
||||
"form": form,
|
||||
})
|
||||
|
|
|
@ -2,8 +2,6 @@ from __future__ import unicode_literals
|
|||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from markitup.widgets import MarkItUpWidget
|
||||
|
||||
from symposion.reviews.models import Review, Comment, ProposalMessage, VOTES
|
||||
|
||||
|
||||
|
@ -11,7 +9,6 @@ class ReviewForm(forms.ModelForm):
|
|||
class Meta:
|
||||
model = Review
|
||||
fields = ["vote", "comment"]
|
||||
widgets = {"comment": MarkItUpWidget()}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ReviewForm, self).__init__(*args, **kwargs)
|
||||
|
@ -25,14 +22,12 @@ class ReviewCommentForm(forms.ModelForm):
|
|||
class Meta:
|
||||
model = Comment
|
||||
fields = ["text"]
|
||||
widgets = {"text": MarkItUpWidget()}
|
||||
|
||||
|
||||
class SpeakerCommentForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = ProposalMessage
|
||||
fields = ["message"]
|
||||
widgets = {"message": MarkItUpWidget()}
|
||||
|
||||
|
||||
class BulkPresentationForm(forms.Form):
|
||||
|
|
143
symposion/reviews/migrations/0001_initial.py
Normal file
143
symposion/reviews/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,143 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from decimal import Decimal
|
||||
import datetime
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('symposion_proposals', '0001_initial'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Comment',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
|
||||
('text', models.TextField(verbose_name='Text')),
|
||||
('text_html', models.TextField(blank=True)),
|
||||
('public', models.BooleanField(verbose_name='Public', default=False, choices=[(True, 'public'), (False, 'private')])),
|
||||
('commented_at', models.DateTimeField(verbose_name='Commented at', default=datetime.datetime.now)),
|
||||
('commenter', models.ForeignKey(verbose_name='Commenter', to=settings.AUTH_USER_MODEL)),
|
||||
('proposal', models.ForeignKey(to='symposion_proposals.ProposalBase', verbose_name='Proposal', related_name='comments')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'comments',
|
||||
'verbose_name': 'comment',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='LatestVote',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
|
||||
('vote', models.CharField(choices=[('+1', '+1 \u2014 Good proposal and I will argue for it to be accepted.'), ('+0', '+0 \u2014 OK proposal, but I will not argue for it to be accepted.'), ('\u22120', '\u22120 \u2014 Weak proposal, but I will not argue strongly against acceptance.'), ('\u22121', '\u22121 \u2014 Serious issues and I will argue to reject this proposal.')], verbose_name='Vote', max_length=2)),
|
||||
('submitted_at', models.DateTimeField(editable=False, verbose_name='Submitted at', default=datetime.datetime.now)),
|
||||
('proposal', models.ForeignKey(to='symposion_proposals.ProposalBase', verbose_name='Proposal', related_name='votes')),
|
||||
('user', models.ForeignKey(verbose_name='User', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'latest votes',
|
||||
'verbose_name': 'latest vote',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='NotificationTemplate',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
|
||||
('label', models.CharField(verbose_name='Label', max_length=100)),
|
||||
('from_address', models.EmailField(verbose_name='From address', max_length=254)),
|
||||
('subject', models.CharField(verbose_name='Subject', max_length=100)),
|
||||
('body', models.TextField(verbose_name='Body')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'notification templates',
|
||||
'verbose_name': 'notification template',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ProposalMessage',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
|
||||
('message', models.TextField(verbose_name='Message')),
|
||||
('message_html', models.TextField(blank=True)),
|
||||
('submitted_at', models.DateTimeField(editable=False, verbose_name='Submitted at', default=datetime.datetime.now)),
|
||||
('proposal', models.ForeignKey(to='symposion_proposals.ProposalBase', verbose_name='Proposal', related_name='messages')),
|
||||
('user', models.ForeignKey(verbose_name='User', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'proposal messages',
|
||||
'verbose_name': 'proposal message',
|
||||
'ordering': ['submitted_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ProposalResult',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
|
||||
('score', models.DecimalField(decimal_places=2, verbose_name='Score', max_digits=5, default=Decimal('0.00'))),
|
||||
('comment_count', models.PositiveIntegerField(verbose_name='Comment count', default=0)),
|
||||
('vote_count', models.PositiveIntegerField(verbose_name='Vote count', default=0)),
|
||||
('plus_one', models.PositiveIntegerField(verbose_name='Plus one', default=0)),
|
||||
('plus_zero', models.PositiveIntegerField(verbose_name='Plus zero', default=0)),
|
||||
('minus_zero', models.PositiveIntegerField(verbose_name='Minus zero', default=0)),
|
||||
('minus_one', models.PositiveIntegerField(verbose_name='Minus one', default=0)),
|
||||
('accepted', models.NullBooleanField(verbose_name='Accepted', default=None, choices=[(True, 'accepted'), (False, 'rejected'), (None, 'undecided')])),
|
||||
('status', models.CharField(choices=[('accepted', 'accepted'), ('rejected', 'rejected'), ('undecided', 'undecided'), ('standby', 'standby')], verbose_name='Status', max_length=20, default='undecided')),
|
||||
('proposal', models.OneToOneField(to='symposion_proposals.ProposalBase', verbose_name='Proposal', related_name='result')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'proposal_results',
|
||||
'verbose_name': 'proposal_result',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ResultNotification',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
|
||||
('timestamp', models.DateTimeField(verbose_name='Timestamp', default=datetime.datetime.now)),
|
||||
('to_address', models.EmailField(verbose_name='To address', max_length=254)),
|
||||
('from_address', models.EmailField(verbose_name='From address', max_length=254)),
|
||||
('subject', models.CharField(verbose_name='Subject', max_length=100)),
|
||||
('body', models.TextField(verbose_name='Body')),
|
||||
('proposal', models.ForeignKey(to='symposion_proposals.ProposalBase', verbose_name='Proposal', related_name='notifications')),
|
||||
('template', models.ForeignKey(to='symposion_reviews.NotificationTemplate', blank=True, verbose_name='Template', null=True, on_delete=django.db.models.deletion.SET_NULL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Review',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
|
||||
('vote', models.CharField(blank=True, verbose_name='Vote', max_length=2, choices=[('+1', '+1 \u2014 Good proposal and I will argue for it to be accepted.'), ('+0', '+0 \u2014 OK proposal, but I will not argue for it to be accepted.'), ('\u22120', '\u22120 \u2014 Weak proposal, but I will not argue strongly against acceptance.'), ('\u22121', '\u22121 \u2014 Serious issues and I will argue to reject this proposal.')])),
|
||||
('comment', models.TextField(verbose_name='Comment')),
|
||||
('comment_html', models.TextField(blank=True)),
|
||||
('submitted_at', models.DateTimeField(editable=False, verbose_name='Submitted at', default=datetime.datetime.now)),
|
||||
('proposal', models.ForeignKey(to='symposion_proposals.ProposalBase', verbose_name='Proposal', related_name='reviews')),
|
||||
('user', models.ForeignKey(verbose_name='User', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'reviews',
|
||||
'verbose_name': 'review',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ReviewAssignment',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True, serialize=False)),
|
||||
('origin', models.IntegerField(choices=[(0, 'auto-assigned, initial'), (1, 'opted-in'), (2, 'auto-assigned, later')], verbose_name='Origin')),
|
||||
('assigned_at', models.DateTimeField(verbose_name='Assigned at', default=datetime.datetime.now)),
|
||||
('opted_out', models.BooleanField(verbose_name='Opted out', default=False)),
|
||||
('proposal', models.ForeignKey(verbose_name='Proposal', to='symposion_proposals.ProposalBase')),
|
||||
('user', models.ForeignKey(verbose_name='User', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='latestvote',
|
||||
unique_together=set([('proposal', 'user')]),
|
||||
),
|
||||
]
|
0
symposion/reviews/migrations/__init__.py
Normal file
0
symposion/reviews/migrations/__init__.py
Normal file
|
@ -4,26 +4,22 @@ from datetime import datetime
|
|||
from decimal import Decimal
|
||||
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
from django.db.models import Q, F
|
||||
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
|
||||
|
||||
from symposion.markdown_parser import parse
|
||||
from symposion.proposals.models import ProposalBase
|
||||
from symposion.schedule.models import Presentation
|
||||
|
||||
|
||||
class ProposalScoreExpression(object):
|
||||
|
||||
def as_sql(self, qn, connection=None):
|
||||
sql = "((3 * plus_one + plus_zero) - (minus_zero + 3 * minus_one))"
|
||||
return sql, []
|
||||
|
||||
def prepare_database_save(self, unused):
|
||||
return self
|
||||
def score_expression():
|
||||
return (
|
||||
(3 * F("plus_one") + F("plus_zero")) -
|
||||
(F("minus_zero") + 3 * F("minus_one"))
|
||||
)
|
||||
|
||||
|
||||
class Votes(object):
|
||||
|
@ -97,9 +93,14 @@ class ProposalMessage(models.Model):
|
|||
proposal = models.ForeignKey(ProposalBase, related_name="messages", verbose_name=_("Proposal"))
|
||||
user = models.ForeignKey(User, verbose_name=_("User"))
|
||||
|
||||
message = MarkupField(verbose_name=_("Message"))
|
||||
message = models.TextField(verbose_name=_("Message"))
|
||||
message_html = models.TextField(blank=True)
|
||||
submitted_at = models.DateTimeField(default=datetime.now, editable=False, verbose_name=_("Submitted at"))
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.message_html = parse(self.message)
|
||||
return super(ProposalMessage, self).save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
ordering = ["submitted_at"]
|
||||
verbose_name = _("proposal message")
|
||||
|
@ -115,10 +116,12 @@ class Review(models.Model):
|
|||
# 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, verbose_name=_("Vote"))
|
||||
comment = MarkupField(verbose_name=_("Comment"))
|
||||
comment = models.TextField(verbose_name=_("Comment"))
|
||||
comment_html = models.TextField(blank=True)
|
||||
submitted_at = models.DateTimeField(default=datetime.now, editable=False, verbose_name=_("Submitted at"))
|
||||
|
||||
def save(self, **kwargs):
|
||||
self.comment_html = parse(self.comment)
|
||||
if self.vote:
|
||||
vote, created = LatestVote.objects.get_or_create(
|
||||
proposal=self.proposal,
|
||||
|
@ -258,7 +261,7 @@ class ProposalResult(models.Model):
|
|||
vote=VOTES.MINUS_ONE
|
||||
).count()
|
||||
result.save()
|
||||
cls._default_manager.filter(pk=result.pk).update(score=ProposalScoreExpression())
|
||||
cls._default_manager.filter(pk=result.pk).update(score=score_expression())
|
||||
|
||||
def update_vote(self, vote, previous=None, removal=False):
|
||||
mapping = {
|
||||
|
@ -287,7 +290,7 @@ class ProposalResult(models.Model):
|
|||
self.comment_count = models.F("comment_count") + 1
|
||||
self.save()
|
||||
model = self.__class__
|
||||
model._default_manager.filter(pk=self.pk).update(score=ProposalScoreExpression())
|
||||
model._default_manager.filter(pk=self.pk).update(score=score_expression())
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("proposal_result")
|
||||
|
@ -297,7 +300,8 @@ class ProposalResult(models.Model):
|
|||
class Comment(models.Model):
|
||||
proposal = models.ForeignKey(ProposalBase, related_name="comments", verbose_name=_("Proposal"))
|
||||
commenter = models.ForeignKey(User, verbose_name=_("Commenter"))
|
||||
text = MarkupField(verbose_name=_("Text"))
|
||||
text = models.TextField(verbose_name=_("Text"))
|
||||
text_html = models.TextField(blank=True)
|
||||
|
||||
# Or perhaps more accurately, can the user see this comment.
|
||||
public = models.BooleanField(choices=[(True, _("public")), (False, _("private"))], default=False, verbose_name=_("Public"))
|
||||
|
@ -307,6 +311,10 @@ class Comment(models.Model):
|
|||
verbose_name = _("comment")
|
||||
verbose_name_plural = _("comments")
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.comment_html = parse(self.comment)
|
||||
return super(Comment, self).save(*args, **kwargs)
|
||||
|
||||
|
||||
class NotificationTemplate(models.Model):
|
||||
|
||||
|
|
|
@ -5,11 +5,13 @@ from django.shortcuts import render, redirect, get_object_or_404
|
|||
from django.template import Context, Template
|
||||
from django.views.decorators.http import require_POST
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from account.decorators import login_required
|
||||
|
||||
# @@@ switch to pinax-teams
|
||||
from symposion.teams.models import Team
|
||||
|
||||
from symposion.conf import settings
|
||||
from symposion.proposals.models import ProposalBase, ProposalSection
|
||||
from symposion.teams.models import Team
|
||||
from symposion.utils.mail import send_email
|
||||
|
||||
from symposion.reviews.forms import ReviewForm, SpeakerCommentForm
|
||||
|
@ -21,7 +23,7 @@ from symposion.reviews.models import (
|
|||
|
||||
|
||||
def access_not_permitted(request):
|
||||
return render(request, "reviews/access_not_permitted.html")
|
||||
return render(request, "symposion/reviews/access_not_permitted.html")
|
||||
|
||||
|
||||
def proposals_generator(request, queryset, user_pk=None, check_speaker=True):
|
||||
|
@ -96,7 +98,7 @@ def review_section(request, section_slug, assigned=False, reviewed="all"):
|
|||
"reviewed": reviewed,
|
||||
}
|
||||
|
||||
return render(request, "reviews/review_list.html", ctx)
|
||||
return render(request, "symposion/reviews/review_list.html", ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
|
@ -120,7 +122,7 @@ def review_list(request, section_slug, user_pk):
|
|||
ctx = {
|
||||
"proposals": proposals,
|
||||
}
|
||||
return render(request, "reviews/review_list.html", ctx)
|
||||
return render(request, "symposion/reviews/review_list.html", ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
|
@ -164,7 +166,7 @@ def review_admin(request, section_slug):
|
|||
"section_slug": section_slug,
|
||||
"reviewers": reviewers(),
|
||||
}
|
||||
return render(request, "reviews/review_admin.html", ctx)
|
||||
return render(request, "symposion/reviews/review_admin.html", ctx)
|
||||
|
||||
|
||||
# FIXME: This view is too complex according to flake8
|
||||
|
@ -273,7 +275,7 @@ def review_detail(request, pk):
|
|||
reviews = Review.objects.filter(proposal=proposal).order_by("-submitted_at")
|
||||
messages = proposal.messages.order_by("submitted_at")
|
||||
|
||||
return render(request, "reviews/review_detail.html", {
|
||||
return render(request, "symposion/reviews/review_detail.html", {
|
||||
"proposal": proposal,
|
||||
"latest_vote": latest_vote,
|
||||
"reviews": reviews,
|
||||
|
@ -353,7 +355,7 @@ def review_status(request, section_slug=None, key=None):
|
|||
else:
|
||||
ctx["proposals"] = proposals
|
||||
|
||||
return render(request, "reviews/review_stats.html", ctx)
|
||||
return render(request, "symposion/reviews/review_stats.html", ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
|
@ -364,7 +366,7 @@ def review_assignments(request):
|
|||
user=request.user,
|
||||
opted_out=False
|
||||
)
|
||||
return render(request, "reviews/review_assignment.html", {
|
||||
return render(request, "symposion/reviews/review_assignment.html", {
|
||||
"assignments": assignments,
|
||||
})
|
||||
|
||||
|
@ -398,7 +400,7 @@ def review_bulk_accept(request, section_slug):
|
|||
else:
|
||||
form = BulkPresentationForm()
|
||||
|
||||
return render(request, "reviews/review_bulk_accept.html", {
|
||||
return render(request, "symposion/reviews/review_bulk_accept.html", {
|
||||
"form": form,
|
||||
})
|
||||
|
||||
|
@ -417,7 +419,7 @@ def result_notification(request, section_slug, status):
|
|||
"proposals": proposals,
|
||||
"notification_templates": notification_templates,
|
||||
}
|
||||
return render(request, "reviews/result_notification.html", ctx)
|
||||
return render(request, "symposion/reviews/result_notification.html", ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
|
@ -455,7 +457,7 @@ def result_notification_prepare(request, section_slug, status):
|
|||
"proposals": proposals,
|
||||
"proposal_pks": ",".join([str(pk) for pk in proposal_pks]),
|
||||
}
|
||||
return render(request, "reviews/result_notification_prepare.html", ctx)
|
||||
return render(request, "symposion/reviews/result_notification_prepare.html", ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
|
|
|
@ -9,8 +9,6 @@ from django.contrib import messages
|
|||
from django.db import IntegrityError, transaction
|
||||
from django.db.models import Q
|
||||
|
||||
from markitup.widgets import MarkItUpWidget
|
||||
|
||||
from symposion.schedule.models import (Day, Presentation, Room, SlotKind, Slot,
|
||||
SlotRoom)
|
||||
|
||||
|
@ -44,7 +42,6 @@ class SlotEditForm(forms.Form):
|
|||
def build_content_override_field(self):
|
||||
kwargs = {
|
||||
"label": "Content",
|
||||
"widget": MarkItUpWidget(),
|
||||
"required": False,
|
||||
"initial": self.slot.content_override,
|
||||
}
|
||||
|
|
186
symposion/schedule/migrations/0001_initial.py
Normal file
186
symposion/schedule/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,186 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import datetime
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('symposion_speakers', '__first__'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('symposion_conference', '0001_initial'),
|
||||
('symposion_proposals', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Day',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('date', models.DateField(verbose_name='Date')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['date'],
|
||||
'verbose_name': 'date',
|
||||
'verbose_name_plural': 'dates',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Presentation',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('title', models.CharField(max_length=100, verbose_name='Title')),
|
||||
('description', models.TextField(verbose_name='Description')),
|
||||
('description_html', models.TextField(blank=True)),
|
||||
('abstract', models.TextField(verbose_name='Abstract')),
|
||||
('abstract_html', models.TextField(blank=True)),
|
||||
('cancelled', models.BooleanField(default=False, verbose_name='Cancelled')),
|
||||
('additional_speakers', models.ManyToManyField(related_name='copresentations', to='symposion_speakers.Speaker', verbose_name='Additional speakers', blank=True)),
|
||||
('proposal_base', models.OneToOneField(to='symposion_proposals.ProposalBase', related_name='presentation', verbose_name='Proposal base')),
|
||||
('section', models.ForeignKey(to='symposion_conference.Section', related_name='presentations', verbose_name='Section')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['slot'],
|
||||
'verbose_name': 'presentation',
|
||||
'verbose_name_plural': 'presentations',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Room',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('name', models.CharField(max_length=65, verbose_name='Name')),
|
||||
('order', models.PositiveIntegerField(verbose_name='Order')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Room',
|
||||
'verbose_name_plural': 'Rooms',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Schedule',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('published', models.BooleanField(default=True, verbose_name='Published')),
|
||||
('hidden', models.BooleanField(default=False, verbose_name='Hide schedule from overall conference view')),
|
||||
('section', models.OneToOneField(to='symposion_conference.Section', verbose_name='Section')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['section'],
|
||||
'verbose_name': 'Schedule',
|
||||
'verbose_name_plural': 'Schedules',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Session',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('day', models.ForeignKey(to='symposion_schedule.Day', related_name='sessions', verbose_name='Day')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Session',
|
||||
'verbose_name_plural': 'Sessions',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SessionRole',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('role', models.IntegerField(verbose_name='Role', choices=[(1, 'Session Chair'), (2, 'Session Runner')])),
|
||||
('status', models.NullBooleanField(verbose_name='Status')),
|
||||
('submitted', models.DateTimeField(default=datetime.datetime.now)),
|
||||
('session', models.ForeignKey(to='symposion_schedule.Session', verbose_name='Session')),
|
||||
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, verbose_name='User')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Session role',
|
||||
'verbose_name_plural': 'Session roles',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Slot',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('start', models.TimeField(verbose_name='Start')),
|
||||
('end', models.TimeField(verbose_name='End')),
|
||||
('content_override', models.TextField(verbose_name='Content override', blank=True)),
|
||||
('content_override_html', models.TextField(blank=True)),
|
||||
('day', models.ForeignKey(to='symposion_schedule.Day', verbose_name='Day')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['day', 'start', 'end'],
|
||||
'verbose_name': 'slot',
|
||||
'verbose_name_plural': 'slots',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SlotKind',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('label', models.CharField(max_length=50, verbose_name='Label')),
|
||||
('schedule', models.ForeignKey(to='symposion_schedule.Schedule', verbose_name='schedule')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Slot kind',
|
||||
'verbose_name_plural': 'Slot kinds',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SlotRoom',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('room', models.ForeignKey(to='symposion_schedule.Room', verbose_name='Room')),
|
||||
('slot', models.ForeignKey(to='symposion_schedule.Slot', verbose_name='Slot')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['slot', 'room__order'],
|
||||
'verbose_name': 'Slot room',
|
||||
'verbose_name_plural': 'Slot rooms',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='slot',
|
||||
name='kind',
|
||||
field=models.ForeignKey(to='symposion_schedule.SlotKind', verbose_name='Kind'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='session',
|
||||
name='slots',
|
||||
field=models.ManyToManyField(related_name='sessions', verbose_name='Slots', to='symposion_schedule.Slot'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='room',
|
||||
name='schedule',
|
||||
field=models.ForeignKey(to='symposion_schedule.Schedule', verbose_name='Schedule'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='presentation',
|
||||
name='slot',
|
||||
field=models.OneToOneField(to='symposion_schedule.Slot', related_name='content_ptr', blank=True, null=True, verbose_name='Slot'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='presentation',
|
||||
name='speaker',
|
||||
field=models.ForeignKey(to='symposion_speakers.Speaker', related_name='presentations', verbose_name='Speaker'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='day',
|
||||
name='schedule',
|
||||
field=models.ForeignKey(to='symposion_schedule.Schedule', verbose_name='Schedule'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='slotroom',
|
||||
unique_together=set([('slot', 'room')]),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='sessionrole',
|
||||
unique_together=set([('session', 'user', 'role')]),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='day',
|
||||
unique_together=set([('schedule', 'date')]),
|
||||
),
|
||||
]
|
0
symposion/schedule/migrations/__init__.py
Normal file
0
symposion/schedule/migrations/__init__.py
Normal file
|
@ -8,8 +8,7 @@ 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
|
||||
|
||||
from symposion.markdown_parser import parse
|
||||
from symposion.proposals.models import ProposalBase
|
||||
from symposion.conference.models import Section
|
||||
from symposion.speakers.models import Speaker
|
||||
|
@ -87,7 +86,12 @@ class Slot(models.Model):
|
|||
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"))
|
||||
content_override = models.TextField(blank=True, verbose_name=_("Content override"))
|
||||
content_override_html = models.TextField(blank=True)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.content_override_html = parse(self.content_override)
|
||||
return super(Slot, self).save(*args, **kwargs)
|
||||
|
||||
def assign(self, content):
|
||||
"""
|
||||
|
@ -179,8 +183,10 @@ class Presentation(models.Model):
|
|||
|
||||
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"))
|
||||
description = models.TextField(verbose_name=_("Description"))
|
||||
description_html = models.TextField(blank=True)
|
||||
abstract = models.TextField(verbose_name=_("Abstract"))
|
||||
abstract_html = models.TextField(blank=True)
|
||||
speaker = models.ForeignKey(Speaker, related_name="presentations", verbose_name=_("Speaker"))
|
||||
additional_speakers = models.ManyToManyField(Speaker, related_name="copresentations",
|
||||
blank=True, verbose_name=_("Additional speakers"))
|
||||
|
@ -188,6 +194,11 @@ class Presentation(models.Model):
|
|||
proposal_base = models.OneToOneField(ProposalBase, related_name="presentation", verbose_name=_("Proposal base"))
|
||||
section = models.ForeignKey(Section, related_name="presentations", verbose_name=_("Section"))
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.description_html = parse(self.description)
|
||||
self.abstract_html = parse(self.abstract)
|
||||
return super(Presentation, self).save(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def number(self):
|
||||
return self.proposal.number
|
||||
|
|
|
@ -22,7 +22,6 @@ try:
|
|||
"django.contrib.contenttypes",
|
||||
"django.contrib.sites",
|
||||
|
||||
"markitup",
|
||||
"reversion",
|
||||
|
||||
"symposion",
|
||||
|
@ -34,8 +33,6 @@ try:
|
|||
],
|
||||
SITE_ID=1,
|
||||
NOSE_ARGS=['-s'],
|
||||
|
||||
MARKITUP_FILTER=('django.contrib.markup.templatetags.markup.textile', {}),
|
||||
)
|
||||
|
||||
try:
|
||||
|
|
|
@ -6,11 +6,12 @@ from django.http import Http404, HttpResponse
|
|||
from django.shortcuts import render, get_object_or_404, redirect
|
||||
from django.template import loader, Context
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib import messages
|
||||
from django.contrib.sites.models import Site
|
||||
|
||||
from account.decorators import login_required
|
||||
|
||||
from symposion.schedule.forms import SlotEditForm, ScheduleSectionForm
|
||||
from symposion.schedule.models import Schedule, Day, Slot, Presentation, Session, SessionRole
|
||||
from symposion.schedule.timetable import TimeTable
|
||||
|
@ -47,7 +48,7 @@ def schedule_conference(request):
|
|||
ctx = {
|
||||
"sections": sections,
|
||||
}
|
||||
return render(request, "schedule/schedule_conference.html", ctx)
|
||||
return render(request, "symposion/schedule/schedule_conference.html", ctx)
|
||||
|
||||
|
||||
def schedule_detail(request, slug=None):
|
||||
|
@ -63,7 +64,7 @@ def schedule_detail(request, slug=None):
|
|||
"schedule": schedule,
|
||||
"days": days,
|
||||
}
|
||||
return render(request, "schedule/schedule_detail.html", ctx)
|
||||
return render(request, "symposion/schedule/schedule_detail.html", ctx)
|
||||
|
||||
|
||||
def schedule_list(request, slug=None):
|
||||
|
@ -76,7 +77,7 @@ def schedule_list(request, slug=None):
|
|||
"schedule": schedule,
|
||||
"presentations": presentations,
|
||||
}
|
||||
return render(request, "schedule/schedule_list.html", ctx)
|
||||
return render(request, "symposion/schedule/schedule_list.html", ctx)
|
||||
|
||||
|
||||
def schedule_list_csv(request, slug=None):
|
||||
|
@ -92,7 +93,7 @@ def schedule_list_csv(request, slug=None):
|
|||
file_slug = "presentations"
|
||||
response["Content-Disposition"] = 'attachment; filename="%s.csv"' % file_slug
|
||||
|
||||
response.write(loader.get_template("schedule/schedule_list.csv").render(Context({
|
||||
response.write(loader.get_template("symposion/schedule/schedule_list.csv").render(Context({
|
||||
"presentations": presentations,
|
||||
|
||||
})))
|
||||
|
@ -126,7 +127,7 @@ def schedule_edit(request, slug=None):
|
|||
"days": days,
|
||||
"form": form
|
||||
}
|
||||
return render(request, "schedule/schedule_edit.html", ctx)
|
||||
return render(request, "symposion/schedule/schedule_edit.html", ctx)
|
||||
|
||||
|
||||
@login_required
|
||||
|
@ -160,7 +161,7 @@ def schedule_slot_edit(request, slug, slot_pk):
|
|||
"form": form,
|
||||
"slot": slot,
|
||||
}
|
||||
return render(request, "schedule/_slot_edit.html", ctx)
|
||||
return render(request, "symposion/schedule/_slot_edit.html", ctx)
|
||||
|
||||
|
||||
def schedule_presentation_detail(request, pk):
|
||||
|
@ -175,7 +176,7 @@ def schedule_presentation_detail(request, pk):
|
|||
"presentation": presentation,
|
||||
"schedule": schedule,
|
||||
}
|
||||
return render(request, "schedule/presentation_detail.html", ctx)
|
||||
return render(request, "symposion/schedule/presentation_detail.html", ctx)
|
||||
|
||||
|
||||
def schedule_json(request):
|
||||
|
@ -230,7 +231,7 @@ def schedule_json(request):
|
|||
data.append(slot_data)
|
||||
|
||||
return HttpResponse(
|
||||
json.dumps({'schedule': data}),
|
||||
json.dumps({"schedule": data}),
|
||||
content_type="application/json"
|
||||
)
|
||||
|
||||
|
@ -238,7 +239,7 @@ def schedule_json(request):
|
|||
def session_list(request):
|
||||
sessions = Session.objects.all().order_by('pk')
|
||||
|
||||
return render(request, "schedule/session_list.html", {
|
||||
return render(request, "symposion/schedule/session_list.html", {
|
||||
"sessions": sessions,
|
||||
})
|
||||
|
||||
|
@ -306,7 +307,7 @@ def session_detail(request, session_id):
|
|||
|
||||
return redirect("schedule_session_detail", session_id)
|
||||
|
||||
return render(request, "schedule/session_detail.html", {
|
||||
return render(request, "symposion/schedule/session_detail.html", {
|
||||
"session": session,
|
||||
"chair": chair,
|
||||
"chair_denied": chair_denied,
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
from __future__ import unicode_literals
|
||||
from django import forms
|
||||
|
||||
from markitup.widgets import MarkItUpWidget
|
||||
|
||||
from symposion.speakers.models import Speaker
|
||||
|
||||
|
||||
|
@ -15,6 +13,3 @@ class SpeakerForm(forms.ModelForm):
|
|||
"biography",
|
||||
"photo",
|
||||
]
|
||||
widgets = {
|
||||
"biography": MarkItUpWidget(),
|
||||
}
|
||||
|
|
36
symposion/speakers/migrations/0001_initial.py
Normal file
36
symposion/speakers/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import datetime
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Speaker',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)),
|
||||
('name', models.CharField(verbose_name='Name', help_text='As you would like it to appear in the conference program.', max_length=100)),
|
||||
('biography', models.TextField(verbose_name='Biography', blank=True, help_text="A little bit about you. Edit using <a href='http://warpedvisions.org/projects/markdown-cheat-sheet/target='_blank'>Markdown</a>.")),
|
||||
('biography_html', models.TextField(blank=True)),
|
||||
('photo', models.ImageField(verbose_name='Photo', upload_to='speaker_photos', blank=True)),
|
||||
('annotation', models.TextField(verbose_name='Annotation')),
|
||||
('invite_email', models.CharField(verbose_name='Invite_email', unique=True, db_index=True, max_length=200, null=True)),
|
||||
('invite_token', models.CharField(verbose_name='Invite token', db_index=True, max_length=40)),
|
||||
('created', models.DateTimeField(editable=False, verbose_name='Created', default=datetime.datetime.now)),
|
||||
('user', models.OneToOneField(null=True, related_name='speaker_profile', verbose_name='User', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Speaker',
|
||||
'verbose_name_plural': 'Speakers',
|
||||
'ordering': ['name'],
|
||||
},
|
||||
),
|
||||
]
|
0
symposion/speakers/migrations/__init__.py
Normal file
0
symposion/speakers/migrations/__init__.py
Normal file
|
@ -9,7 +9,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from markitup.fields import MarkupField
|
||||
from symposion.markdown_parser import parse
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
|
@ -24,10 +24,11 @@ class Speaker(models.Model):
|
|||
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 "
|
||||
biography = models.TextField(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"))
|
||||
biography_html = models.TextField(blank=True)
|
||||
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"))
|
||||
|
@ -43,6 +44,10 @@ class Speaker(models.Model):
|
|||
verbose_name = _("Speaker")
|
||||
verbose_name_plural = _("Speakers")
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.biography_html = parse(self.biography)
|
||||
return super(Speaker, self).save(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
if self.user:
|
||||
return self.name
|
||||
|
|
|
@ -4,10 +4,11 @@ from django.http import Http404
|
|||
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 account.decorators import login_required
|
||||
|
||||
from symposion.proposals.models import ProposalBase
|
||||
from symposion.speakers.forms import SpeakerForm
|
||||
from symposion.speakers.models import Speaker
|
||||
|
@ -39,9 +40,8 @@ def speaker_create(request):
|
|||
return redirect("dashboard")
|
||||
else:
|
||||
form = SpeakerForm(initial={"name": request.user.get_full_name()})
|
||||
|
||||
return render(request, "speakers/speaker_create.html", {
|
||||
"form": form,
|
||||
return render(request, "symposion/speakers/speaker_create.html", {
|
||||
"speaker_form": form,
|
||||
})
|
||||
|
||||
|
||||
|
@ -68,8 +68,8 @@ def speaker_create_staff(request, pk):
|
|||
else:
|
||||
form = SpeakerForm(initial={"name": user.get_full_name()})
|
||||
|
||||
return render(request, "speakers/speaker_create.html", {
|
||||
"form": form,
|
||||
return render(request, "symposion/speakers/speaker_create.html", {
|
||||
"speaker_form": form,
|
||||
})
|
||||
|
||||
|
||||
|
@ -121,8 +121,8 @@ def speaker_edit(request, pk=None):
|
|||
else:
|
||||
form = SpeakerForm(instance=speaker)
|
||||
|
||||
return render(request, "speakers/speaker_edit.html", {
|
||||
"form": form,
|
||||
return render(request, "symposion/speakers/speaker_edit.html", {
|
||||
"speaker_form": form,
|
||||
})
|
||||
|
||||
|
||||
|
@ -132,7 +132,7 @@ def speaker_profile(request, pk):
|
|||
if not presentations and not request.user.is_staff:
|
||||
raise Http404()
|
||||
|
||||
return render(request, "speakers/speaker_profile.html", {
|
||||
return render(request, "symposion/speakers/speaker_profile.html", {
|
||||
"speaker": speaker,
|
||||
"presentations": presentations,
|
||||
})
|
||||
|
|
115
symposion/sponsorship/migrations/0001_initial.py
Normal file
115
symposion/sponsorship/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,115 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.conf import settings
|
||||
import datetime
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('symposion_conference', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Benefit',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')),
|
||||
('name', models.CharField(verbose_name='Name', max_length=100)),
|
||||
('description', models.TextField(blank=True, verbose_name='Description')),
|
||||
('type', models.CharField(default='simple', choices=[('text', 'Text'), ('file', 'File'), ('richtext', 'Rich Text'), ('weblogo', 'Web Logo'), ('simple', 'Simple'), ('option', 'Option')], verbose_name='Type', max_length=10)),
|
||||
('content_type', models.CharField(default='simple', choices=[('simple', 'Simple'), ('listing_text_af', 'Listing Text (Afrikaans)'), ('listing_text_ar', 'Listing Text (Arabic)'), ('listing_text_ast', 'Listing Text (Asturian)'), ('listing_text_az', 'Listing Text (Azerbaijani)'), ('listing_text_bg', 'Listing Text (Bulgarian)'), ('listing_text_be', 'Listing Text (Belarusian)'), ('listing_text_bn', 'Listing Text (Bengali)'), ('listing_text_br', 'Listing Text (Breton)'), ('listing_text_bs', 'Listing Text (Bosnian)'), ('listing_text_ca', 'Listing Text (Catalan)'), ('listing_text_cs', 'Listing Text (Czech)'), ('listing_text_cy', 'Listing Text (Welsh)'), ('listing_text_da', 'Listing Text (Danish)'), ('listing_text_de', 'Listing Text (German)'), ('listing_text_el', 'Listing Text (Greek)'), ('listing_text_en', 'Listing Text (English)'), ('listing_text_en-au', 'Listing Text (Australian English)'), ('listing_text_en-gb', 'Listing Text (British English)'), ('listing_text_eo', 'Listing Text (Esperanto)'), ('listing_text_es', 'Listing Text (Spanish)'), ('listing_text_es-ar', 'Listing Text (Argentinian Spanish)'), ('listing_text_es-mx', 'Listing Text (Mexican Spanish)'), ('listing_text_es-ni', 'Listing Text (Nicaraguan Spanish)'), ('listing_text_es-ve', 'Listing Text (Venezuelan Spanish)'), ('listing_text_et', 'Listing Text (Estonian)'), ('listing_text_eu', 'Listing Text (Basque)'), ('listing_text_fa', 'Listing Text (Persian)'), ('listing_text_fi', 'Listing Text (Finnish)'), ('listing_text_fr', 'Listing Text (French)'), ('listing_text_fy', 'Listing Text (Frisian)'), ('listing_text_ga', 'Listing Text (Irish)'), ('listing_text_gl', 'Listing Text (Galician)'), ('listing_text_he', 'Listing Text (Hebrew)'), ('listing_text_hi', 'Listing Text (Hindi)'), ('listing_text_hr', 'Listing Text (Croatian)'), ('listing_text_hu', 'Listing Text (Hungarian)'), ('listing_text_ia', 'Listing Text (Interlingua)'), ('listing_text_id', 'Listing Text (Indonesian)'), ('listing_text_io', 'Listing Text (Ido)'), ('listing_text_is', 'Listing Text (Icelandic)'), ('listing_text_it', 'Listing Text (Italian)'), ('listing_text_ja', 'Listing Text (Japanese)'), ('listing_text_ka', 'Listing Text (Georgian)'), ('listing_text_kk', 'Listing Text (Kazakh)'), ('listing_text_km', 'Listing Text (Khmer)'), ('listing_text_kn', 'Listing Text (Kannada)'), ('listing_text_ko', 'Listing Text (Korean)'), ('listing_text_lb', 'Listing Text (Luxembourgish)'), ('listing_text_lt', 'Listing Text (Lithuanian)'), ('listing_text_lv', 'Listing Text (Latvian)'), ('listing_text_mk', 'Listing Text (Macedonian)'), ('listing_text_ml', 'Listing Text (Malayalam)'), ('listing_text_mn', 'Listing Text (Mongolian)'), ('listing_text_mr', 'Listing Text (Marathi)'), ('listing_text_my', 'Listing Text (Burmese)'), ('listing_text_nb', 'Listing Text (Norwegian Bokmal)'), ('listing_text_ne', 'Listing Text (Nepali)'), ('listing_text_nl', 'Listing Text (Dutch)'), ('listing_text_nn', 'Listing Text (Norwegian Nynorsk)'), ('listing_text_os', 'Listing Text (Ossetic)'), ('listing_text_pa', 'Listing Text (Punjabi)'), ('listing_text_pl', 'Listing Text (Polish)'), ('listing_text_pt', 'Listing Text (Portuguese)'), ('listing_text_pt-br', 'Listing Text (Brazilian Portuguese)'), ('listing_text_ro', 'Listing Text (Romanian)'), ('listing_text_ru', 'Listing Text (Russian)'), ('listing_text_sk', 'Listing Text (Slovak)'), ('listing_text_sl', 'Listing Text (Slovenian)'), ('listing_text_sq', 'Listing Text (Albanian)'), ('listing_text_sr', 'Listing Text (Serbian)'), ('listing_text_sr-latn', 'Listing Text (Serbian Latin)'), ('listing_text_sv', 'Listing Text (Swedish)'), ('listing_text_sw', 'Listing Text (Swahili)'), ('listing_text_ta', 'Listing Text (Tamil)'), ('listing_text_te', 'Listing Text (Telugu)'), ('listing_text_th', 'Listing Text (Thai)'), ('listing_text_tr', 'Listing Text (Turkish)'), ('listing_text_tt', 'Listing Text (Tatar)'), ('listing_text_udm', 'Listing Text (Udmurt)'), ('listing_text_uk', 'Listing Text (Ukrainian)'), ('listing_text_ur', 'Listing Text (Urdu)'), ('listing_text_vi', 'Listing Text (Vietnamese)'), ('listing_text_zh-cn', 'Listing Text (Simplified Chinese)'), ('listing_text_zh-hans', 'Listing Text (Simplified Chinese)'), ('listing_text_zh-hant', 'Listing Text (Traditional Chinese)'), ('listing_text_zh-tw', 'Listing Text (Traditional Chinese)')], verbose_name='content type', max_length=20)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='BenefitLevel',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')),
|
||||
('max_words', models.PositiveIntegerField(blank=True, verbose_name='Max words', null=True)),
|
||||
('other_limits', models.CharField(blank=True, verbose_name='Other limits', max_length=200)),
|
||||
('benefit', models.ForeignKey(to='symposion_sponsorship.Benefit', related_name='benefit_levels', verbose_name='Benefit')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Benefit levels',
|
||||
'ordering': ['level'],
|
||||
'verbose_name': 'Benefit level',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Sponsor',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')),
|
||||
('name', models.CharField(verbose_name='Sponsor Name', max_length=100)),
|
||||
('display_url', models.URLField(blank=True, verbose_name='display URL')),
|
||||
('external_url', models.URLField(verbose_name='External URL')),
|
||||
('annotation', models.TextField(blank=True, verbose_name='Annotation')),
|
||||
('contact_name', models.CharField(verbose_name='Contact Name', max_length=100)),
|
||||
('contact_email', models.EmailField(verbose_name='Contact Email', max_length=254)),
|
||||
('added', models.DateTimeField(default=datetime.datetime.now, verbose_name='added')),
|
||||
('active', models.BooleanField(default=False, verbose_name='active')),
|
||||
('web_logo_benefit', models.NullBooleanField(verbose_name='Web logo benefit', help_text='Web logo benefit is complete')),
|
||||
('print_logo_benefit', models.NullBooleanField(verbose_name='Print logo benefit', help_text='Print logo benefit is complete')),
|
||||
('print_description_benefit', models.NullBooleanField(verbose_name='Print description benefit', help_text='Print description benefit is complete')),
|
||||
('company_description_benefit', models.NullBooleanField(verbose_name='Company description benefit', help_text='Company description benefit is complete')),
|
||||
('applicant', models.ForeignKey(to=settings.AUTH_USER_MODEL, null=True, related_name='sponsorships', verbose_name='Applicant')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Sponsors',
|
||||
'ordering': ['name'],
|
||||
'verbose_name': 'Sponsor',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SponsorBenefit',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')),
|
||||
('active', models.BooleanField(default=True, verbose_name='Active')),
|
||||
('max_words', models.PositiveIntegerField(blank=True, verbose_name='Max words', null=True)),
|
||||
('other_limits', models.CharField(blank=True, verbose_name='Other limits', max_length=200)),
|
||||
('text', models.TextField(blank=True, verbose_name='Text')),
|
||||
('upload', models.FileField(blank=True, verbose_name='File', upload_to='sponsor_files')),
|
||||
('is_complete', models.NullBooleanField(verbose_name='Complete?', help_text='True - benefit complete; False - benefit incomplete; Null - n/a')),
|
||||
('benefit', models.ForeignKey(to='symposion_sponsorship.Benefit', related_name='sponsor_benefits', verbose_name='Benefit')),
|
||||
('sponsor', models.ForeignKey(to='symposion_sponsorship.Sponsor', related_name='sponsor_benefits', verbose_name='Sponsor')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Sponsor benefits',
|
||||
'ordering': ['-active'],
|
||||
'verbose_name': 'Sponsor benefit',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SponsorLevel',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')),
|
||||
('name', models.CharField(verbose_name='Name', max_length=100)),
|
||||
('order', models.IntegerField(default=0, verbose_name='Order')),
|
||||
('cost', models.PositiveIntegerField(verbose_name='Cost')),
|
||||
('description', models.TextField(blank=True, verbose_name='Description', help_text='This is private.')),
|
||||
('conference', models.ForeignKey(to='symposion_conference.Conference', verbose_name='Conference')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Sponsor levels',
|
||||
'ordering': ['conference', 'order'],
|
||||
'verbose_name': 'Sponsor level',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='sponsor',
|
||||
name='level',
|
||||
field=models.ForeignKey(to='symposion_sponsorship.SponsorLevel', verbose_name='level'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='sponsor',
|
||||
name='sponsor_logo',
|
||||
field=models.ForeignKey(blank=True, to='symposion_sponsorship.SponsorBenefit', null=True, related_name='+', verbose_name='Sponsor logo', editable=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='benefitlevel',
|
||||
name='level',
|
||||
field=models.ForeignKey(to='symposion_sponsorship.SponsorLevel', related_name='benefit_levels', verbose_name='Level'),
|
||||
),
|
||||
]
|
0
symposion/sponsorship/migrations/__init__.py
Normal file
0
symposion/sponsorship/migrations/__init__.py
Normal file
|
@ -4,7 +4,7 @@ from django.views.generic import TemplateView
|
|||
|
||||
urlpatterns = patterns(
|
||||
"symposion.sponsorship.views",
|
||||
url(r"^$", TemplateView.as_view(template_name="sponsorship/list.html"), name="sponsor_list"),
|
||||
url(r"^$", TemplateView.as_view(template_name="symposion/sponsorship/list.html"), name="sponsor_list"),
|
||||
url(r"^apply/$", "sponsor_apply", name="sponsor_apply"),
|
||||
url(r"^add/$", "sponsor_add", name="sponsor_add"),
|
||||
url(r"^ziplogos/$", "sponsor_zip_logo_files", name="sponsor_zip_logos"),
|
||||
|
|
|
@ -9,12 +9,13 @@ 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 account.decorators import login_required
|
||||
|
||||
from symposion.sponsorship.forms import SponsorApplicationForm, \
|
||||
SponsorDetailsForm, SponsorBenefitsFormSet
|
||||
from symposion.sponsorship.models import Benefit, Sponsor, SponsorBenefit, \
|
||||
|
@ -43,7 +44,7 @@ def sponsor_apply(request):
|
|||
else:
|
||||
form = SponsorApplicationForm(user=request.user)
|
||||
|
||||
return render_to_response("sponsorship/apply.html", {
|
||||
return render_to_response("symposion/sponsorship/apply.html", {
|
||||
"form": form,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
|
@ -63,7 +64,7 @@ def sponsor_add(request):
|
|||
else:
|
||||
form = SponsorApplicationForm(user=request.user)
|
||||
|
||||
return render_to_response("sponsorship/add.html", {
|
||||
return render_to_response("symposion/sponsorship/add.html", {
|
||||
"form": form,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
|
@ -96,7 +97,7 @@ def sponsor_detail(request, pk):
|
|||
form = SponsorDetailsForm(instance=sponsor)
|
||||
formset = SponsorBenefitsFormSet(**formset_kwargs)
|
||||
|
||||
return render_to_response("sponsorship/detail.html", {
|
||||
return render_to_response("symposion/sponsorship/detail.html", {
|
||||
"sponsor": sponsor,
|
||||
"form": form,
|
||||
"formset": formset,
|
||||
|
|
56
symposion/teams/migrations/0001_initial.py
Normal file
56
symposion/teams/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,56 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import datetime
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('auth', '0006_require_contenttypes_0002'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Membership',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')),
|
||||
('state', models.CharField(max_length=20, choices=[('applied', 'applied'), ('invited', 'invited'), ('declined', 'declined'), ('rejected', 'rejected'), ('member', 'member'), ('manager', 'manager')], verbose_name='State')),
|
||||
('message', models.TextField(blank=True, verbose_name='Message')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Memberships',
|
||||
'verbose_name': 'Membership',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Team',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID')),
|
||||
('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=[('open', 'open'), ('application', 'by application'), ('invitation', 'by invitation')], verbose_name='Access')),
|
||||
('created', models.DateTimeField(editable=False, default=datetime.datetime.now, verbose_name='Created')),
|
||||
('manager_permissions', models.ManyToManyField(related_name='manager_teams', blank=True, to='auth.Permission', verbose_name='Manager permissions')),
|
||||
('permissions', models.ManyToManyField(related_name='member_teams', blank=True, to='auth.Permission', verbose_name='Permissions')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'Teams',
|
||||
'verbose_name': 'Team',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='membership',
|
||||
name='team',
|
||||
field=models.ForeignKey(verbose_name='Team', to='teams.Team', related_name='memberships'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='membership',
|
||||
name='user',
|
||||
field=models.ForeignKey(verbose_name='User', to=settings.AUTH_USER_MODEL, related_name='memberships'),
|
||||
),
|
||||
]
|
0
symposion/teams/migrations/__init__.py
Normal file
0
symposion/teams/migrations/__init__.py
Normal file
|
@ -2,12 +2,12 @@ from __future__ import unicode_literals
|
|||
from django.http import Http404, HttpResponseNotAllowed
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
|
||||
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 account.decorators import login_required
|
||||
|
||||
from symposion.utils.mail import send_email
|
||||
from symposion.teams.forms import TeamInvitationForm
|
||||
from symposion.teams.models import Team, Membership
|
||||
|
||||
|
@ -75,7 +75,7 @@ def team_detail(request, slug):
|
|||
else:
|
||||
form = None
|
||||
|
||||
return render(request, "teams/team_detail.html", {
|
||||
return render(request, "symposion/teams/team_detail.html", {
|
||||
"team": team,
|
||||
"state": state,
|
||||
"invite_form": form,
|
||||
|
|
|
@ -17,10 +17,10 @@ def send_email(to, kind, **kwargs):
|
|||
ctx.update(kwargs.get("context", {}))
|
||||
subject = "[%s] %s" % (
|
||||
current_site.name,
|
||||
render_to_string("emails/%s/subject.txt" % kind, ctx).strip()
|
||||
render_to_string("symposion/emails/%s/subject.txt" % kind, ctx).strip()
|
||||
)
|
||||
|
||||
message_html = render_to_string("emails/%s/message.html" % kind, ctx)
|
||||
message_html = render_to_string("symposion/emails/%s/message.html" % kind, ctx)
|
||||
message_plaintext = strip_tags(message_html)
|
||||
|
||||
from_email = settings.DEFAULT_FROM_EMAIL
|
||||
|
|
|
@ -1,53 +1,9 @@
|
|||
from __future__ import unicode_literals
|
||||
import hashlib
|
||||
import random
|
||||
|
||||
from django.shortcuts import render, redirect
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
import account.views
|
||||
|
||||
import symposion.forms
|
||||
|
||||
|
||||
class SignupView(account.views.SignupView):
|
||||
|
||||
form_class = symposion.forms.SignupForm
|
||||
form_kwargs = {
|
||||
"prefix": "signup",
|
||||
}
|
||||
|
||||
def create_user(self, form, commit=True):
|
||||
user_kwargs = {
|
||||
"first_name": form.cleaned_data["first_name"],
|
||||
"last_name": form.cleaned_data["last_name"]
|
||||
}
|
||||
return super(SignupView, self).create_user(form, commit=commit,
|
||||
**user_kwargs)
|
||||
|
||||
def generate_username(self, form):
|
||||
def random_username():
|
||||
h = hashlib.sha1(form.cleaned_data["email"]).hexdigest()[:25]
|
||||
# don't ask
|
||||
n = random.randint(1, (10 ** (5 - 1)) - 1)
|
||||
return "%s%d" % (h, n)
|
||||
while True:
|
||||
try:
|
||||
username = random_username()
|
||||
User.objects.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
break
|
||||
return username
|
||||
|
||||
|
||||
class LoginView(account.views.LoginView):
|
||||
|
||||
form_class = account.forms.LoginEmailForm
|
||||
form_kwargs = {
|
||||
"prefix": "login",
|
||||
}
|
||||
from account.decorators import login_required
|
||||
|
||||
|
||||
@login_required
|
||||
|
|
Loading…
Reference in a new issue