diff --git a/README.rst b/README.rst index c0a3abd4..ebb3c6de 100644 --- a/README.rst +++ b/README.rst @@ -27,7 +27,12 @@ See http://eldarion.com/symposion/ for commercial support, customization and hos Quickstart ========== -If you're interested in running symposion locally, we have built a [basic +To install Symposion, run: + + pip install symposion + +Symposion is a Django app. You will need to create a Django project to +customize and manage your Symposion installation. We have built a [basic Django startproject template that includes Symposion][1]. [1]: https://github.com/pinax/pinax-project-symposion diff --git a/requirements/base.txt b/requirements/base.txt new file mode 100644 index 00000000..b503a4ba --- /dev/null +++ b/requirements/base.txt @@ -0,0 +1,13 @@ +Django>=1.5,<=1.6 +django-appconf==0.5 +django-forms-bootstrap>=2.0.3.post2 +django-markitup==2.1 +django-model-utils==2.0.2 +django-reversion==1.8 +django-sitetree==1.0.0 +django-taggit==0.11.2 +django-timezones==0.2 +django-user-accounts==1.0b13 +easy-thumbnails==1.4 +html5lib==0.95 +markdown==2.3.1 diff --git a/requirements-docs.txt b/requirements/docs.txt similarity index 100% rename from requirements-docs.txt rename to requirements/docs.txt diff --git a/setup.py b/setup.py index 74eebbc5..bdf75e6f 100644 --- a/setup.py +++ b/setup.py @@ -1,10 +1,20 @@ #!/usr/bin/env python - +import os from setuptools import setup, find_packages import symposion +def read_file(filename): + """Read a file into a string.""" + path = os.path.abspath(os.path.dirname(__file__)) + filepath = os.path.join(path, filename) + try: + return open(filepath).read() + except IOError: + return '' + + setup( name="symposion", author="James Tauber", @@ -12,7 +22,7 @@ setup( version=symposion.__version__, description="A collection of Django apps for conference websites.", url="http://eldarion.com/symposion/", - packages=find_packages(exclude=["symposion_project"]), + packages=find_packages(), include_package_data=True, classifiers=( "Development Status :: 4 - Beta", @@ -22,4 +32,5 @@ setup( "Natural Language :: English", "License :: OSI Approved :: MIT License", ), + install_requires=read_file("requirements/base.txt").splitlines(), ) diff --git a/symposion/boxes/migrations/0001_initial.py b/symposion/boxes/migrations/0001_initial.py new file mode 100644 index 00000000..7e0f7f75 --- /dev/null +++ b/symposion/boxes/migrations/0001_initial.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Box' + db.create_table('boxes_box', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('label', self.gf('django.db.models.fields.CharField')(max_length=100, db_index=True)), + ('content', self.gf('markitup.fields.MarkupField')(no_rendered_field=True, blank=True)), + ('created_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='boxes', to=orm['auth.User'])), + ('last_updated_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='updated_boxes', to=orm['auth.User'])), + ('_content_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('boxes', ['Box']) + + + def backwards(self, orm): + # Deleting model 'Box' + db.delete_table('boxes_box') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'boxes.box': { + 'Meta': {'object_name': 'Box'}, + '_content_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'content': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'boxes'", 'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '100', 'db_index': 'True'}), + 'last_updated_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'updated_boxes'", 'to': "orm['auth.User']"}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + } + } + + complete_apps = ['boxes'] \ No newline at end of file diff --git a/symposion/boxes/migrations/__init__.py b/symposion/boxes/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/boxes/models.py b/symposion/boxes/models.py index f12e5c95..4eb2a019 100644 --- a/symposion/boxes/models.py +++ b/symposion/boxes/models.py @@ -1,5 +1,4 @@ from django.db import models - from django.contrib.auth.models import User import reversion diff --git a/symposion/boxes/urls.py b/symposion/boxes/urls.py index c7076c91..96464b66 100644 --- a/symposion/boxes/urls.py +++ b/symposion/boxes/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls import url, patterns +from django.conf.urls import patterns, url urlpatterns = patterns( diff --git a/symposion/cms/migrations/0001_initial.py b/symposion/cms/migrations/0001_initial.py new file mode 100644 index 00000000..beb391d2 --- /dev/null +++ b/symposion/cms/migrations/0001_initial.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Page' + db.create_table('cms_page', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('title', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('path', self.gf('django.db.models.fields.CharField')(unique=True, max_length=100)), + ('body', self.gf('markitup.fields.MarkupField')(no_rendered_field=True)), + ('status', self.gf('django.db.models.fields.IntegerField')(default=2)), + ('publish_date', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('updated', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('_body_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('cms', ['Page']) + + # Adding model 'File' + db.create_table('cms_file', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('file', self.gf('django.db.models.fields.files.FileField')(max_length=100)), + ('created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + )) + db.send_create_signal('cms', ['File']) + + + def backwards(self, orm): + # Deleting model 'Page' + db.delete_table('cms_page') + + # Deleting model 'File' + db.delete_table('cms_file') + + + models = { + 'cms.file': { + 'Meta': {'object_name': 'File'}, + 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'cms.page': { + 'Meta': {'object_name': 'Page'}, + '_body_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'body': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}), + 'publish_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'status': ('django.db.models.fields.IntegerField', [], {'default': '2'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'updated': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['cms'] \ No newline at end of file diff --git a/symposion/cms/migrations/__init__.py b/symposion/cms/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/conference/migrations/0001_initial.py b/symposion/conference/migrations/0001_initial.py new file mode 100644 index 00000000..7546ca52 --- /dev/null +++ b/symposion/conference/migrations/0001_initial.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Conference' + db.create_table('conference_conference', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('title', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('start_date', self.gf('django.db.models.fields.DateField')(null=True, blank=True)), + ('end_date', self.gf('django.db.models.fields.DateField')(null=True, blank=True)), + ('timezone', self.gf('timezones.fields.TimeZoneField')(default='US/Eastern', max_length=100, blank=True)), + )) + db.send_create_signal('conference', ['Conference']) + + # Adding model 'Section' + db.create_table('conference_section', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('conference', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['conference.Conference'])), + ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('slug', self.gf('django.db.models.fields.SlugField')(max_length=50)), + ('start_date', self.gf('django.db.models.fields.DateField')(null=True, blank=True)), + ('end_date', self.gf('django.db.models.fields.DateField')(null=True, blank=True)), + )) + db.send_create_signal('conference', ['Section']) + + + def backwards(self, orm): + # Deleting model 'Conference' + db.delete_table('conference_conference') + + # Deleting model 'Section' + db.delete_table('conference_section') + + + models = { + 'conference.conference': { + 'Meta': {'object_name': 'Conference'}, + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'timezone': ('timezones.fields.TimeZoneField', [], {'default': "'US/Eastern'", 'max_length': '100', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'conference.section': { + 'Meta': {'ordering': "['start_date']", 'object_name': 'Section'}, + 'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Conference']"}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['conference'] \ No newline at end of file diff --git a/symposion/conference/migrations/__init__.py b/symposion/conference/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/conference/models.py b/symposion/conference/models.py index 354403b6..db09050f 100644 --- a/symposion/conference/models.py +++ b/symposion/conference/models.py @@ -3,6 +3,9 @@ from django.utils.translation import ugettext_lazy as _ from timezones.fields import TimeZoneField +from south.modelsinspector import add_introspection_rules +add_introspection_rules([], [r"^timezones\.fields\.TimeZoneField"]) + CONFERENCE_CACHE = {} diff --git a/symposion/proposals/actions.py b/symposion/proposals/actions.py index 3dcfb168..d059da81 100644 --- a/symposion/proposals/actions.py +++ b/symposion/proposals/actions.py @@ -22,9 +22,8 @@ def export_as_csv_action(description="Export selected objects as CSV file", elif exclude: excludeset = set(exclude) field_names = field_names - excludeset - response = HttpResponse(mimetype="text/csv") - response["Content-Disposition"] = \ - "attachment; filename=%s.csv" % unicode(opts).replace(".", "_") + response = HttpResponse(content_type="text/csv") + response["Content-Disposition"] = "attachment; filename=%s.csv" % unicode(opts).replace(".", "_") writer = csv.writer(response) if header: writer.writerow(list(field_names)) diff --git a/symposion/proposals/migrations/0001_initial.py b/symposion/proposals/migrations/0001_initial.py new file mode 100644 index 00000000..dc013cbd --- /dev/null +++ b/symposion/proposals/migrations/0001_initial.py @@ -0,0 +1,210 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + depends_on = ( + ("speakers", "0001_initial"), + ) + + def forwards(self, orm): + # Adding model 'ProposalSection' + db.create_table('proposals_proposalsection', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('section', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['conference.Section'], unique=True)), + ('start', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)), + ('end', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)), + ('closed', self.gf('django.db.models.fields.NullBooleanField')(null=True, blank=True)), + ('published', self.gf('django.db.models.fields.NullBooleanField')(null=True, blank=True)), + )) + db.send_create_signal('proposals', ['ProposalSection']) + + # Adding model 'ProposalKind' + db.create_table('proposals_proposalkind', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('section', self.gf('django.db.models.fields.related.ForeignKey')(related_name='proposal_kinds', to=orm['conference.Section'])), + ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('slug', self.gf('django.db.models.fields.SlugField')(max_length=50)), + )) + db.send_create_signal('proposals', ['ProposalKind']) + + # Adding model 'ProposalBase' + db.create_table('proposals_proposalbase', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('kind', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['proposals.ProposalKind'])), + ('title', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('description', self.gf('django.db.models.fields.TextField')(max_length=400)), + ('abstract', self.gf('markitup.fields.MarkupField')(no_rendered_field=True)), + ('additional_notes', self.gf('markitup.fields.MarkupField')(no_rendered_field=True, blank=True)), + ('submitted', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('speaker', self.gf('django.db.models.fields.related.ForeignKey')(related_name='proposals', to=orm['speakers.Speaker'])), + ('cancelled', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('_abstract_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + ('_additional_notes_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('proposals', ['ProposalBase']) + + # Adding model 'AdditionalSpeaker' + db.create_table('proposals_proposalbase_additional_speakers', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('speaker', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['speakers.Speaker'])), + ('proposalbase', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['proposals.ProposalBase'])), + ('status', self.gf('django.db.models.fields.IntegerField')(default=1)), + )) + db.send_create_signal('proposals', ['AdditionalSpeaker']) + + # Adding unique constraint on 'AdditionalSpeaker', fields ['speaker', 'proposalbase'] + db.create_unique('proposals_proposalbase_additional_speakers', ['speaker_id', 'proposalbase_id']) + + # Adding model 'SupportingDocument' + db.create_table('proposals_supportingdocument', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('proposal', self.gf('django.db.models.fields.related.ForeignKey')(related_name='supporting_documents', to=orm['proposals.ProposalBase'])), + ('uploaded_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('created_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('file', self.gf('django.db.models.fields.files.FileField')(max_length=100)), + ('description', self.gf('django.db.models.fields.CharField')(max_length=140)), + )) + db.send_create_signal('proposals', ['SupportingDocument']) + + + def backwards(self, orm): + # Removing unique constraint on 'AdditionalSpeaker', fields ['speaker', 'proposalbase'] + db.delete_unique('proposals_proposalbase_additional_speakers', ['speaker_id', 'proposalbase_id']) + + # Deleting model 'ProposalSection' + db.delete_table('proposals_proposalsection') + + # Deleting model 'ProposalKind' + db.delete_table('proposals_proposalkind') + + # Deleting model 'ProposalBase' + db.delete_table('proposals_proposalbase') + + # Deleting model 'AdditionalSpeaker' + db.delete_table('proposals_proposalbase_additional_speakers') + + # Deleting model 'SupportingDocument' + db.delete_table('proposals_supportingdocument') + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'conference.conference': { + 'Meta': {'object_name': 'Conference'}, + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'timezone': ('timezones.fields.TimeZoneField', [], {'default': "'US/Eastern'", 'max_length': '100', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'conference.section': { + 'Meta': {'ordering': "['start_date']", 'object_name': 'Section'}, + 'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Conference']"}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'proposals.additionalspeaker': { + 'Meta': {'unique_together': "(('speaker', 'proposalbase'),)", 'object_name': 'AdditionalSpeaker', 'db_table': "'proposals_proposalbase_additional_speakers'"}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposalbase': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['proposals.ProposalBase']"}), + 'speaker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['speakers.Speaker']"}), + 'status': ('django.db.models.fields.IntegerField', [], {'default': '1'}) + }, + 'proposals.proposalbase': { + 'Meta': {'object_name': 'ProposalBase'}, + '_abstract_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + '_additional_notes_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'abstract': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}), + 'additional_notes': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'additional_speakers': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['speakers.Speaker']", 'symmetrical': 'False', 'through': "orm['proposals.AdditionalSpeaker']", 'blank': 'True'}), + 'cancelled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'description': ('django.db.models.fields.TextField', [], {'max_length': '400'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'kind': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['proposals.ProposalKind']"}), + 'speaker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'proposals'", 'to': "orm['speakers.Speaker']"}), + 'submitted': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'proposals.proposalkind': { + 'Meta': {'object_name': 'ProposalKind'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'proposal_kinds'", 'to': "orm['conference.Section']"}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}) + }, + 'proposals.proposalsection': { + 'Meta': {'object_name': 'ProposalSection'}, + 'closed': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'end': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'published': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}), + 'section': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['conference.Section']", 'unique': 'True'}), + 'start': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + 'proposals.supportingdocument': { + 'Meta': {'object_name': 'SupportingDocument'}, + 'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '140'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposal': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'supporting_documents'", 'to': "orm['proposals.ProposalBase']"}), + 'uploaded_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'speakers.speaker': { + 'Meta': {'ordering': "['name']", 'object_name': 'Speaker'}, + '_biography_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'annotation': ('django.db.models.fields.TextField', [], {}), + 'biography': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invite_email': ('django.db.models.fields.CharField', [], {'max_length': '200', 'unique': 'True', 'null': 'True', 'db_index': 'True'}), + 'invite_token': ('django.db.models.fields.CharField', [], {'max_length': '40', 'db_index': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'photo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'speaker_profile'", 'unique': 'True', 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['proposals'] diff --git a/symposion/proposals/migrations/__init__.py b/symposion/proposals/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/proposals/urls.py b/symposion/proposals/urls.py index 994fad30..2a0a6ffe 100644 --- a/symposion/proposals/urls.py +++ b/symposion/proposals/urls.py @@ -12,15 +12,10 @@ urlpatterns = patterns( name="proposal_speaker_manage"), url(r"^(\d+)/cancel/$", "proposal_cancel", name="proposal_cancel"), url(r"^(\d+)/leave/$", "proposal_leave", name="proposal_leave"), - url(r"^(\d+)/join/$", "proposal_pending_join", - name="proposal_pending_join"), - url(r"^(\d+)/decline/$", "proposal_pending_decline", - name="proposal_pending_decline"), + url(r"^(\d+)/join/$", "proposal_pending_join", name="proposal_pending_join"), + url(r"^(\d+)/decline/$", "proposal_pending_decline", name="proposal_pending_decline"), - url(r"^(\d+)/document/create/$", "document_create", - name="proposal_document_create"), - url(r"^document/(\d+)/delete/$", "document_delete", - name="proposal_document_delete"), - url(r"^document/(\d+)/([^/]+)$", "document_download", - name="proposal_document_download"), + url(r"^(\d+)/document/create/$", "document_create", name="proposal_document_create"), + url(r"^document/(\d+)/delete/$", "document_delete", name="proposal_document_delete"), + url(r"^document/(\d+)/([^/]+)$", "document_download", name="proposal_document_download"), ) diff --git a/symposion/proposals/views.py b/symposion/proposals/views.py index 878d17ce..fe146c9b 100644 --- a/symposion/proposals/views.py +++ b/symposion/proposals/views.py @@ -1,3 +1,4 @@ +import hashlib import random import sys @@ -9,8 +10,6 @@ from django.http import Http404, HttpResponse, HttpResponseForbidden from django.shortcuts import render, redirect, get_object_or_404 from django.views import static -from hashlib import sha1 - from django.contrib import messages from django.contrib.auth.models import User from django.contrib.auth.decorators import login_required @@ -123,8 +122,8 @@ def proposal_speaker_manage(request, pk): Q(user=None, invite_email=email_address) ) except Speaker.DoesNotExist: - salt = sha1(str(random.random())).hexdigest()[:5] - token = sha1(salt + email_address).hexdigest() + salt = hashlib.sha1(str(random.random())).hexdigest()[:5] + token = hashlib.sha1(salt + email_address).hexdigest() pending = Speaker.objects.create( invite_email=email_address, invite_token=token, diff --git a/symposion/reviews/fixture_gen.py b/symposion/reviews/fixture_gen.py deleted file mode 100644 index 3a6aaa40..00000000 --- a/symposion/reviews/fixture_gen.py +++ /dev/null @@ -1,9 +0,0 @@ -from django.contrib.auth.models import Group - -from fixture_generator import fixture_generator - - -@fixture_generator(Group) -def initial_data(): - Group.objects.create(name="reviewers") - Group.objects.create(name="reviewers-admins") diff --git a/symposion/reviews/migrations/0001_initial.py b/symposion/reviews/migrations/0001_initial.py new file mode 100644 index 00000000..76df4e2f --- /dev/null +++ b/symposion/reviews/migrations/0001_initial.py @@ -0,0 +1,316 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'ReviewAssignment' + db.create_table('reviews_reviewassignment', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('proposal', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['proposals.ProposalBase'])), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('origin', self.gf('django.db.models.fields.IntegerField')()), + ('assigned_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('opted_out', self.gf('django.db.models.fields.BooleanField')(default=False)), + )) + db.send_create_signal('reviews', ['ReviewAssignment']) + + # Adding model 'ProposalMessage' + db.create_table('reviews_proposalmessage', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('proposal', self.gf('django.db.models.fields.related.ForeignKey')(related_name='messages', to=orm['proposals.ProposalBase'])), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('message', self.gf('markitup.fields.MarkupField')(no_rendered_field=True)), + ('submitted_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('_message_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('reviews', ['ProposalMessage']) + + # Adding model 'Review' + db.create_table('reviews_review', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('proposal', self.gf('django.db.models.fields.related.ForeignKey')(related_name='reviews', to=orm['proposals.ProposalBase'])), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('vote', self.gf('django.db.models.fields.CharField')(max_length=2, blank=True)), + ('comment', self.gf('markitup.fields.MarkupField')(no_rendered_field=True)), + ('submitted_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('_comment_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('reviews', ['Review']) + + # Adding model 'LatestVote' + db.create_table('reviews_latestvote', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('proposal', self.gf('django.db.models.fields.related.ForeignKey')(related_name='votes', to=orm['proposals.ProposalBase'])), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('vote', self.gf('django.db.models.fields.CharField')(max_length=2)), + ('submitted_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + )) + db.send_create_signal('reviews', ['LatestVote']) + + # Adding unique constraint on 'LatestVote', fields ['proposal', 'user'] + db.create_unique('reviews_latestvote', ['proposal_id', 'user_id']) + + # Adding model 'ProposalResult' + db.create_table('reviews_proposalresult', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('proposal', self.gf('django.db.models.fields.related.OneToOneField')(related_name='result', unique=True, to=orm['proposals.ProposalBase'])), + ('score', self.gf('django.db.models.fields.DecimalField')(default='0.00', max_digits=5, decimal_places=2)), + ('comment_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), + ('vote_count', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), + ('plus_one', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), + ('plus_zero', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), + ('minus_zero', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), + ('minus_one', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), + ('accepted', self.gf('django.db.models.fields.NullBooleanField')(default=None, null=True, blank=True)), + ('status', self.gf('django.db.models.fields.CharField')(default='undecided', max_length=20)), + )) + db.send_create_signal('reviews', ['ProposalResult']) + + # Adding model 'Comment' + db.create_table('reviews_comment', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('proposal', self.gf('django.db.models.fields.related.ForeignKey')(related_name='comments', to=orm['proposals.ProposalBase'])), + ('commenter', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('text', self.gf('markitup.fields.MarkupField')(no_rendered_field=True)), + ('public', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('commented_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('_text_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('reviews', ['Comment']) + + # Adding model 'NotificationTemplate' + db.create_table('reviews_notificationtemplate', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('label', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('from_address', self.gf('django.db.models.fields.EmailField')(max_length=75)), + ('subject', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('body', self.gf('django.db.models.fields.TextField')()), + )) + db.send_create_signal('reviews', ['NotificationTemplate']) + + # Adding model 'ResultNotification' + db.create_table('reviews_resultnotification', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('proposal', self.gf('django.db.models.fields.related.ForeignKey')(related_name='notifications', to=orm['proposals.ProposalBase'])), + ('template', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['reviews.NotificationTemplate'], null=True, on_delete=models.SET_NULL, blank=True)), + ('timestamp', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('to_address', self.gf('django.db.models.fields.EmailField')(max_length=75)), + ('from_address', self.gf('django.db.models.fields.EmailField')(max_length=75)), + ('subject', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('body', self.gf('django.db.models.fields.TextField')()), + )) + db.send_create_signal('reviews', ['ResultNotification']) + + + def backwards(self, orm): + # Removing unique constraint on 'LatestVote', fields ['proposal', 'user'] + db.delete_unique('reviews_latestvote', ['proposal_id', 'user_id']) + + # Deleting model 'ReviewAssignment' + db.delete_table('reviews_reviewassignment') + + # Deleting model 'ProposalMessage' + db.delete_table('reviews_proposalmessage') + + # Deleting model 'Review' + db.delete_table('reviews_review') + + # Deleting model 'LatestVote' + db.delete_table('reviews_latestvote') + + # Deleting model 'ProposalResult' + db.delete_table('reviews_proposalresult') + + # Deleting model 'Comment' + db.delete_table('reviews_comment') + + # Deleting model 'NotificationTemplate' + db.delete_table('reviews_notificationtemplate') + + # Deleting model 'ResultNotification' + db.delete_table('reviews_resultnotification') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'conference.conference': { + 'Meta': {'object_name': 'Conference'}, + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'timezone': ('timezones.fields.TimeZoneField', [], {'default': "'US/Eastern'", 'max_length': '100', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'conference.section': { + 'Meta': {'ordering': "['start_date']", 'object_name': 'Section'}, + 'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Conference']"}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'proposals.additionalspeaker': { + 'Meta': {'unique_together': "(('speaker', 'proposalbase'),)", 'object_name': 'AdditionalSpeaker', 'db_table': "'proposals_proposalbase_additional_speakers'"}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposalbase': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['proposals.ProposalBase']"}), + 'speaker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['speakers.Speaker']"}), + 'status': ('django.db.models.fields.IntegerField', [], {'default': '1'}) + }, + 'proposals.proposalbase': { + 'Meta': {'object_name': 'ProposalBase'}, + '_abstract_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + '_additional_notes_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'abstract': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}), + 'additional_notes': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'additional_speakers': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['speakers.Speaker']", 'symmetrical': 'False', 'through': "orm['proposals.AdditionalSpeaker']", 'blank': 'True'}), + 'cancelled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'description': ('django.db.models.fields.TextField', [], {'max_length': '400'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'kind': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['proposals.ProposalKind']"}), + 'speaker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'proposals'", 'to': "orm['speakers.Speaker']"}), + 'submitted': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'proposals.proposalkind': { + 'Meta': {'object_name': 'ProposalKind'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'proposal_kinds'", 'to': "orm['conference.Section']"}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}) + }, + 'reviews.comment': { + 'Meta': {'object_name': 'Comment'}, + '_text_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'commented_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'commenter': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposal': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'comments'", 'to': "orm['proposals.ProposalBase']"}), + 'public': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'text': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}) + }, + 'reviews.latestvote': { + 'Meta': {'unique_together': "[('proposal', 'user')]", 'object_name': 'LatestVote'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposal': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['proposals.ProposalBase']"}), + 'submitted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'vote': ('django.db.models.fields.CharField', [], {'max_length': '2'}) + }, + 'reviews.notificationtemplate': { + 'Meta': {'object_name': 'NotificationTemplate'}, + 'body': ('django.db.models.fields.TextField', [], {}), + 'from_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'subject': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'reviews.proposalmessage': { + 'Meta': {'ordering': "['submitted_at']", 'object_name': 'ProposalMessage'}, + '_message_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'message': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}), + 'proposal': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'messages'", 'to': "orm['proposals.ProposalBase']"}), + 'submitted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'reviews.proposalresult': { + 'Meta': {'object_name': 'ProposalResult'}, + 'accepted': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}), + 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'minus_one': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'minus_zero': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'plus_one': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'plus_zero': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'proposal': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'result'", 'unique': 'True', 'to': "orm['proposals.ProposalBase']"}), + 'score': ('django.db.models.fields.DecimalField', [], {'default': "'0.00'", 'max_digits': '5', 'decimal_places': '2'}), + 'status': ('django.db.models.fields.CharField', [], {'default': "'undecided'", 'max_length': '20'}), + 'vote_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}) + }, + 'reviews.resultnotification': { + 'Meta': {'object_name': 'ResultNotification'}, + 'body': ('django.db.models.fields.TextField', [], {}), + 'from_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposal': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notifications'", 'to': "orm['proposals.ProposalBase']"}), + 'subject': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'template': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['reviews.NotificationTemplate']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'to_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}) + }, + 'reviews.review': { + 'Meta': {'object_name': 'Review'}, + '_comment_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'comment': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposal': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reviews'", 'to': "orm['proposals.ProposalBase']"}), + 'submitted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}), + 'vote': ('django.db.models.fields.CharField', [], {'max_length': '2', 'blank': 'True'}) + }, + 'reviews.reviewassignment': { + 'Meta': {'object_name': 'ReviewAssignment'}, + 'assigned_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'opted_out': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'origin': ('django.db.models.fields.IntegerField', [], {}), + 'proposal': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['proposals.ProposalBase']"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'speakers.speaker': { + 'Meta': {'ordering': "['name']", 'object_name': 'Speaker'}, + '_biography_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'annotation': ('django.db.models.fields.TextField', [], {}), + 'biography': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invite_email': ('django.db.models.fields.CharField', [], {'max_length': '200', 'unique': 'True', 'null': 'True', 'db_index': 'True'}), + 'invite_token': ('django.db.models.fields.CharField', [], {'max_length': '40', 'db_index': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'photo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'speaker_profile'", 'unique': 'True', 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['reviews'] \ No newline at end of file diff --git a/symposion/reviews/migrations/__init__.py b/symposion/reviews/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/reviews/tests.py b/symposion/reviews/tests.py deleted file mode 100644 index 07e3cc99..00000000 --- a/symposion/reviews/tests.py +++ /dev/null @@ -1,143 +0,0 @@ -from django.core.urlresolvers import reverse -from django.test import TestCase - -from django.contrib.auth.models import User, Group - -from symposion.proposals.models import Proposal -from symposion.reviews.models import Review, ReviewAssignment - - -class login(object): - def __init__(self, testcase, user, password): - self.testcase = testcase - success = testcase.client.login(username=user, password=password) - self.testcase.assertTrue( - success, - "login with username=%r, password=%r failed" % (user, password) - ) - - def __enter__(self): - pass - - def __exit__(self, *args): - self.testcase.client.logout() - - -class ReviewTests(TestCase): - fixtures = ["proposals"] - - def get(self, url_name, *args, **kwargs): - return self.client.get(reverse(url_name, args=args, kwargs=kwargs)) - - def post(self, url_name, *args, **kwargs): - data = kwargs.pop("data") - return self.client.post(reverse(url_name, args=args, kwargs=kwargs), data) - - def login(self, user, password): - return login(self, user, password) - - def test_detail_perms(self): - guidos_proposal = Proposal.objects.all()[0] - response = self.get("review_detail", pk=guidos_proposal.pk) - - # Not logged in - self.assertEqual(response.status_code, 302) - - with self.login("guido", "pythonisawesome"): - response = self.get("review_detail", pk=guidos_proposal.pk) - # Guido can see his own proposal. - self.assertEqual(response.status_code, 200) - - with self.login("matz", "pythonsucks"): - response = self.get("review_detail", pk=guidos_proposal.pk) - # Matz can't see guido's proposal - self.assertEqual(response.status_code, 302) - - larry = User.objects.get(username="larryw") - # Larry is a trustworthy guy, he's a reviewer. - larry.groups.add(Group.objects.get(name="reviewers")) - with self.login("larryw", "linenoisehere"): - response = self.get("review_detail", pk=guidos_proposal.pk) - # Reviewers can see a review detail page. - self.assertEqual(response.status_code, 200) - - def test_reviewing(self): - guidos_proposal = Proposal.objects.all()[0] - - with self.login("guido", "pythonisawesome"): - response = self.post("review_review", pk=guidos_proposal.pk, data={ - "vote": "+1", - }) - # It redirects, but... - self.assertEqual(response.status_code, 302) - # ... no vote recorded - self.assertEqual(guidos_proposal.reviews.count(), 0) - - larry = User.objects.get(username="larryw") - # Larry is a trustworthy guy, he's a reviewer. - larry.groups.add(Group.objects.get(name="reviewers")) - with self.login("larryw", "linenoisehere"): - response = self.post("review_review", pk=guidos_proposal.pk, data={ - "vote": "+0", - "text": "Looks like a decent proposal, and Guido is a smart guy", - }) - self.assertEqual(response.status_code, 302) - self.assertEqual(guidos_proposal.reviews.count(), 1) - self.assertEqual(ReviewAssignment.objects.count(), 1) - assignment = ReviewAssignment.objects.get() - self.assertEqual(assignment.proposal, guidos_proposal) - self.assertEqual(assignment.origin, ReviewAssignment.OPT_IN) - self.assertEqual(guidos_proposal.comments.count(), 1) - comment = guidos_proposal.comments.get() - self.assertFalse(comment.public) - - response = self.post("review_review", pk=guidos_proposal.pk, data={ - "vote": "+1", - "text": "Actually Perl is dead, we really need a talk on the future", - }) - self.assertEqual(guidos_proposal.reviews.count(), 2) - self.assertEqual(ReviewAssignment.objects.count(), 1) - assignment = ReviewAssignment.objects.get() - self.assertEqual(assignment.review, Review.objects.order_by("-id")[0]) - self.assertEqual(guidos_proposal.comments.count(), 2) - - # Larry's a big fan... - response = self.post("review_review", pk=guidos_proposal.pk, data={ - "vote": "+20", - }) - self.assertEqual(guidos_proposal.reviews.count(), 2) - - def test_speaker_commenting(self): - guidos_proposal = Proposal.objects.all()[0] - - with self.login("guido", "pythonisawesome"): - response = self.get("review_comment", pk=guidos_proposal.pk) - # Guido can comment on his proposal. - self.assertEqual(response.status_code, 200) - - response = self.post("review_comment", pk=guidos_proposal.pk, data={ - "text": "FYI I can do this as a 30-minute or 45-minute talk.", - }) - self.assertEqual(response.status_code, 302) - self.assertEqual(guidos_proposal.comments.count(), 1) - comment = guidos_proposal.comments.get() - self.assertTrue(comment.public) - - larry = User.objects.get(username="larryw") - # Larry is a trustworthy guy, he's a reviewer. - larry.groups.add(Group.objects.get(name="reviewers")) - with self.login("larryw", "linenoisehere"): - response = self.get("review_comment", pk=guidos_proposal.pk) - # Larry can comment, since he's a reviewer - self.assertEqual(response.status_code, 200) - - response = self.post("review_comment", pk=guidos_proposal.pk, data={ - "text": "Thanks for the heads-up Guido." - }) - self.assertEqual(response.status_code, 302) - self.assertEqual(guidos_proposal.comments.count(), 2) - - with self.login("matz", "pythonsucks"): - response = self.get("review_comment", pk=guidos_proposal.pk) - # Matz can't comment. - self.assertEqual(response.status_code, 302) diff --git a/symposion/reviews/urls.py b/symposion/reviews/urls.py index 09264557..55196c65 100644 --- a/symposion/reviews/urls.py +++ b/symposion/reviews/urls.py @@ -3,30 +3,18 @@ from django.conf.urls import patterns, url urlpatterns = patterns( "symposion.reviews.views", - url(r"^section/(?P[\w\-]+)/all/$", "review_section", - {"reviewed": "all"}, name="review_section"), - url(r"^section/(?P[\w\-]+)/reviewed/$", "review_section", - {"reviewed": "reviewed"}, name="user_reviewed"), - url(r"^section/(?P[\w\-]+)/not_reviewed/$", "review_section", - {"reviewed": "not_reviewed"}, name="user_not_reviewed"), - url(r"^section/(?P[\w\-]+)/assignments/$", "review_section", - {"assigned": True}, name="review_section_assignments"), - url(r"^section/(?P[\w\-]+)/status/$", "review_status", - name="review_status"), - url(r"^section/(?P[\w\-]+)/status/(?P\w+)/$", - "review_status", name="review_status"), - url(r"^section/(?P[\w\-]+)/list/(?P\d+)/$", - "review_list", name="review_list_user"), - url(r"^section/(?P[\w\-]+)/admin/$", "review_admin", - name="review_admin"), - url(r"^section/(?P[\w\-]+)/admin/accept/$", - "review_bulk_accept", name="review_bulk_accept"), - url(r"^section/(?P[\w\-]+)/notification/(?P\w+)/$", - "result_notification", name="result_notification"), - url(r"^section/(?P[\w\-]+)/notification/(?P\w+)/prepare/$", - "result_notification_prepare", name="result_notification_prepare"), - url(r"^section/(?P[\w\-]+)/notification/(?P\w+)/send/$", - "result_notification_send", name="result_notification_send"), + url(r"^section/(?P[\w\-]+)/all/$", "review_section", {"reviewed": "all"}, name="review_section"), + url(r"^section/(?P[\w\-]+)/reviewed/$", "review_section", {"reviewed": "reviewed"}, name="user_reviewed"), + url(r"^section/(?P[\w\-]+)/not_reviewed/$", "review_section", {"reviewed": "not_reviewed"}, name="user_not_reviewed"), + url(r"^section/(?P[\w\-]+)/assignments/$", "review_section", {"assigned": True}, name="review_section_assignments"), + url(r"^section/(?P[\w\-]+)/status/$", "review_status", name="review_status"), + url(r"^section/(?P[\w\-]+)/status/(?P\w+)/$", "review_status", name="review_status"), + url(r"^section/(?P[\w\-]+)/list/(?P\d+)/$", "review_list", name="review_list_user"), + url(r"^section/(?P[\w\-]+)/admin/$", "review_admin", name="review_admin"), + url(r"^section/(?P[\w\-]+)/admin/accept/$", "review_bulk_accept", name="review_bulk_accept"), + url(r"^section/(?P[\w\-]+)/notification/(?P\w+)/$", "result_notification", name="result_notification"), + url(r"^section/(?P[\w\-]+)/notification/(?P\w+)/prepare/$", "result_notification_prepare", name="result_notification_prepare"), + url(r"^section/(?P[\w\-]+)/notification/(?P\w+)/send/$", "result_notification_send", name="result_notification_send"), url(r"^review/(?P\d+)/$", "review_detail", name="review_detail"), diff --git a/symposion/reviews/views.py b/symposion/reviews/views.py index 28be7101..dd5961bf 100644 --- a/symposion/reviews/views.py +++ b/symposion/reviews/views.py @@ -69,7 +69,7 @@ def review_section(request, section_slug, assigned=False, reviewed="all"): return access_not_permitted(request) section = get_object_or_404(ProposalSection, section__slug=section_slug) - queryset = ProposalBase.objects.filter(kind__section=section) + queryset = ProposalBase.objects.filter(kind__section=section.section) if assigned: assignments = ReviewAssignment.objects.filter(user=request.user)\ @@ -343,8 +343,7 @@ def review_status(request, section_slug=None, key=None): for status in proposals: if key and key != status: continue - proposals[status] = list(proposals_generator(request, proposals[status], - check_speaker=not admin)) + proposals[status] = list(proposals_generator(request, proposals[status], check_speaker=not admin)) if key: ctx.update({ @@ -409,9 +408,7 @@ def result_notification(request, section_slug, status): if not request.user.has_perm("reviews.can_manage_%s" % section_slug): return access_not_permitted(request) - proposals = ProposalBase.objects.filter(kind__section__slug=section_slug, - result__status=status)\ - .select_related("speaker__user", "result").select_subclasses() + proposals = ProposalBase.objects.filter(kind__section__slug=section_slug, result__status=status).select_related("speaker__user", "result").select_subclasses() notification_templates = NotificationTemplate.objects.all() ctx = { diff --git a/symposion/schedule/forms.py b/symposion/schedule/forms.py index f9b863ac..6a01cbfe 100644 --- a/symposion/schedule/forms.py +++ b/symposion/schedule/forms.py @@ -1,15 +1,17 @@ import csv import time + from datetime import datetime from django import forms from django.contrib import messages -from django.db import IntegrityError +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) +from symposion.schedule.models import (Day, Presentation, Room, SlotKind, Slot, + SlotRoom) class SlotEditForm(forms.Form): @@ -145,10 +147,8 @@ class ScheduleSectionForm(forms.Form): ) created_items.append(slot) try: - # @@@ TODO - upgrade Django, use atomic transactions - # with transaction.atomic(): - # SlotRoom.objects.create(slot=slot, room=room) - SlotRoom.objects.create(slot=slot, room=room) + with transaction.atomic(): + SlotRoom.objects.create(slot=slot, room=room) except IntegrityError: # delete all created objects and report error for x in created_items: diff --git a/symposion/schedule/migrations/0001_initial.py b/symposion/schedule/migrations/0001_initial.py new file mode 100644 index 00000000..3798087d --- /dev/null +++ b/symposion/schedule/migrations/0001_initial.py @@ -0,0 +1,284 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Schedule' + db.create_table('schedule_schedule', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('section', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['conference.Section'], unique=True)), + ('published', self.gf('django.db.models.fields.BooleanField')(default=True)), + ('hidden', self.gf('django.db.models.fields.BooleanField')(default=False)), + )) + db.send_create_signal('schedule', ['Schedule']) + + # Adding model 'Day' + db.create_table('schedule_day', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('schedule', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['schedule.Schedule'])), + ('date', self.gf('django.db.models.fields.DateField')()), + )) + db.send_create_signal('schedule', ['Day']) + + # Adding unique constraint on 'Day', fields ['schedule', 'date'] + db.create_unique('schedule_day', ['schedule_id', 'date']) + + # Adding model 'Room' + db.create_table('schedule_room', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('schedule', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['schedule.Schedule'])), + ('name', self.gf('django.db.models.fields.CharField')(max_length=65)), + ('order', self.gf('django.db.models.fields.PositiveIntegerField')()), + )) + db.send_create_signal('schedule', ['Room']) + + # Adding model 'SlotKind' + db.create_table('schedule_slotkind', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('schedule', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['schedule.Schedule'])), + ('label', self.gf('django.db.models.fields.CharField')(max_length=50)), + )) + db.send_create_signal('schedule', ['SlotKind']) + + # Adding model 'Slot' + db.create_table('schedule_slot', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('day', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['schedule.Day'])), + ('kind', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['schedule.SlotKind'])), + ('start', self.gf('django.db.models.fields.TimeField')()), + ('end', self.gf('django.db.models.fields.TimeField')()), + ('content_override', self.gf('markitup.fields.MarkupField')(no_rendered_field=True, blank=True)), + ('_content_override_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('schedule', ['Slot']) + + # Adding model 'SlotRoom' + db.create_table('schedule_slotroom', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('slot', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['schedule.Slot'])), + ('room', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['schedule.Room'])), + )) + db.send_create_signal('schedule', ['SlotRoom']) + + # Adding unique constraint on 'SlotRoom', fields ['slot', 'room'] + db.create_unique('schedule_slotroom', ['slot_id', 'room_id']) + + # Adding model 'Presentation' + db.create_table('schedule_presentation', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('slot', self.gf('django.db.models.fields.related.OneToOneField')(blank=True, related_name='content_ptr', unique=True, null=True, to=orm['schedule.Slot'])), + ('title', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('description', self.gf('markitup.fields.MarkupField')(no_rendered_field=True)), + ('abstract', self.gf('markitup.fields.MarkupField')(no_rendered_field=True)), + ('speaker', self.gf('django.db.models.fields.related.ForeignKey')(related_name='presentations', to=orm['speakers.Speaker'])), + ('cancelled', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('proposal_base', self.gf('django.db.models.fields.related.OneToOneField')(related_name='presentation', unique=True, to=orm['proposals.ProposalBase'])), + ('section', self.gf('django.db.models.fields.related.ForeignKey')(related_name='presentations', to=orm['conference.Section'])), + ('_description_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + ('_abstract_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('schedule', ['Presentation']) + + # Adding M2M table for field additional_speakers on 'Presentation' + m2m_table_name = db.shorten_name('schedule_presentation_additional_speakers') + db.create_table(m2m_table_name, ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('presentation', models.ForeignKey(orm['schedule.presentation'], null=False)), + ('speaker', models.ForeignKey(orm['speakers.speaker'], null=False)) + )) + db.create_unique(m2m_table_name, ['presentation_id', 'speaker_id']) + + + def backwards(self, orm): + # Removing unique constraint on 'SlotRoom', fields ['slot', 'room'] + db.delete_unique('schedule_slotroom', ['slot_id', 'room_id']) + + # Removing unique constraint on 'Day', fields ['schedule', 'date'] + db.delete_unique('schedule_day', ['schedule_id', 'date']) + + # Deleting model 'Schedule' + db.delete_table('schedule_schedule') + + # Deleting model 'Day' + db.delete_table('schedule_day') + + # Deleting model 'Room' + db.delete_table('schedule_room') + + # Deleting model 'SlotKind' + db.delete_table('schedule_slotkind') + + # Deleting model 'Slot' + db.delete_table('schedule_slot') + + # Deleting model 'SlotRoom' + db.delete_table('schedule_slotroom') + + # Deleting model 'Presentation' + db.delete_table('schedule_presentation') + + # Removing M2M table for field additional_speakers on 'Presentation' + db.delete_table(db.shorten_name('schedule_presentation_additional_speakers')) + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'conference.conference': { + 'Meta': {'object_name': 'Conference'}, + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'timezone': ('timezones.fields.TimeZoneField', [], {'default': "'US/Eastern'", 'max_length': '100', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'conference.section': { + 'Meta': {'ordering': "['start_date']", 'object_name': 'Section'}, + 'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Conference']"}), + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'proposals.additionalspeaker': { + 'Meta': {'unique_together': "(('speaker', 'proposalbase'),)", 'object_name': 'AdditionalSpeaker', 'db_table': "'proposals_proposalbase_additional_speakers'"}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposalbase': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['proposals.ProposalBase']"}), + 'speaker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['speakers.Speaker']"}), + 'status': ('django.db.models.fields.IntegerField', [], {'default': '1'}) + }, + 'proposals.proposalbase': { + 'Meta': {'object_name': 'ProposalBase'}, + '_abstract_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + '_additional_notes_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'abstract': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}), + 'additional_notes': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'additional_speakers': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['speakers.Speaker']", 'symmetrical': 'False', 'through': "orm['proposals.AdditionalSpeaker']", 'blank': 'True'}), + 'cancelled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'description': ('django.db.models.fields.TextField', [], {'max_length': '400'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'kind': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['proposals.ProposalKind']"}), + 'speaker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'proposals'", 'to': "orm['speakers.Speaker']"}), + 'submitted': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'proposals.proposalkind': { + 'Meta': {'object_name': 'ProposalKind'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'proposal_kinds'", 'to': "orm['conference.Section']"}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}) + }, + 'schedule.day': { + 'Meta': {'ordering': "['date']", 'unique_together': "[('schedule', 'date')]", 'object_name': 'Day'}, + 'date': ('django.db.models.fields.DateField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'schedule': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Schedule']"}) + }, + 'schedule.presentation': { + 'Meta': {'ordering': "['slot']", 'object_name': 'Presentation'}, + '_abstract_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + '_description_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'abstract': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}), + 'additional_speakers': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'copresentations'", 'blank': 'True', 'to': "orm['speakers.Speaker']"}), + 'cancelled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'description': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'proposal_base': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'presentation'", 'unique': 'True', 'to': "orm['proposals.ProposalBase']"}), + 'section': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'presentations'", 'to': "orm['conference.Section']"}), + 'slot': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'content_ptr'", 'unique': 'True', 'null': 'True', 'to': "orm['schedule.Slot']"}), + 'speaker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'presentations'", 'to': "orm['speakers.Speaker']"}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'schedule.room': { + 'Meta': {'object_name': 'Room'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '65'}), + 'order': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'schedule': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Schedule']"}) + }, + 'schedule.schedule': { + 'Meta': {'ordering': "['section']", 'object_name': 'Schedule'}, + 'hidden': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'published': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'section': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['conference.Section']", 'unique': 'True'}) + }, + 'schedule.slot': { + 'Meta': {'ordering': "['day', 'start', 'end']", 'object_name': 'Slot'}, + '_content_override_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'content_override': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'day': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Day']"}), + 'end': ('django.db.models.fields.TimeField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'kind': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.SlotKind']"}), + 'start': ('django.db.models.fields.TimeField', [], {}) + }, + 'schedule.slotkind': { + 'Meta': {'object_name': 'SlotKind'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'schedule': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Schedule']"}) + }, + 'schedule.slotroom': { + 'Meta': {'ordering': "['slot', 'room__order']", 'unique_together': "[('slot', 'room')]", 'object_name': 'SlotRoom'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'room': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Room']"}), + 'slot': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['schedule.Slot']"}) + }, + 'speakers.speaker': { + 'Meta': {'ordering': "['name']", 'object_name': 'Speaker'}, + '_biography_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'annotation': ('django.db.models.fields.TextField', [], {}), + 'biography': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invite_email': ('django.db.models.fields.CharField', [], {'max_length': '200', 'unique': 'True', 'null': 'True', 'db_index': 'True'}), + 'invite_token': ('django.db.models.fields.CharField', [], {'max_length': '40', 'db_index': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'photo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'speaker_profile'", 'unique': 'True', 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['schedule'] \ No newline at end of file diff --git a/symposion/schedule/migrations/__init__.py b/symposion/schedule/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/schedule/models.py b/symposion/schedule/models.py index 5954e07e..38ff6f09 100644 --- a/symposion/schedule/models.py +++ b/symposion/schedule/models.py @@ -79,10 +79,10 @@ class Slot(models.Model): """ Unassign the associated content with this slot. """ - if self.content and self.content.slot_id: - presentation = self.content - presentation.slot = None - presentation.save() + content = self.content + if content and content.slot_id: + content.slot = None + content.save() @property def content(self): diff --git a/symposion/schedule/views.py b/symposion/schedule/views.py index 03fd17e8..b82505d1 100644 --- a/symposion/schedule/views.py +++ b/symposion/schedule/views.py @@ -6,9 +6,10 @@ 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 import messages from django.contrib.sites.models import Site -from symposion.schedule.forms import SlotEditForm +from symposion.schedule.forms import SlotEditForm, ScheduleSectionForm from symposion.schedule.models import Schedule, Day, Slot, Presentation from symposion.schedule.timetable import TimeTable @@ -81,8 +82,8 @@ def schedule_list_csv(request, slug=None): presentations = Presentation.objects.filter(section=schedule.section) presentations = presentations.exclude(cancelled=True).order_by("id") + response = HttpResponse(content_type="text/csv") - response = HttpResponse(mimetype="text/csv") if slug: file_slug = slug else: @@ -104,11 +105,24 @@ def schedule_edit(request, slug=None): schedule = fetch_schedule(slug) + if request.method == "POST": + form = ScheduleSectionForm( + request.POST, request.FILES, schedule=schedule + ) + if form.is_valid(): + if 'submit' in form.data: + msg = form.build_schedule() + elif 'delete' in form.data: + msg = form.delete_schedule() + messages.add_message(request, msg[0], msg[1]) + else: + form = ScheduleSectionForm(schedule=schedule) days_qs = Day.objects.filter(schedule=schedule) days = [TimeTable(day) for day in days_qs] ctx = { "schedule": schedule, "days": days, + "form": form } return render(request, "schedule/schedule_edit.html", ctx) diff --git a/symposion/speakers/fixture_gen.py b/symposion/speakers/fixture_gen.py deleted file mode 100644 index fdecb6b7..00000000 --- a/symposion/speakers/fixture_gen.py +++ /dev/null @@ -1,29 +0,0 @@ -from django.contrib.auth.models import User - -from fixture_generator import fixture_generator - -from symposion.speakers.models import Speaker - - -@fixture_generator(Speaker, User) -def speakers(): - guido = User.objects.create_user("guido", "guido@python.org", "pythonisawesome") - matz = User.objects.create_user("matz", "matz@ruby.org", "pythonsucks") - larry = User.objects.create_user("larryw", "larry@perl.org", "linenoisehere") - - Speaker.objects.create( - user=guido, - name="Guido van Rossum", - biography="I wrote Python, and named it after Monty Python", - ) - Speaker.objects.create( - user=matz, - name="Yukihiro Matsumoto", - biography=("I wrote Ruby, and named it after the rare gem Ruby, a pun " - "on Perl/pearl."), - ) - Speaker.objects.create( - user=larry, - name="Larry Wall", - biography="I wrote Perl, and named it after the Parable of the Pearl", - ) diff --git a/symposion/speakers/migrations/0001_initial.py b/symposion/speakers/migrations/0001_initial.py new file mode 100644 index 00000000..1db93f8c --- /dev/null +++ b/symposion/speakers/migrations/0001_initial.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Speaker' + db.create_table('speakers_speaker', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('user', self.gf('django.db.models.fields.related.OneToOneField')(related_name='speaker_profile', unique=True, null=True, to=orm['auth.User'])), + ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('biography', self.gf('markitup.fields.MarkupField')(no_rendered_field=True, blank=True)), + ('photo', self.gf('django.db.models.fields.files.ImageField')(max_length=100, blank=True)), + ('annotation', self.gf('django.db.models.fields.TextField')()), + ('invite_email', self.gf('django.db.models.fields.CharField')(max_length=200, unique=True, null=True, db_index=True)), + ('invite_token', self.gf('django.db.models.fields.CharField')(max_length=40, db_index=True)), + ('created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('_biography_rendered', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('speakers', ['Speaker']) + + + def backwards(self, orm): + # Deleting model 'Speaker' + db.delete_table('speakers_speaker') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'speakers.speaker': { + 'Meta': {'ordering': "['name']", 'object_name': 'Speaker'}, + '_biography_rendered': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'annotation': ('django.db.models.fields.TextField', [], {}), + 'biography': ('markitup.fields.MarkupField', [], {'no_rendered_field': 'True', 'blank': 'True'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'invite_email': ('django.db.models.fields.CharField', [], {'max_length': '200', 'unique': 'True', 'null': 'True', 'db_index': 'True'}), + 'invite_token': ('django.db.models.fields.CharField', [], {'max_length': '40', 'db_index': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'photo': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'speaker_profile'", 'unique': 'True', 'null': 'True', 'to': "orm['auth.User']"}) + } + } + + complete_apps = ['speakers'] \ No newline at end of file diff --git a/symposion/speakers/migrations/__init__.py b/symposion/speakers/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/sponsorship/migrations/0001_initial.py b/symposion/sponsorship/migrations/0001_initial.py new file mode 100644 index 00000000..356b8a8d --- /dev/null +++ b/symposion/sponsorship/migrations/0001_initial.py @@ -0,0 +1,188 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + depends_on = ( + ("conference", "0001_initial"), + ) + + def forwards(self, orm): + # Adding model 'SponsorLevel' + db.create_table('sponsorship_sponsorlevel', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('conference', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['conference.Conference'])), + ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('order', self.gf('django.db.models.fields.IntegerField')(default=0)), + ('cost', self.gf('django.db.models.fields.PositiveIntegerField')()), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('sponsorship', ['SponsorLevel']) + + # Adding model 'Sponsor' + db.create_table('sponsorship_sponsor', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('applicant', self.gf('django.db.models.fields.related.ForeignKey')(related_name='sponsorships', null=True, to=orm['auth.User'])), + ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('external_url', self.gf('django.db.models.fields.URLField')(max_length=200)), + ('annotation', self.gf('django.db.models.fields.TextField')(blank=True)), + ('contact_name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('contact_email', self.gf('django.db.models.fields.EmailField')(max_length=75)), + ('level', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['sponsorship.SponsorLevel'])), + ('added', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + ('active', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('sponsor_logo', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='+', null=True, to=orm['sponsorship.SponsorBenefit'])), + )) + db.send_create_signal('sponsorship', ['Sponsor']) + + # Adding model 'Benefit' + db.create_table('sponsorship_benefit', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + ('type', self.gf('django.db.models.fields.CharField')(default='simple', max_length=10)), + )) + db.send_create_signal('sponsorship', ['Benefit']) + + # Adding model 'BenefitLevel' + db.create_table('sponsorship_benefitlevel', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('benefit', self.gf('django.db.models.fields.related.ForeignKey')(related_name='benefit_levels', to=orm['sponsorship.Benefit'])), + ('level', self.gf('django.db.models.fields.related.ForeignKey')(related_name='benefit_levels', to=orm['sponsorship.SponsorLevel'])), + ('max_words', self.gf('django.db.models.fields.PositiveIntegerField')(null=True, blank=True)), + ('other_limits', self.gf('django.db.models.fields.CharField')(max_length=200, blank=True)), + )) + db.send_create_signal('sponsorship', ['BenefitLevel']) + + # Adding model 'SponsorBenefit' + db.create_table('sponsorship_sponsorbenefit', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('sponsor', self.gf('django.db.models.fields.related.ForeignKey')(related_name='sponsor_benefits', to=orm['sponsorship.Sponsor'])), + ('benefit', self.gf('django.db.models.fields.related.ForeignKey')(related_name='sponsor_benefits', to=orm['sponsorship.Benefit'])), + ('active', self.gf('django.db.models.fields.BooleanField')(default=True)), + ('max_words', self.gf('django.db.models.fields.PositiveIntegerField')(null=True, blank=True)), + ('other_limits', self.gf('django.db.models.fields.CharField')(max_length=200, blank=True)), + ('text', self.gf('django.db.models.fields.TextField')(blank=True)), + ('upload', self.gf('django.db.models.fields.files.FileField')(max_length=100, blank=True)), + )) + db.send_create_signal('sponsorship', ['SponsorBenefit']) + + + def backwards(self, orm): + # Deleting model 'SponsorLevel' + db.delete_table('sponsorship_sponsorlevel') + + # Deleting model 'Sponsor' + db.delete_table('sponsorship_sponsor') + + # Deleting model 'Benefit' + db.delete_table('sponsorship_benefit') + + # Deleting model 'BenefitLevel' + db.delete_table('sponsorship_benefitlevel') + + # Deleting model 'SponsorBenefit' + db.delete_table('sponsorship_sponsorbenefit') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'conference.conference': { + 'Meta': {'object_name': 'Conference'}, + 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), + 'timezone': ('timezones.fields.TimeZoneField', [], {'default': "'US/Eastern'", 'max_length': '100', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'sponsorship.benefit': { + 'Meta': {'object_name': 'Benefit'}, + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'type': ('django.db.models.fields.CharField', [], {'default': "'simple'", 'max_length': '10'}) + }, + 'sponsorship.benefitlevel': { + 'Meta': {'ordering': "['level']", 'object_name': 'BenefitLevel'}, + 'benefit': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'benefit_levels'", 'to': "orm['sponsorship.Benefit']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'benefit_levels'", 'to': "orm['sponsorship.SponsorLevel']"}), + 'max_words': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'other_limits': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}) + }, + 'sponsorship.sponsor': { + 'Meta': {'object_name': 'Sponsor'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'added': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'annotation': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'applicant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sponsorships'", 'null': 'True', 'to': "orm['auth.User']"}), + 'contact_email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}), + 'contact_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sponsorship.SponsorLevel']"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'sponsor_logo': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['sponsorship.SponsorBenefit']"}) + }, + 'sponsorship.sponsorbenefit': { + 'Meta': {'ordering': "['-active']", 'object_name': 'SponsorBenefit'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'benefit': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sponsor_benefits'", 'to': "orm['sponsorship.Benefit']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'max_words': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}), + 'other_limits': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), + 'sponsor': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sponsor_benefits'", 'to': "orm['sponsorship.Sponsor']"}), + 'text': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'upload': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'blank': 'True'}) + }, + 'sponsorship.sponsorlevel': { + 'Meta': {'ordering': "['conference', 'order']", 'object_name': 'SponsorLevel'}, + 'conference': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['conference.Conference']"}), + 'cost': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}) + } + } + + complete_apps = ['sponsorship'] diff --git a/symposion/sponsorship/migrations/__init__.py b/symposion/sponsorship/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/teams/migrations/0001_initial.py b/symposion/teams/migrations/0001_initial.py new file mode 100644 index 00000000..d1ab1600 --- /dev/null +++ b/symposion/teams/migrations/0001_initial.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Team' + db.create_table('teams_team', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=50)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), + ('description', self.gf('django.db.models.fields.TextField')(blank=True)), + ('access', self.gf('django.db.models.fields.CharField')(max_length=20)), + ('created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)), + )) + db.send_create_signal('teams', ['Team']) + + # Adding M2M table for field permissions on 'Team' + m2m_table_name = db.shorten_name('teams_team_permissions') + db.create_table(m2m_table_name, ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('team', models.ForeignKey(orm['teams.team'], null=False)), + ('permission', models.ForeignKey(orm['auth.permission'], null=False)) + )) + db.create_unique(m2m_table_name, ['team_id', 'permission_id']) + + # Adding M2M table for field manager_permissions on 'Team' + m2m_table_name = db.shorten_name('teams_team_manager_permissions') + db.create_table(m2m_table_name, ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('team', models.ForeignKey(orm['teams.team'], null=False)), + ('permission', models.ForeignKey(orm['auth.permission'], null=False)) + )) + db.create_unique(m2m_table_name, ['team_id', 'permission_id']) + + # Adding model 'Membership' + db.create_table('teams_membership', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='memberships', to=orm['auth.User'])), + ('team', self.gf('django.db.models.fields.related.ForeignKey')(related_name='memberships', to=orm['teams.Team'])), + ('state', self.gf('django.db.models.fields.CharField')(max_length=20)), + ('message', self.gf('django.db.models.fields.TextField')(blank=True)), + )) + db.send_create_signal('teams', ['Membership']) + + + def backwards(self, orm): + # Deleting model 'Team' + db.delete_table('teams_team') + + # Removing M2M table for field permissions on 'Team' + db.delete_table(db.shorten_name('teams_team_permissions')) + + # Removing M2M table for field manager_permissions on 'Team' + db.delete_table(db.shorten_name('teams_team_manager_permissions')) + + # Deleting model 'Membership' + db.delete_table('teams_membership') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'teams.membership': { + 'Meta': {'object_name': 'Membership'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'message': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'state': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'team': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'memberships'", 'to': "orm['teams.Team']"}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'memberships'", 'to': "orm['auth.User']"}) + }, + 'teams.team': { + 'Meta': {'object_name': 'Team'}, + 'access': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'created': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'manager_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'manager_teams'", 'blank': 'True', 'to': "orm['auth.Permission']"}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'member_teams'", 'blank': 'True', 'to': "orm['auth.Permission']"}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}) + } + } + + complete_apps = ['teams'] \ No newline at end of file diff --git a/symposion/teams/migrations/__init__.py b/symposion/teams/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/symposion/templates/cms/page_detail.html b/symposion/templates/cms/page_detail.html index 770eae29..6f35395b 100644 --- a/symposion/templates/cms/page_detail.html +++ b/symposion/templates/cms/page_detail.html @@ -1,5 +1,8 @@ {% extends "site_base.html" %} +{% load url from future %} + + {% load sitetree %} {% load i18n %} @@ -12,7 +15,7 @@ {% block body %} {% if editable %} {% endif %}

{{ page.title }}

diff --git a/symposion/templates/emails/speaker_no_profile/message.html b/symposion/templates/emails/speaker_no_profile/message.html index 14007092..d77693c1 100644 --- a/symposion/templates/emails/speaker_no_profile/message.html +++ b/symposion/templates/emails/speaker_no_profile/message.html @@ -1,8 +1,9 @@ +{% load url from future %}

{{ proposal.speaker.name }} attached you as an additional speaker to a talk proposal for {{ current_site.name }} entitled "{{ proposal.title }}".

Go to

-

http://{{ current_site }}{% url speaker_create_token token %}

+

http://{{ current_site }}{% url 'speaker_create_token' token %}

to confirm and fill out your speaker profile.

diff --git a/symposion/templates/schedule/schedule_edit.html b/symposion/templates/schedule/schedule_edit.html index b5335506..9b1ab864 100644 --- a/symposion/templates/schedule/schedule_edit.html +++ b/symposion/templates/schedule/schedule_edit.html @@ -18,7 +18,7 @@

Schedule Edit

- + {% for timetable in days %}

{{ timetable.day.date }}

{% include "schedule/_edit_grid.html" %} @@ -45,5 +45,19 @@ e.preventDefault(); }); }); + $(function() { + //submit event handler + $("form#schedule-builder :submit").click(function(e) { + var name = this.name; + if(name == 'delete') { + if (!confirm("Are you sure you want to delete the schedule?")) + { + e.preventDefault(); + return; + } + } + }); + }); + {% endblock %}