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…
	
	Add table
		
		Reference in a new issue
	
	 Patrick Altman
						Patrick Altman